1.5 Hello, Spider!

在掌握了编写Python爬虫所需的准备知识后,就可以上手第一个爬虫程序了。在这里分析一个再简单不过的爬虫,并由此展开进一步的讨论。

1.5.1 编写第一个爬虫程序

在各大编程语言中,初学者要学会编写的第一个简单程序一般就是“Hello, World!”,即通过程序来在屏幕上输出一行“Hello, World!”这样的文字,在Python中,只需一行代码就可以做到。我们把这第一个爬虫就称之为“HelloSpider”,见例1-1。

【例1-1】HelloSpider.py,一个最简单的Python网络爬虫。

我们执行这个脚本,在终端中运行如下命令(也可以在直接IDE中单击“运行”):

很快就能看到输出如下:

这正是“Python之禅”的内容,上面的程序完成了一个网络爬虫程序最普遍的流程:访问站点;定位所需的信息;得到并处理信息。接下来介绍每一行代码都做了什么:

这里使用import导入了两个模块,分别是lxml库中的html以及Python中著名的requests库。lxml是用于解析XML和HTML的工具,可以使用XPath和CSS来定位元素,而requests则是著名的Python HTTP库,其口号是“给人类用的HTTP”,相比于Python自带的urllib库而言,requests有着不少优点,使用起来十分简单,接口设计也非常合理。实际上,对Python比较熟悉的话就会知道,在Python 2中一度存在着urllib, urllib2, urllib3, httplib, httplib2等一堆让人易于混淆的库,可能官方也察觉到了这个缺点,Python 3中的新标准库urllib就比Python 2好用一些。曾有人在网上问道“urllib, urllib2, urllib3的区别是什么,怎么用”,有人回答“为什么不去用requests呢?”,可见requests的确有着十分突出的优点。同时也建议读者,尤其是刚刚接触网络爬虫的人采用requests,可以省时省力。

这里定义了两个变量,Python不需要声明变量的类型,url和xpath会自动被识别为字符串类型。url是一个网页的链接,可以直接在浏览器中打开,页面中包含了Python之禅的文本信息。xpath变量则是一个xpath路径表达式,我们刚才提到,lxml库可以使用xpath来定位元素,当然,定位网页中元素的方法不止xpath一种,以后会介绍更多的定位方法。

这里使用了requests中的get方法,对url发送了一个HTTP GET请求,返回值被赋值给res,于是便得到了一个名为res的Response对象,接下来就可以从这个Response对象中获取想要的信息。

lxml.html是lxml下的一个模块,顾名思义,主要负责处理HTML。fromstring方法传入的参数是res.text,即刚才提到的Response对象的text(文本)内容。在fromstring函数的doc string中(文档字符串,即此方法的说明)说到,这个方法可以“Parse the html, returning a single element/document.”即fromstring根据这段文本来构建一个lxml中的HtmlElement对象。

这两行代码使用xpath来定位HtmlElement中的信息,并进行输出。text就是我们得到的结果,“.join()”是一个字符串方法,用于将序列中的元素以指定的字符连接生成一个新的字符串。因为text是一个list对象,所以使用“”这个空字符来连接。如果不进行这个操作而直接输出:

程序会报错,出现“TypeError: Can't convert 'list' object to str implicitly”这样的错误。当然,对于list序列而言,还可以通过一段循环来输出其中的内容。

值得一提的是,如果不使用requests而使用Python 3的urllib来完成以上操作,需要把其中的两行代码改为:

其中的urllib是Python 3的标准库,包含了很多基本功能,比如向网络请求数据、处理Cookie、自定义请求头(Headers)等。urlopen方法用来通过网络打开并读取远程对象,包括HTML、媒体文件等。显然,就代码量而言,工作量比requests要大,而且看起来也不甚简洁。

提示:urllib是Python 3的标准库,虽然在本书中主要使用requests来代替urllib的某些功能,但作为官方工具,urllib仍然值得进一步了解,在爬虫程序实践中,也可能会用到urllib中的有关功能。有兴趣的读者可阅读urllib的官方文档:https://docs.python.org/3/library/urllib.html,其中给出了详尽的说明。

1.5.2 对爬虫的思考

通过刚才这个十分简单的爬虫示例,我们不难发现,爬虫的核心任务就是访问某个站点(一般为一个URL地址)然后提取其中的特定信息,之后对数据进行处理(在这个例子中只是简单地输出)。当然,根据具体的应用场景,爬虫可能还需要很多其他的功能,比如自动抓取多个页面、处理表单、对数据进行存储或者清洗等。

其实,如果用户只是想获取特定网站所提供的关键数据,而每个网站都提供了自己的API(应用程序接口,Application Programming Interface),那么对于网络爬虫的需求可能就没有那么大了。毕竟,如果网站已经为用户准备好了特定格式的数据,只需要访问API就能够得到所需的信息,那么又有谁愿意费时费力地编写复杂的信息抽取程序呢?现实是,虽然有很多网站都提供了可供普通用户使用的API,但其中很多功能往往是面向商业的收费服务。另外,API毕竟是官方定义的,免费的格式化数据不一定能够满足用户的需求。掌握网络爬虫编写,不仅能够做出只属于自己的功能,还能在某种程度上拥有一个高度个性化的“浏览器”,因此,学习爬虫相关知识是很有必要的。

对于个人编写的爬虫而言,一般不会存在法律和道德问题。但随着与互联网知识产权相关的法律法规逐渐完善,用户在使用自己的爬虫时,还是需要特别注意遵守网站的规定以及公序良俗的。2014年8月微博宣布停止脉脉使用的微博开放平台所有接口,理由是“脉脉通过恶意抓取行为获得并使用了未经微博用户授权的档案数据,违反微博开放平台的开发者协议”。最新出台的《网络安全法》也对企业使用爬虫技术来获取网络上及用户的特定信息这一行为做出了一些规定,可以说,爬虫程序方兴未艾,随着互联网的发展,对于爬虫程序的秩序也提出了新的要求。对于普通个人开发者而言,一般需要注意的包括:

●不应访问和抓取某些充满不良信息的网站,包括一些充斥暴力、色情或反动信息的网站。

●始终注意版权意识。如果你想爬取的信息是其他作者的原创内容,未经作者或版权所有者的授权,请不要将这些信息用作其他用途,尤其是商业方面的行为。

●保持对网站的善意。如果你没有经过网站运营者的同意,使得爬虫程序对目标网站的性能产生了一定影响,恶意造成了服务器资源的大量浪费,那么且不说法律层面,至少这也是不道德的。你的出发点应该是一个爬虫技术的爱好者,而不是一个试图攻击网站的黑客。尤其是分布式大规模爬虫,更需要注意这点。

●请遵循robots.txt和网站服务协议。虽然robots文件只是一个“君子协议”,并没有强制性约束爬虫程序的能力,只是表达了“请不要抓取本网站的这些信息”的意向。在实际的爬虫编写过程中,用户应该尽可能遵循robots.txt的内容,尤其是爬虫无节制地抓取网站内容时。有必要的话,应该查询并牢记网站服务协议中的相关说明。

提示:Robots协议虽然没有强制性,但一般是会受法律承认的。美国联邦法院早在2000年就在eBay vs Bedder's Edge一案中支持了eBay屏蔽BE爬虫的主张。北京第一中级人民法院于2006年在审理泛亚起诉百度侵权案中也认定网站有权利用设置的Robots.txt文件拒绝搜索引擎(百度)的收录。可见,Robots协议在互联网业界和司法界都得到了认可。

关于robots文件的具体内容,会在下一节调研分析网站的过程中继续介绍。