1.爬虫定义
爬虫就是用计算机代替人工去获取海量的web数据的程序。是获取数据的一种方式,也是数据分析的前提。
2.编写一个合格的爬虫程序
1)爬虫程序目的不是攻击网站,而是获取开放的数据。但是由于爬虫的程序特性,获取资源速度过快,可能会导致服务器瘫痪。因此爬取信息时需要尽量模仿人工获取行为,所以发送多个请求之间尽量间隔一个合理的随机时间。
2)有些网站对爬虫程序做了一些防备,比如请求头的验证。解决起来很简单,在请求头中加入一些客户端信息(如:User-Agent)或者上下文信息(如:Referer)。
3)有些信息需要登陆之后才能访问。于是模拟登陆就成了爬虫程序需要的基本功能,也是实现起来较为复杂的。
常见的网站登陆校验方式有两种,一种基于cookie,一种基于token。
cookie与服务器端的session一同保证交互的状态,用于克服http请求的无状态特性。这种情况的第一步当然是寻找登陆接口,该过程一般为手动寻找。通过向登陆接口提交账号密码,进行登陆,服务器端登陆校验过后,会在session中记录登录信息,所以只需要保留已验证的cookie,每次请求通过携带cookie信息,就能获得已登陆的权限。
不过模拟登陆实现起来并不简单,因为很多网站的登陆接口远远不止只输入账号密码这么简单。常见的防备有验证码,还有动态生成的一些认证字符串。这些都让爬虫程序的模拟登陆不能做到完全自动化。一些简单的验证码也许能够使用一些图像识别函数库进行自动解析。
不过遇到一些高级的验证方式就可能非常困难了:
更别说一些奇葩的验证码,连手动验证都有点小困难:
以上纯属验证码搞笑,主要还是想说明模拟登陆的困难。
4)页面js的处理,有些数据可能需要执行js代码后才会显示在页面上,这就表示网页源代码中是没有我们需要的数据的。比如常见的ajax请求,获取到数据之后再利用js将数据插入页面。
3.扩展性的思考
对于爬虫程序,要做到有效,就必须要专一。因为web网页结构多种多样,数据在页面上的分布也不尽相同。可以说爬虫程序要做到抽象是很困难的。
不过这也不代表无法得到一个扩展性好的设计。
只要将爬取规则常见的情况列举出来,似乎就能够得到一些共性。
比如,webmagic中就将爬取规则抽象成了help url和target url。前者是列表页面的url,后者是数据实体的url。比如前者代表文章列表,后者就是某个文章页面。这样的设计符合大多数情况。
我们可以把最终要的数据分为三种。
1)一个页面代表一个数据实体。
2)一个接口返回的json或者xml数据代表一个数据实体。
3)一个数据实体的部分数据在一个页面上,部分数据又来自ajax请求。
其中第三种是复杂的,因为需要通过不同的接口拼装出一个数据实体。而程序是难以自行发现这些接口的。
虽然不同网站对登陆的实现不同,但无非是提交账号密码和验证数据给登陆接口。然后通过已认证的cookie或者token作为登陆凭证和服务器进行后续的交互。
难点是,如何让程序自行发现需要进行登陆,或者之前的登陆已失效。服务器肯定是会告诉客户端这些信息的,但是这里不同的网站实现又会不一样,有的网站是直接跳转至登陆页面,而有的网站是返回一个错误码,弹框确认之后再跳转,或者有些设计不佳的网站,登陆失效后什么也不提示,直接不返回任何数据。
总的来说,要把一个爬虫程序做好,最好还是先做到专一,根据不同的网站设计不同的爬取规则,编写不同的实现,这样虽然不易扩展,但实现起来要方便。等这般设计的系统稳定之后,如果业务所需的数据来源不再变化,再将已有的数据来源的通用部分进行抽象,再来考虑扩展性。