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函数形参用法实例分析
Aug 04 Python
Python中如何优雅的合并两个字典(dict)方法示例
Aug 09 Python
python实现快速排序的示例(二分法思想)
Mar 12 Python
python 请求服务器的实现代码(http请求和https请求)
May 25 Python
对python 通过ssh访问数据库的实例详解
Feb 19 Python
python 实现返回一个列表中出现次数最多的元素方法
Jun 11 Python
Django发送邮件功能实例详解
Sep 02 Python
flask框架蓝图和子域名配置详解
Jan 25 Python
浅谈Python中的异常和JSON读写数据的实现
Feb 27 Python
Python %r和%s区别代码实例解析
Apr 03 Python
详解Python自动化之文件自动化处理
Jun 21 Python
linux中nohup和后台运行进程查看及终止
Jun 24 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代码
2007/03/03 PHP
php中Swoole的热更新实现代码实例
2021/03/04 PHP
[转]JS宝典学习笔记
2007/02/07 Javascript
window.js 主要包含了页面的一些操作
2009/12/23 Javascript
用jquery与css打造个性化的单选框和复选框
2010/10/20 Javascript
onmouseover和onmouseout的一些问题思考
2013/08/14 Javascript
JS获取URL中的参数数据
2013/12/05 Javascript
下拉框select的绑定示例
2014/09/04 Javascript
同一个网页中实现多个JavaScript特效的方法
2015/02/02 Javascript
JavaScript对象数组排序函数及六个用法
2015/12/23 Javascript
js获取时间精确到秒(年月日)
2016/03/16 Javascript
JS添加删除DIV的简单实例
2016/07/08 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
Jq通过td获取同行其它列td的方法
2016/10/05 Javascript
JavaScript模仿Pinterest实现图片预加载功能
2016/10/25 Javascript
详解Angular.js指令中scope类型的几种特殊情况
2017/02/21 Javascript
vue 登录滑动验证实现代码
2018/08/24 Javascript
微信小程序实现复选框效果
2018/12/28 Javascript
React 组件渲染和更新的实现代码示例
2019/02/21 Javascript
使用element-ui table expand展开行实现手风琴效果
2019/03/15 Javascript
微信小程序的mpvue框架快速上手指南
2019/05/15 Javascript
ES6 Class中实现私有属性的一些方法总结
2019/07/08 Javascript
使用React代码动态生成栅格布局的方法
2020/05/24 Javascript
解决vue 给window添加和移除resize事件遇到的坑
2020/07/21 Javascript
Python的函数嵌套的使用方法
2014/01/24 Python
Python简单实现子网掩码转换的方法
2016/04/13 Python
使用python批量化音乐文件格式转换的实例
2019/01/09 Python
用Python实现将一张图片分成9宫格的示例
2019/07/05 Python
Python中__repr__和__str__区别详解
2019/11/07 Python
Keras SGD 随机梯度下降优化器参数设置方式
2020/06/19 Python
python右对齐的实例方法
2020/07/05 Python
标准毕业生自荐信范文
2013/11/04 职场文书
致百米运动员广播稿
2014/01/29 职场文书
优秀应届毕业生自荐书
2014/06/29 职场文书
自主招生自荐信格式范文
2015/03/25 职场文书
公司仓库管理制度
2015/08/04 职场文书