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 文件操作api(文件操作函数)
Aug 28 Python
Python中执行存储过程及获取存储过程返回值的方法
Oct 07 Python
利用python实现微信头像加红色数字功能
Mar 26 Python
python 画三维图像 曲面图和散点图的示例
Dec 29 Python
python石头剪刀布小游戏(三局两胜制)
Jan 20 Python
python实现一个简单的ping工具方法
Jan 31 Python
python 多个参数不为空校验方法
Feb 14 Python
Python画图实现同一结点多个柱状图的示例
Jul 07 Python
python Dijkstra算法实现最短路径问题的方法
Sep 19 Python
Python多进程编程multiprocessing代码实例
Mar 12 Python
Keras框架中的epoch、bacth、batch size、iteration使用介绍
Jun 10 Python
python Matplotlib基础--如何添加文本和标注
Jan 26 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中的string类型使用说明
2010/07/27 PHP
twig模板常用语句实例小结
2016/02/04 PHP
PHP Imagick完美实现图片裁切、生成缩略图、添加水印
2016/02/22 PHP
thinkPHP3.2简单实现文件上传的方法
2016/05/16 PHP
ThinkPHP3.2框架使用addAll()批量插入数据的方法
2017/03/16 PHP
yii2.0框架使用 beforeAction 防非法登陆的方法分析
2019/09/11 PHP
基于jquery的滚动条滚动固定div(附演示下载)
2012/10/29 Javascript
简单实用的反馈表单无刷新提交带验证
2013/11/15 Javascript
关于jQuery中的each方法(jQuery到底干了什么)
2014/03/05 Javascript
javascript实现字符串反转的方法
2015/02/05 Javascript
node.js+express制作网页计算器
2016/01/17 Javascript
js实现String.Fomat的实例代码
2016/09/02 Javascript
一个可复用的vue分页组件
2017/05/15 Javascript
关于javascript sort()排序你可能忽略的一点理解
2017/07/18 Javascript
Canvas放置反弹效果随机图形(实例)
2017/08/17 Javascript
又拍云 Node.js 实现文件上传、删除功能
2018/10/28 Javascript
js实现页面图片消除效果
2020/03/24 Javascript
Javascript实现秒表计时游戏
2020/05/27 Javascript
关于vue 结合原生js 解决echarts resize问题
2020/07/26 Javascript
详解duck typing鸭子类型程序设计与Python的实现示例
2016/06/03 Python
python导入时小括号大作用
2017/01/10 Python
python得到电脑的开机时间方法
2018/10/15 Python
Python实现的文轩网爬虫完整示例
2019/05/16 Python
pytorch 固定部分参数训练的方法
2019/08/17 Python
css3+jq创作含苞待放的荷花
2014/02/20 HTML / CSS
eDreams意大利:南欧领先的在线旅行社
2018/11/23 全球购物
通信专业个人自我鉴定
2013/10/21 职场文书
好听的队名和口号
2014/06/09 职场文书
公安学专业求职信
2014/07/27 职场文书
优秀班集体申报材料
2014/12/25 职场文书
幼儿园中班教师个人工作总结
2015/02/06 职场文书
文言文辞职信
2015/02/28 职场文书
2015年乡镇安全生产工作总结
2015/05/19 职场文书
公司职员入党自传书
2015/06/26 职场文书
MySQL系列之十一 日志记录
2021/07/02 MySQL
日元符号 ¥
2022/02/17 杂记