有时或基于如下凡此种种需求,咱们会想要去抓取新浪微博的内容:跨域
想必新浪深知微博内容自己是最其有价值的资产,一旦被竞争对手大批量抓取导入,则辛苦创建起的门槛将瞬间化做他人之嫁衣,所以作了很是繁复的安全保护,包括强制登陆跳转认证、跨域检测、cookie 植入、禁止帐号密码登陆而启用 OAuth2.0 等等。浏览器
近期我的有一些抓取需求,在查询大量过期的网络资料测试无果后,决定另辟蹊径完成这一目标,并最终测试成功。在此分享出来。(这篇文章将提供解决问题的方法思路,但不会给出具体代码。伸手党请移步百度或 Github。)安全
你须要准备:一个我的微博帐号,咱们将透过它去访问其余用户页面,从而抓取。除此以外,别无所求。 服务器
解题思路:cookie
1.最初我从微博 Web 版入手,发现即便是浏览器中可正常查看的内容,若直接经过 PHP 的 curl 或者 file_get_contents 读取,也没法直接取得,而是读取到一串 js 代码,做用是跨域判断+cookie判断+header跳转。料想要模拟的请求和一重重越过的限制定会不少。网络
2.转换思路,既然微博的 Web 版限制不少,那就从移动版下手(移动网页 weibo.cn,而非指移动 App)。移动版碍于手机机能的限制,身份验证要求会下降不少。通过实验,微博移动版的展现规则是:加V用户、微博广场,可直接访问其页面;普通用户,则必须登陆才能看到。而断定当前登陆用户身份的标识,则应该是手机浏览器自己存储的 cookie 与服务端的某个 session 比对。session
3.因为我须要获取普通用户的微博内容,所以还要想办法继续绕。你固然能够每次直接模拟用户登陆,但相对繁琐,我但愿能一劳永逸。既然移动版的身份断定很大程度上依赖手机浏览器 cookie,而通常浏览器 cookie 不那么容易取,且某些土鳖机型连 cookie 都没法记录(号称 1.3 亿月活跃用户的上市公司必定会照顾穷苦大众的),那么微博必定提供了其余退而求其次的解决方法。因而我注意到了登录框下的「记住登陆状态,需支持并打开手机的cookie功能。」选项。curl
See?默认是勾上的,也便是说微博团队主观上是但愿用户勾上这个,从而借助 cookie 判断来提升登陆安全性的。测试
我遂果断取消勾选该选项,输入任何一个本身的微博帐号密码,点击登陆。大数据
4.值得注意的状况出现了:登陆时的验证网页走的是 newlogin.sina.cn,而非勾选状态下会走的 login.sina.cn。说明此种状况下,登陆验证的确是进行了特殊的处理,从而让没有开启 cookie 功能的手机也能被断定为登陆。
查看跳转页面的源代码,发现有以下一行:
若是没有自动跳转,请<a href="http://weibo.cn/?s2w=login&gsid=4uwc8bfa1vnw8ivzI9gUd706F3W&vt=4">点击这里</a>
注意这个 gsid 参数,料想它就是断定本地用户身份的标识,因而整个提取出来(为了个人帐号安全,我对这个案例中的 gsid 作了修改,大家直接照搬是没法成功的,仍是本身跑一遍登陆流程吧)。
5.最精彩的状况来了。为了验证咱们能不能凭这一串 gsid 伪造登陆后的身份,我开启 Chrome 的隐身模式,随便找了一个正常状况下必须登陆才能看到页面的非加V用户,而后在地址栏后面加上了 gsid 参数,URL 整个变成:
http://weibo.cn/u/1665167973?vt=4&st=7fe6&gsid=4uwc8bfa1vnw8ivzI9gUd706F3W
(固然这里的 gsid 我也作了改动,只是做为演示,实际 gsid 还请自行得到)
直接回车!擦,虽然此前没有执行过登陆动做,可是已经以登陆后的的身份在看他的页面内容了哟。这样,我就能够直接凭借上述固定 URL 去爬去用户的内容。
(上图中的「咱们都关注XDash」,你就能够知道当前是登陆状态,取到了用户身份的。事实上的确如此。)
背后原理应该是,以 GET 方式在 URL 中发送了本地登陆后的身份标识,微博服务器比对这串标识来断定对应的登陆用户身份,而后返回到本地,本地因而就以这个用户身份登陆,冠冕堂皇地获取数据了。(大一的时候我曾参与过一个基于 ASP 的校园社区的开发,阅读了帝国 CMS 的代码,那时候对于手机用户的身份认证就是这么原始哒。)
如今想要的一览无余了,接下来...Hulk,smash!
微博手机版,阿喀琉斯的脚后跟。