这篇文章于去年4月发布在个人简书,如今把它放到这里,主要是为了宣传本身的分布式微博爬虫。下面是主要内容,但愿能帮到有这个需求的朋友javascript
最近因为须要一直在研究微博的爬虫,第一步即是模拟登录,从开始摸索到走通模拟登录这条路其实仍是挺艰难的,须要必定的经验,为了让朋友们之后少走点弯路,这里我把个人分析过程和代码都附上来。php
首先,咱们先用正常的帐号登录,具体看会有些什么请求。这里我用的是Http Analyzer抓包(Filders也是一个不错的选择)。下面是正常登录流程的截图:java
接下来我会详细说明各个过程。node
第一步:预登录。python
如今微博、空间等大型网站在输入用户名后基本都会作编码或者加密处理,这里在用户名输入框输入个人帐号,经过抓包工具能够看到服务器会返回一段字符串:git
这一步就是预登录过程,同窗们能够本身试试。登录的时候咱们须要用到其中的servertime、nonce、pubkey等字段。固然这个不是我本身猜测的,后面的步骤会作说明。github
还有一点,就是预登录的url:web
这里su的值是本身用户名通过base64编码的值。但可能大家会问我是如何知道的呢,待会儿我会讲到。通过实测,若是咱们这里不给su传参数,其实也是能够的。为了最真实的模拟用户登陆,咱们最好仍是带上它的值。算法
请看图一的第一条js请求http://i.sso.sina.com.cn/js/ssologin.js
,同窗们能够点进去看,这个就是前面提到的加密用户名和密码等一系列的加密文件了,若是有同窗非要问我是怎么找到这个加密文件的,我也只有说:反复抓包,从在浏览器输入weibo.com事后就找js文件请求路径,而后再用代码格式化工具打开,挨着一个一个看,在代码中搜关键字,好比这里咱们能够搜"nonce"、“servertime”等,就能找到加密文件了。
打开加密文件咱们能够看到加密用户名的代码,在加密js文件中搜索'username',能够看到有一行代码为:
username = sinaSSOEncoder.base64.encode(urlencode(username))
如今咱们能够直接查找encode方法(代码太多就不贴上来了),便可查找到对应方法了,为了验证咱们的猜测,咱们能够在webstorm中copy这个encode函数带上本身的用户名运行,返回的结果就是su的值,这个值在以后进行post提交的时候也会用到。若是对加密有必定经验的同窗可能一眼就会看出这个是base64编码,python中有个base64模块能够干这个事情。咱们再回到图一,http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)
这个地址就是进行post提交数据的地址,下面是我本身提交的数据:
这里咱们须要本身构造su(加密后的用户名),sp(加密后的密码),servertime,nonce,rsakv等数据,其它数据都不用变。有同窗问我为哈其它数据不用变?你本身能够多登录几回,看变化的值,那么那些值就是须要构造的值,其它值就直接拿过来用就好了。这里的su,servertime,nonce,rsakv都已经拿到了,因此当前须要的就只是sp的值了。咱们仍是按照原来的方法在js文件中查找“sp”,能够找到requests.sp=password这段代码,因此咱们就只须要看password怎么构造的了。经过查找能够看到关键加密代码:
password = RSAKey.encrypt([me.servertime,me.nonce].join("t") +"n"+ password)
这一段代码即是加密密码的代码,有经验的同窗一看就知道是用的RSA加密,python中也有相应的rsa加密库可用。可是咱们假设你们都没看出来或者不知道python中有rsa这个第三方库。这时候就要给你们介绍一些个人经验了,我如今已经知道的有三种模拟登录方案:
a)最简单暴力,效率也是最高的,直接把js源码转化为相应的python代码,模拟加密流程进行加密
b)使用selenium+phantomjs/firefox的方案直接模拟人的操做填写表单提交数据进行模拟登录,这种方式最为简单,效率稍微低一些。若是有同窗对这种简单暴力的方式感兴趣,能够到个人github上查看一下源码
c)比较折中的方案,经过pyv8/pyexecjs等渲染js代码进行执行,本文主要就是讲的这种方式。第一种方式若是是遇到微博调整了登录加密算法,就必须改加密代码,第二种方式和第三种方式不存在这个问题。
因为我用的是Python3,并不支持PyV8,因此我选了和它相似的PyexecJS,这个也能够直接执行js代码。我也不是很熟悉Javascript代码,因此我直接定义了一个函数处理加密密码,并没对其加密源代码修改太多:
function get_pass(mypass,nonce,servertime,rsakey){ varRSAKey = newsinaSSOEncoder.RSAKey(); RSAKey.setPublic(rsakey,"10001"); password= RSAKey.encrypt([servertime,nonce].join("\t") +"\n"+ mypass) return password }
这个函数中的东西其实就是copy的加密文件的加密过程代码。为了试验,我直接使用以前本身登录抓到的nonce、servertime、rsakey等数据,在webstorm中调用这个函数,可是报错了,提示"navigator is undefined",webstorm 使用的nodejs的运行时环境,而navigator为浏览器的某个属性,因此运行会出问题。因而我就是用phantomjs来做为运行时环境.考虑到有同窗不知道phantomjs怎么使用,这里我简要说一下吧。使用windows的同窗先要去phantomjs官网下载它的可执行文件,而后设置环境变量。在命令行输入"phantomjs some.js"便可执行some.js文件,其实就和在命令行执行python或者java文件同样,若是不清楚的能够百度执行命令行执行python的方法,仿照着来就能够了,再不清楚就问我。使用ubuntu的同窗能够直接用sudo apt-get install phantomjs,就能够安装使用了。我直接把加密的js文件使用phantomjs运行,果真好着呢。缘由是由于phantomjs其实就是一款无ui的浏览器,天然支持navigator、window等属性。而pyexecjs支持使用phantomjs做为运行时环境,具体用法pyexecjs的git主页有,我也在代码中有所体现。
with open('G:/javascript/sinajs.js','r') as f: source = f.read() phantom = execjs.get('PhantomJS') getpass = phantom.compile(source) mypass = getpass.call('get_pass',my_pass,nonce,servertime,pubkey)
这段代码就能够获得加密事后的密码了。
以后,即可以进行post提交,提交地址能够从抓包工具看到:http://login.sina.com.cn/sso/...。
根据经验,到这里过程基本就完了。可是微博有点坑啊,这里还须要有一步,就是图一所示的相似
这一步会将请求重定向,返回当前帐号的登录信息,以下图:
那么问题来了,怎么获取上面的请求地址呢。分析上面地址,有ticket字段,这个应该是让你登录的凭据,因此这个地址应该是服务端返回的,若是不是,起码ticket是服务端返回的,因而咱们又使用抓包工具查看在请求这段url以前返回的信息,发现有和上述url吻合的信息:
这段代码是使用post后回复的内容,因此能够直接从中提取出咱们须要的url。而后再使用get方式请求上述的url,它会经历一次重定向,直接返回登录信息。这个时候,就表明成功登录了。
PS:授人以鱼不如授人以渔,这是我一直秉承的信念。可能有的老手以为我写得很啰嗦,但其实不少新手可能都不知道这些细节,因此我把我在分析新浪微博模拟登录的过程全写了出来。另外,除了这种方式,本文提到的另外两种方式也有实现。最暴力的方式须要使用rsa这个第三方库,具体我在代码上有详细注释,还有一种是使用selenium+phantomjs这种方式,我也在代码中关键地方有注释,若是想看看具体过程,能够点击这里(个人我的博客)查看分析过程。
Talk is cheap,show me the code!
最后奉上本文的全部方式的模拟登录代码(若是以为喜欢或者看了对你有帮助,不妨在github上给个star,也欢迎fork)
代码连接:smart_login,欢迎fork和star
看了本文还没看够?那么推荐你查看超详细的Python实现百度云盘模拟登录,该文会从另一个角度来谈模拟登录
此外,打一个广告,若是对如何构建分布式爬虫或者大规模微博数据采集感兴趣的话,能够专一一下个人开源分布式微博爬虫项目,目前还在快速迭代,单从功能角度来说,抓取部分基本上快实现和测试完了。