python爬虫之遍历单个域名
作者:laozhang 发布时间:2021-06-28 07:45:34
即使你没听说过“ * 六度分隔理论”,也很可能听过“凯文 • 贝肯 (Kevin Bacon)的六度分隔值游戏”。在这两个游戏中,目标都是把两 个不相干的主题(在前一种情况中是相互链接的 * 词条,而在后 一种情况中是出现在同一部电影中的演员)用一个链条(至多包含 6 个 主题,包括原来的两个主题)连接起来。
比如,埃里克 • 艾德尔和布兰登 • 弗雷泽都出现在电影《骑警杜德雷》 里,布兰登 • 弗雷泽又和凯文 • 贝肯都出现在电影《我呼吸的空气》 里。因此,根据这两个条件,从埃里克 • 艾德尔到凯文 • 贝肯的链条 长度只有 3 个主题。
感谢 The Oracle of Bacon 的存在,满足了我对这类关系链的好奇心。
我们将在本节创建一个项目来实现“ * 六度分隔理论”的查找方 法。也就是说,我们要实现从埃里克 • 艾德尔的词条页面 (https://en.wikipedia.org/wiki/Eric_Idle)开始,经过最少的链接点击次 数找到凯文 • 贝肯的词条页面(https://en.wikipedia.org/wiki/Kevin_Bacon)。
这么做对 * 的服务器负载有多大影响?
根据维基媒体基金会( * 所属的组织)的统计,该网站每秒 会收到大约2500次点击,其中超过 99% 的点击都指向 * 域 名[详情请见“维基媒体统计图”(Wikimedia in Figures)里的“流量 数据”(Traffic Volume)部分内容]。因为网站流量很大,所以你 的网络爬虫不可能对 * 的服务器负载产生显著影响。不过, 如果你频繁地运行本书的代码示例,或者自己创建项目来抓取维基 百科的词条,那么希望你能够向维基媒体基金会提供一点捐赠—— 不只是为了抵消你占用的服务器资源,也是为了其他人能够利用维 基百科这个教育资源。
还需要注意的是,如果你准备利用 * 的数据做一个大型项 目,应该确认该数据是不能够通过 * API 获取的。 * 网站经常被用于演示爬虫,因为它的 HTML 结构简单并且相对稳定。但是它的 API 往往会使得数据获取更加高效。 你应该已经知道如何写一段 Python 代码,来获取 * 网站的任何 页面并提取该页面中的链接了。
from urllib.request import urlopen from bs4 import BeautifulSoup
html = urlopen('http://en.wikipedia.org/wiki/Kevin_Bacon')
bs = BeautifulSoup(html, 'html.parser')
for link in bs.find_all('a'):
if 'href' in link.attrs:
print(link.attrs['href'])
如果你观察生成的一列链接,会看到你想要的所有词条链接都在里 面:“Apollo 13”“Philadelphia”“Primetime Emmy Award”,等等。但是, 也有一些你不需要的链接:
//wikimediafoundation.org/wiki/Privacy_policy
//en.wikipedia.org/wiki/Wikipedia:Contact_us
其实, * 的每个页面都充满了侧边栏、页眉和页脚链接,以及连 接到分类页面、对话页面和其他不包含词条的页面的链接:
/wiki/Category:Articles_with_unsourced_statements_from_April_2014
/wiki/Talk:Kevin_Bacon
最近我有个朋友在做一个类似的 * 抓取项目,他说,为了判断一 个 * 内链是否链接到一个词条页面,他写了一个很大的过滤函 数,代码超过了 100 行。不幸的是,他没有提前花很多时间去寻找“词 条链接”和“其他链接”之间的模式,也可能他后来发现了。如果你仔细 观察那些指向词条页面(不是指向其他内部页面)的链接,会发现它们 都有 3 个共同点:
它们都在 id 是 bodyContent 的 div 标签里
URL 不包含冒号
URL 都以 /wiki/ 开头
我们可以利用这些规则稍微调整一下代码来仅获取词条链接,使用的正则表达式为 ^(/wiki/)((?!:).)*$"):
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
html = urlopen('http://en.wikipedia.org/wiki/Kevin_Bacon')
bs = BeautifulSoup(html, 'html.parser')
for link in bs.find('div', {'id':'bodyContent'}).find_all(
'a', href=re.compile('^(/wiki/)((?!:).)*$')):
if 'href' in link.attrs:
print(link.attrs['href'])
如果你运行以上代码,就会看到 * 上凯文 • 贝肯词条里所有指向 其他词条的链接。
当然,写程序来找出这个静态的 * 词条里所有的词条链接很有 趣,不过没什么实际用处。你需要让这段程序更像下面的形式。
一个函数 getLinks,可以用一个 /wiki/< 词条名称 > 形式的维 基百科词条 URL 作为参数,然后以同样的形式返回一个列表,里 面包含所有的词条 URL。
一个主函数,以某个起始词条为参数调用 getLinks,然后从返回 的 URL 列表里随机选择一个词条链接,再次调用 getLinks,直到 你主动停止程序,或者在新的页面上没有词条链接了。
完整的代码如下所示:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import datetime
import random
import re
random.seed(datetime.datetime.now())
def getLinks(articleUrl): html = urlopen('http://en.wikipedia.org{}'.format(articleUrl))
bs = BeautifulSoup(html, 'html.parser')
return bs.find('div', {'id':'bodyContent'}).find_all('a',
href=re.compile('^(/wiki/)((?!:).)*$'))
links = getLinks('/wiki/Kevin_Bacon')
while len(links) > 0:
newArticle = links[random.randint(0, len(links)-1)].attrs['href']
print(newArticle)
links = getLinks(newArticle)
导入需要的 Python 库之后,程序首先做的是用系统当前时间设置随机 数生成器的种子。这样可以保证每次程序运行的时候, * 词条的 选择都是一个全新的随机路径。
伪随机数和随机数种子
在前面的示例中,为了能够连续地随机遍历 * ,我用 Python 的随机数生成器在每个页面上随机选择一个词条链接。但是,用随 机数的时候需要格外小心。
虽然计算机很擅长做精确计算,但是它们处理随机事件时非常不靠 谱。因此,随机数是一个难题。大多数随机数算法都努力生成一个 呈均匀分布且难以预测的数字序列,但是在算法初始化阶段都需要 提供一个随机数“种子”(random seed)。而完全相同的种子每次将 生成同样的“随机”数序列,因此我将系统时间作为生成新随机数序 列(和新随机词条序列)的起点。这样做会让程序运行的时候更具 有随机性。
其实,Python 的伪随机数生成器用的是梅森旋转(Mersenne Twister)算法,它生成的随机数很难预测且呈均匀分布,就是有点 儿耗费 CPU 资源。真正好的随机数可不便宜! 然后,程序定义 getLinks 函数,它接收一个 /wiki/< 词条名称 > 形 式的 * 词条 URL 作为参数,在前面加上 * 的域名 http://en.wikipedia.org,再用该域名的 HTML 获得一个 BeautifulSoup 对象。之后,基于前面介绍过的参数,抽取一列词条 链接所在的标签 a 并返回它们。 程序的主函数首先把起始页面 https://en.wikipedia.org/wiki/Kevin_Bacon 里的词条链接列表设置成链接标签列表(links 变量)。然后用一个循 环,从页面中随机找一个词条链接标签并抽取 href 属性,打印这个页 面,再把这个链接传入 getLinks 函数,重新获取新的链接列表。
当然,这里只是简单地构建一个从一个页面到另一个页面的爬虫,要解 决“ * 六度分隔理论”问题还需要再做一点儿工作。我们还应该存储 URL 链接数据并分析数据。
猜你喜欢
- 前言人脸识别在LWF(Labeled Faces in the Wild)数据集上人脸识别率现在已经99.7%以上,这个识别率确实非常高了,
- 在一群里有朋友发问,有时间,也就看看了,不多说了,看图了:用一般的 select .... order 排序出来,就如下图了,是
- 标记路径演示效果:实例代码import matplotlib.pyplot as pltimport matplotlib.path as
- 一、前言首先说,Python中一切皆对象,老生常谈。还有,Python提供了许多特殊方法、元类等等这样的“元编程”机制。像给对象动态添加属性
- 1、Dreamweaver中的复制我在网页中复制的文字,粘贴到Dreamweaver中时,它总是带有原来网页的格式,请问如何只复制其中的文本
- 1.文件的读取操作文件的第一步就是得打开要操作的文件,然后进行读取文件,最后关闭文件。在python中我们可以使用open函数来打开一个文件
- 游戏说明:一个考验您记忆力的游戏,只要两个方块的;图案能够凑成一对,最终翻开所有的图片,那么您就获胜,计算机将自动记录您的游戏时
- python time.sleep()-睡眠线程还是进程?它会阻止线程。如果查看Python源代码中的Modules / timemodul
- 本文主要给大家介绍了关于python实现循环购物车功能的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:示例代码# -*- co
- 关于什么是并发模型,我在这里引用 Go 语言联合创造者 Rob Pike 的一段话:并发是指一次处理多件事。并行是指一次做多件事。二者不同,
- drop方法有一个可选参数inplace,表明可对原数组作出修改并返回一个新数组。不管参数默认为False还是设置为True,原数组的内存值
- 在微软的ASP编程体系中,ADO对象的建立,使得从网页访问数据库成为一件易事,特别是ADO的Recordset对象使得控制数据的输出显示更为
- Yahoo!的Exceptional Performance团队为改善Web性能带来最佳实践。他们为此进行了一系列的实验、开发了
- 代码如下:--相信大家肯定经常会把数据导入到数据库中,但是可能会有些记录行的所有列的数据是null,这为null的数据是我们不需要 --现在
- 1:使用SHOW语句找出在服务器上当前存在什么数据库:mysql> SHOW DATABASES;2:2、创建一个数据库MYSQLDA
- 1.什么是内存逃逸在一段程序中,每一个函数都会有自己的内存区域分配自己的局部变量,返回值,这些内存会由编译器在栈中进行分配,每一个函数会分配
- 在前面的文章中很早有写到关于添加水印的方法,但是过程还是较为复杂,最近发现的这款filestools非标准库其实真正实现添加水印的只要一个函
- 本文实例为大家分享了python实现简易学生信息管理系统的具体代码,供大家参考,具体内容如下一、系统功能1.录入学生信息2.查找学生信息3.
- 下面我讲讲关于这套系统的加载流程 定义根目录,定义include目录 加载核心文件 配置文件'config.inc.php'
- 主要是运用java.util.regex类。 import java.util.regex.Matcher;import java