爬取知乎的一些思路

来源:互联网 发布:西剑流 知乎 编辑:程序博客网 时间:2024/05/16 18:00

简介:在之前的一个爬取知乎问题和答案的项目中遇到了许许多多的问题,写下此篇文章作为总结和回顾

项目文章:http://blog.csdn.net/sinat_34200786/article/details/78449499


模拟登录知乎

模拟登录就是模拟正常登录的流程构造数据包发送给服务器,让服务器认为请求是正常操作发出的,这样我们就能达到登录的目的。那么首先我们就需要知道当点击登录按钮的时候究竟发送了什么数据给服务器。

打开开发者工具,进入知乎首页,随便输入帐号信息点击登录

这里写图片描述

这里写图片描述

当使用邮箱登录时可以发现点击了登录按钮后记录了一个名为 email 的请求。
请求地址:

https://www.zhihu.com/login/email

Form Data:

_xsrfpasswordcaptcha_typeemail

很明显Form Data就是我们要构造的发送给服务器的数据,各数据意义如下:

_xsrf       :随机生成用于防止CSRF攻击的值password    :用户密码captcha_type:验证码类型(cn代表中文验证码)email       :用户帐号

后三项很容易构造,但是_xsrf怎么获得呢?这类值不会存储在本地,那么它是在我们访问登录页时获得的,这个时候可以去登录页源代码里找找,事实上这个_xsrf确实在源代码里面。

这里写图片描述

我们只需将它提取出来就完成Form Data的构造了

构造好数据后构造Request,这时你会发现Response怎么没有数据?这个问题一开始也困扰我,反复查看登录页的请求也没发现漏掉什么重要的请求。

这时想起Form Data中有个captcha_type,那怎么没有验证码?我们直接在网页上登录时不需要填验证码是不是代表我们的爬虫也不要验证码呢?

回想了一下以前某次登录知乎时是需要验证码的,那么应该是Form Data里漏掉了验证码信息导致登录失败
登录页源代码似乎也证明了这一点

这里写图片描述

但是请求里面没有请求验证码我们要怎么获取验证码?后来知道其实是因为浏览器本地保留了知乎的cookie所以我们除了头几次登陆需要验证码后面都不需要验证码,那么只要把本地保存的cookie删掉就行。

这里写图片描述

这时再登陆就需要验证码了

这里写图片描述

可以看到开发者工具中验证码的请求

这里写图片描述

请求地址:

https://www.zhihu.com/captcha.gif?r=1510991231000&type=login&lang=cn

此时输入信息登陆,查看Form Data中验证码的数据格式

这里写图片描述

验证信息:

captcha : {img_size:[200,44],input_points:[倒立文字位置,倒立文字位置]}

分析一下验证码的请求地址可以发现请求地址中的那串数字是一个时间戳,
这个时间戳在源代码里也有,就在发现_xsrf的位置上面

这里写图片描述

通过查资料发现每个文字的位置都是固定的,具体如下:

capacha_index = [    [12.95, 14.969999999999998],    [36.1, 16.009999999999998],    [57.16, 24.44],    [84.52, 19.17],    [108.72, 28.64],    [132.95, 24.44],    [151.89, 23.380000000000002]]

知道这些信息已经足够构造Form Data的验证码数据了,事实证明Form Data中加上验证码信息后可以登录成功。

模拟登录流程如下:

构造登录页的Request,从Response中提取_xsrf和时间戳构造验证码地址,设置header['X-Xsrftoken'] = _xsrf, 构造Form Data请求验证码(下载验证码到本地)构造验证信息写入到Form Data请求登录

模拟翻页

登录进来了,开始抓取问题链接,这时却发现只有10条不到。因为知乎是在你差不多下拉到页面底部时才向服务器请求数据,动态更新首页问题。为了抓取更多的问题我们就需要构造相应的请求发往服务器。

同样是在开发者工具中,可以发现动态更新的请求链接

这里写图片描述

链接如下:

https://www.zhihu.com/api/v3/feed/topstory?action_feed=True&limit=10&session_token=32992c5f0596214aa6038dec3b973b70&action=down&after_id=9&desktop=true

可以发现session_token就是我们需要构造的数据,一般来说与token对应还会有个Authorization
在请求头中确实发现了Authorization

这里写图片描述

Authorization:

Bearer Mi4xTndyS0FnQUFBQUFBY0VJYUFXUm1DeGNBQUFCaEFsVk5uWFQ5V2dBSVhoNGp3N0ZSLVZpVHpPTHc3UjMyN2x4enZn|1511007901|8a7d8fffa292d469f9766694acf18a729545babc

所以如果我们想获取更多的问题那么我们需要session_token构造更新链接,需要Authorization附加在请求头中完成验证。那么怎么找到这两个值呢?一般session_token会在登录后由服务器发往浏览器,不过在检查了登录后的所有请求后并没有发现session_token,当然也没有发现服务器把Authorization发送过来,所以这两个值应该都是本地生成后附加在请求中的。按照发现_xsrf和时间戳的思路,去首页源代码里找,事实上确实在源代码里。

这里写图片描述

这里写图片描述

你问我怎么在这一坨代码里面找出来?善用浏览器的查找功能。

找到这两个值后只需要更改链接里的after_id我们就可以模拟翻页了,该链接的Response是json数据,很方便解析。和我们在首页直接匹配到的问题URL不同的是返回的数据里的问题URL是不能直接访问的,所以需要将URL里面的question_id提取出来自己拼接成一般的URL。


获取问题的答案

和知乎首页一样,每一个问题的首页也是只有几个答案,剩下的答案需要动态的申请。
首先随便在首页点击一个问题,进入问题首页。

这里写图片描述

这里写图片描述

可以发现URL后面跟着 /answer/number 的问题页都有一个 “查看全部X个回答”的按钮,而如果URL后面没有 /answer/number 的就没有这个按钮

尝试从 “查看全部X个答案”的按钮下手,点击这个按钮可以发现请求了一个超长的链接

这里写图片描述

https://www.zhihu.com/api/v4/questions/52806729/answers?include=data%5B*%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Cquestion%2Cexcerpt%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B*%5D.mark_infos%5B*%5D.url%3Bdata%5B*%5D.author.follower_count%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=3&limit=20&sort_by=default

发现有offset 和 limit 两个值,可以猜测是请求从offset位置开始limit个答案的数据
实际测试结果也确实如此并且返回json数据,只不过limit是固定为20的,就是说每次只能获取20个答案的数据,需要更多循环请求就行了。


参考资料

参考资料一

参考资料二