python爬虫之遍历单个域名


Posted in Python onNovember 20, 2019

即使你没听说过“维基百科六度分隔理论”,也很可能听过“凯文 • 贝肯 (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 链接数据并分析数据。

以上就是关于python爬虫之遍历单个域名的全部知识点,感谢大家的学习和对三水点靠木的支持。

Python 相关文章推荐
深入Python解释器理解Python中的字节码
Apr 01 Python
Python多线程编程(五):死锁的形成
Apr 05 Python
Python实现短网址ShortUrl的Hash运算实例讲解
Aug 10 Python
使用Python从有道词典网页获取单词翻译
Jul 03 Python
使用Python的Scrapy框架十分钟爬取美女图
Dec 26 Python
Python利用ElementTree模块处理XML的方法详解
Aug 31 Python
python编写朴素贝叶斯用于文本分类
Dec 21 Python
说说如何遍历Python列表的方法示例
Feb 11 Python
python3对接mysql数据库实例详解
Apr 30 Python
利用PyQt中的QThread类实现多线程
Feb 18 Python
django修改models重建数据库的操作
Mar 31 Python
Python自动重新加载模块详解(autoreload module)
Apr 01 Python
python matplotlib 画dataframe的时间序列图实例
Nov 20 #Python
python中Lambda表达式详解
Nov 20 #Python
TensorFlow索引与切片的实现方法
Nov 20 #Python
50行Python代码实现视频中物体颜色识别和跟踪(必须以红色为例)
Nov 20 #Python
python中必要的名词解释
Nov 20 #Python
python做接口测试的必要性
Nov 20 #Python
使用NumPy读取MNIST数据的实现代码示例
Nov 20 #Python
You might like
php INI配置文件的解析实现分析
2011/01/04 PHP
rephactor 优秀的PHP的重构工具
2011/06/09 PHP
php的webservice的wsdl的XML无法显示问题的解决方法
2014/03/11 PHP
利用php下载xls文件(自己动手写的)
2014/04/18 PHP
PHP的mysqli_query参数MYSQLI_STORE_RESULT和MYSQLI_USE_RESULT的区别
2014/09/29 PHP
PHP函数实现分页含文本分页和数字分页
2014/10/23 PHP
如何通过Linux命令行使用和运行PHP脚本
2015/07/29 PHP
简单介绍win7下搭建apache+php+mysql开发环境
2015/08/06 PHP
一次因composer错误使用引发的问题与解决
2019/03/06 PHP
JavaScript:new 一个函数和直接调用函数的区别分析
2013/07/10 Javascript
关于Jquery操作Cookie取值错误的解决方法
2013/08/26 Javascript
js/jquery去掉空格,回车,换行示例代码
2013/11/05 Javascript
javascript进行数组追加方法小结
2014/06/16 Javascript
js使用递归解析xml
2014/12/12 Javascript
javascript和jquery实现设置和移除文本框默认值效果代码
2015/01/13 Javascript
JavaScript自定义数组排序方法
2015/02/12 Javascript
鼠标事件的screenY,pageY,clientY,layerY,offsetY属性详解
2015/03/12 Javascript
javascript实现图片上传前台页面
2015/08/18 Javascript
jQuery实现仿微软首页感应鼠标变化滑动窗口效果
2015/10/08 Javascript
jQuery版AJAX简易封装代码
2016/09/14 Javascript
详解JS构造函数中this和return
2017/09/16 Javascript
微信小程序之GET请求的实例详解
2017/09/29 Javascript
利用VS Code开发你的第一个AngularJS 2应用程序
2017/12/15 Javascript
js字符串处理之绝妙的代码
2019/04/05 Javascript
javascript for循环性能测试示例
2019/08/07 Javascript
vue计算属性+vue中class与style绑定(推荐)
2020/03/30 Javascript
关于ES6尾调用优化的使用
2020/09/11 Javascript
python中实现延时回调普通函数示例代码
2017/09/08 Python
Python+OpenCV目标跟踪实现基本的运动检测
2018/07/10 Python
Python实现变声器功能(萝莉音御姐音)
2019/12/05 Python
浅谈Pytorch torch.optim优化器个性化的使用
2020/02/20 Python
仓库保管员岗位职责
2013/12/20 职场文书
证婚人经典证婚词
2014/01/09 职场文书
英文推荐信格式范文
2014/05/09 职场文书
2015年司法所工作总结
2015/04/27 职场文书
总结Pyinstaller打包的高级用法
2021/06/28 Python