从零开始写一只爬虫 · 我是人类

从零开始写一只爬虫

我们这回换一个网站吧。不去折磨那个可怜的招聘网站了。毕竟以后还可能再用到它……万一被拉黑了就不好了……

这次我们来抓取一个免费托管dns的网站。

为了证明我是人,我需要模拟一下浏览器

如何把自己变成外星人?只要自己穿上一件外星人的衣服,说外星人的语言,写外星人的文字就行了。别人把你识别为外星人,你就是个外星人。

现在,我们需要做的,就是给我们的请求穿上个“外星人的衣服”。这个“衣服”就是“请求头”,里面带有请求和响应的“概览”比如说,浏览器类型,浏览器版本,浏览器语言,是否支持gzip压缩,http状态(200、404、500等),好多好多。

Windows下有好几个专业的抓取请求头的东西(比如 Fiddler 之类的)。Linux下面我不知道有没有,但是在逛Ubuntu软件中心的时候,我发现了神器Wireshark,去年计算机网络课的时候拿他抓TCP报文、IP数据报来着。

然后我使用了WireShark抓取请求头……妈呀,吓死宝宝了,专业抓包工具就是不含糊,各种请求的细节都抓取到了。但是我只关心我们的请求头部分:

WireShark抓包结果

好的,全都复制下来,然后这样写:

用法么,下面再说。

为了证明我是人,我需要模拟个登录。

先说明啊,我可不会输入验证码。。。把图片显示出来然后自己输入验证码?高难度的样子。

现在,我需要访问http://freedns.afraid.org/subdomain/这个页面:如果已经登录了,那么页面会正常显示。但如果没有登录,则会被带到http://freedns.afraid.org/zc.php?from=L3N1YmRvbWFpbi8=这个登录页面去。而据我观察,这个网站的登录是拿Cookie来实现的。

那好,怎么才能吃到Cookie呢?响应头里面有……真心有。一般来说,登录这件事啊,就是,你点击登录之后,浏览器把用户名密码发给服务器,服务器发回来一段响应,响应头里面包含一小段Cookie。在Cookie有效期内,你都是“已登录”状态。不过不用我们操心,强大的Python有对应的库。将你的“登录”请求发给服务器,服务器发回响应,里面的Cookie能自动被存到一个叫做Cookie Jar的东西里面。以后再请求其他网页,带上这个Cookie Jar就好了。很是方便。

然后我们要做的,就是找到点击“登录”之后,我们的用户名、密码交给谁了。看HTML代码,form里面有啥,咱就提交啥。不过这样并不保险:有的时候JS会在Form里面动态地加上一些隐藏域。所以,最好的办法还是抓!亲,回Windows下面用Fiddler抓吧,找到登录的返回码为200的包就好了。吾等渣渣已经被强大的WireShark虐爆了……

然后找到登录页面上面的form,我们可以看到,需要提交的东西有:用户名username、密码(还是明文密码)password、记住我remember、从哪里来from和做什么操作action。每个网站需要的数据都不一样,自行处理。

和上面的伪装成浏览器的东西整合一下,这一小段登录代码如下:

获取到Cookie之后,在请求头里面,我们会发现至少一个cookie_pair。That's what we need~

(直接把cookie拿到,然后写到请求头里面应该也是可行的吧……)

我是人,我会从页面中发现链接并自动点击

这个嘛……开始的时候不是说了,作为例子的话使用枚举的么。现在同样可以采用“链接发现”这种形式的。做的改动不多,将链接提取出来,放到队列里面就好了。

虽然在这里例子里面我们还是用不到……

这里需要注意两个问题:

第一是,访问过的链接不能重复访问。这个可以用一个set来记录。已经访问的页面。

注意注意注意!数量太大的话会爆内存的!小范围做例子还是可以的。大范围……我也不会……求大神带我飞。

第二是,相对链接,处理会比较麻烦……比如需要先获取到本页面的url,再替换掉最后的部分,再…………Ok,我不想写了……求放过我。

下面的例子里面只能找出绝对路径。我只是写出来做个Demo而已。虽然你会发现那个函数完全没有被调用。

到这里,这是我们目前的全部代码

这个代码和上一篇中的代码,不同之处在于,替换掉了原来的请求器。不过这样一来我就不知道如何控制请求超时这个问题了,只能在全局设置请求超时时间了。

一个锁锁住两个东西(队列,和已经访问过的集合),是不是有点违背“操作系统”的课程内容?好吧我就这样用了,简单粗暴一点吧。

还有就是,这个网站如果要抓取的话,id号在190000左右的成功率会高一点。有兴趣可以自己运行一下看看。总量在120W左右,所有数据拿下来得好几天。(因为粗暴使用的Python的多线程很慢……)

发表评论

电子邮件地址不会被公开。 必填项已用*标注