美文网首页技术Python3自学 爬虫实战我爱编程
超详细的Python实现新浪微博模拟登陆(小白都能懂)

超详细的Python实现新浪微博模拟登陆(小白都能懂)

作者: resolvewang | 来源:发表于2016-04-29 16:07 被阅读23331次

    最近由于需要一直在研究微博的爬虫,第一步便是模拟登陆,从开始摸索到走通模拟登陆这条路其实还是挺艰难的,需要一定的经验,为了让朋友们以后少走点弯路,这里我把我的分析过程和代码都附上来。

    首先,我们先用正常的账号登陆,具体看会有些什么请求。这里我用的是Http Analyzer抓包(Filders也是一个不错的选择)。下面是正常登陆流程的截图:

    图1

    接下来我会详细说明各个过程。

    第一步:预登陆。

    现在微博、空间等大型网站在输入用户名后基本都会做编码或者加密处理,这里在用户名输入框输入我的账号,通过抓包工具可以看到服务器会返回一段字符串:

    图2

    这一步就是预登陆过程,同学们可以自己试试。登陆的时候我们需要用到其中的servertime、nonce、pubkey等字段。当然这个不是我自己猜想的,后面的步骤会做说明。

    还有一点,就是预登陆的url:

    http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.18)&_=1461819359582

    这里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/login.php?client=ssologin.js(v1.4.18)

    根据经验,到这里过程基本就完了。但是微博有点坑啊,这里还需要有一步,就是图一所示的类似http://passport.weibo.com/wbsso/login?ssosavestate=1493447127&url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack&ticket=ST-NTc3NTg1MjMwNw==-1461911127-gz-1DE185DF04280D7E96BDCD14D9D8E235&retcode=0,这一步会将请求重定向,返回当前账号的登陆信息,如下图:

    图三

    那么问题来了,怎么获取上面的请求地址呢。分析上面地址,有ticket字段,这个应该是让你登陆的凭据,所以这个地址应该是服务端返回的,如果不是,起码ticket是服务端返回的,于是我们又使用抓包工具查看在请求这段url之前返回的信息,发现有和上述url吻合的信息:

    图四

    这段代码是使用post后回复的内容,所以可以直接从中提取出我们需要的url。然后再使用get方式请求上述的url,它会经历一次重定向,直接返回登陆信息。这个时候,就代表成功登陆了。

    PS:授人以鱼不如授人以渔,这是我一直秉承的信念。可能有的老手觉得我写得很啰嗦,但其实很多新手可能都不知道这些细节,所以我把我在分析新浪微博模拟登陆的过程全写了出来。另外,除了这种方式,本文提到的另外两种方式也有实现。最暴力的方式需要使用rsa这个第三方库,具体我在代码上有详细注释,还有一种是使用selenium+phantomjs这种方式,我也在代码中关键地方有注释.

    Talk is cheap,show me the code!

    最后奉上本文的所有方式的模拟登陆代码(如果觉得喜欢或者看了对你有帮助,不妨在github上给个star,也欢迎fork)

    代码链接,欢迎fork和star

    相关文章

      网友评论

      • _夏兮:你好请问验证码要如何绕过去,接口可以设置吗
      • 7516feffca81:你好,我看了您在github上的文章《Python爬虫系列:(二)模拟登陆CSDN》https://rookiefly.cn/detail/65,csdn改了新增了一个post参数fkid,是js生成的,但是我不熟悉js,始终无法用execjs解析出fkid,请问能帮忙看看吗?
        resolvewang:没时间和精力,不好意思哈
      • a21e94122c66:博主可以帮忙抓包app的微博怎么模拟登录吗?
        resolvewang:没那个时间和精力,见谅
      • sexy_cyber:为什么phantomjs在命令行跑出来的结果和python代码调用得出的加密结果不一样呢
      • sexy_cyber:用execjs执行报错execjs._exceptions.ProgramError: SyntaxError: Invalid unicode escape in identifier: 'aA\u00ab'
        sexy_cyber:问题解决了
      • efe0ed0c6198:如果开启了登录保护,登录时会跳转到短信验证码页面,这个有什么好的破解思路吗
        resolvewang:@东篱影下又见桃花 短信验证码没办法取破解,估计只有真正做黑客的才有门路
      • 4175a8ac96f4:楼主,你好,看了你的讲解受益匪浅,非常感谢!!我在用爬虫爬取微博数据做点研究,由于是之前写的爬虫,微博登录改了之后就会出现爬虫被重定向到登陆页面而报错,摸索了很久但是由于水平有限。没能解决,看到你的这篇文章又看到了希望,因此想请您帮忙看下怎么调试。不胜感激~方便的话留个QQ,向您讨教学习~若您看到,劳烦回复,在线等~
        resolvewang:@蜡笔小究 不好意思,今天才上简书,不常上。楼上也说了,我有那么一个开源的项目,你可以自己拿去跑一下。同时感谢楼上的答疑
        4175a8ac96f4:@光喝咖啡也不行 谢谢你,已关注~
        c8860909d174:建议你关注作者的分布式爬虫开源项目https://github.com/SpiderClub/weibospider/tree/v1.7.2
      • cade1657bc9b:楼主你好,我对js不是很了解,在js文件里找了半天不太懂servertime怎么来的...能不能指导下
        resolvewang:servertime是服务器端返回的。仔细读读我写的 “预登陆过程”,我猜你没仔细我写的文章
      • anaffmolon:博主你好,想请教1个问题,我用的是谷歌浏览器抓包的,已经勾选了preserve log,但在登录后在network里全文件搜索,没有找到nonce、prelt,所以想问下是抓包漏了吗?谢谢
        resolvewang:chrome的搜索我感觉不是很好用,有的时候是查不到东西,我很少用,一般都用的第三方工具。
        nonce是你输入了账号后就会发出的ajax请求,不是登录的时候发的,你可以在输入账号后让鼠标定位到一个空白的地方,再查看你的network,看看有不有该请求。
        也可能是你需要清空缓存,因为像js这种东西,需要你每次抓包的时候都清空缓存。
      • d9557f883fd8:不知楼主有没遇到过 4401 4402的错误?是加密的问题么?iOS没有现成的模指生成publickey的算法。蛋疼的一b
      • 还记得_3f37:博主,我想请问一下微博登录是不是改了,我用抓包工具没有看见你说的预登录过程
        resolvewang:不好意思,这几天没怎么上简书,回复晚了。我去看了一下,并没有改这个过程,你再确认确认呢
      • a62d86c7888d: 請問sina_login_by_selenium.py 中 “# 如果driver没加入环境变量中,那么就需要明确指定其路径”driver指的是什麼?
        resolvewang:@fqh2017 你把chromedriver升级一下或许可以,firefox新版本可能需要 geckodriver,老版本可以不装任何驱动。
        a62d86c7888d:@resolvewang 謝謝了,可能是我的chrome版本與chromedriver不配,所以怎麼也搞不出, 我的chrome版本太高回不去了 ,換成FIREFOX又變成TypeError: 'module' object is not callable,灰心得很,明天試試Phantomjs,再次感謝
        resolvewang:@fqh2017 webdriver.就是phantomjs或者chrome的chromedriver
      • e65ea5e21e20:博主 请问那个 在sina_login_direct.py中 sp的 公钥key = rsa.PublicKey(rsaPublickey, 65537)
        为什么是65537 ...我填的10001 一直找不到那个返回页面.....尝试了好久好久才发现是 post数据中的sp错了... :sob:
        resolvewang:@用户5222607674 懂了就行了哈
        e65ea5e21e20:@resolvewang 谢谢楼主回复 ,是的, 因为phantomjs没用过, 我是倒着sp生成方法检索找到这一行 RSAKey.setPublic(me.rsaPubkey, "10001") 在sina_login_direct.py发现是65537 对着js文件检索65537 没找到 就以为是更新了公钥生成方法.....:sob: 可能是我找错了js文件??.或者我没有理解rsa函数....学的不久...
        resolvewang:@用户5222607674 js代码中有啊,你用的是直接登录的嘛,所以需要读js代码啊,它的加密源码中就是65537。弄懂了就行了
      • 980e238455bb:大神,我做新浪微博移动版模拟登录的时候,用HTTP Analyzer工具进行抓包,看到了post请求,但很快就被重定向的包给覆盖了,请问我该怎么做?
        resolvewang: @chinshin 你这个是用工具的问题啊。我以前用没有这个情况啊,你看看有不有保持请求这个选项
      • 980e238455bb:楼主你好。我使用的是HTTP Analyzer V7 Stand-alone版本的抓包工具,为什么抓不到http://i.sso.sina.com.cn/js/ssologin.js这个js请求?
        980e238455bb:@resolvewang 楼主,爬虫的话,JavaScript要学到什么程度?
        980e238455bb:@resolvewang 谢谢楼主的指点,终于抓到包了。
        resolvewang: @chinshin 登录点击过后才有的。另外,注意每次抓包之前清除你的浏览器缓存,js很多时候都会被缓存到电脑中的
      • 2h0n9:谢谢大佬分享,正好这段时间模拟登录京东害我死了好多脑细胞
        6b09fdc26f49:@resolvewang 您写的特别好,非常感谢~打算把你的那些各个网站的项目都学习学习。支持!向你学习。我在模拟登陆京东,但现在卡住了,您能帮我看一下吗?步骤跟您差不多,就是京东的JSEncrypt.js和加密的函数分开在两个请求的响应中,我把其中加密的函数复制到JSEncrypt.js中了,但报错,卡住了,说Can't find variable:$ 不知道为什么会这样,是不是我选js选错了,或者要删减些什么?
        6b09fdc26f49:我现在也在模拟登陆京东诶,你应该已经做完了吧,京东的js 文件选哪个?京东的JSEncrypt.js和加密的函数分开在两个请求的响应中,我把其中加密的函数复制到JSEncrypt.js中了,但报错,卡住了,说Can't find variable:$ 实在是不知道怎么解决这个问题,感觉应该有更好的办法。你是怎么处理的?能指点一下吗
        resolvewang: @Lz_Slime 不客气,点个赞支持一下就行咯
      • 35426cf98828:我现在用phantomjs在做其他东西的模拟登陆,因为phantomjs是单实例,所以需要用另外的js runtime,看了一下pyv8 2012年以后谷歌貌似就没在维护了。是不是还有什么其他的js runtime?
        resolvewang: @dezert_storm 是的,去掉dom操作就行了,有的js代码比较长,要去掉dom和bom非常难
        35426cf98828:纠正一下phantom js并不是单实例,但是我在用phantomjs的截图功能,不同的phantom js 实例会相互覆盖,看起来如果我一个phantom js截图,一个只调用js应该没什么问题:joy: 好痛苦,搞了半天发现白折腾了
        35426cf98828:看了pyexecjs支持的js engine试了个遍,发现除了phantomjs其他的js解析都不认识dom 和类似navigator的关键字,现在是一个折中的方案,把那个加密的js里的dom和navigator之类的都去掉,用Nashorn做运行时来解析js,试过了可以
      • 蜗牛仔:问一下楼主,我按照你主要的逻辑获取到了cookie,可以访问PC端,但是访问不了手机端,在浏览器按照这个界面登陆切换到手机端是可以的,楼主知道这是为什么吗
        resolvewang: @蜗牛仔 是的。是模拟登录获取cookie的,但是我是抓的pc端,而非移动端
        蜗牛仔:@resolvewang 我这是这么想的,然后继续fiddler抓包,结果一直抓不到…你爬的微博数据都是基于这个方式获取到的cookie吧
        resolvewang: @蜗牛仔 我猜大概是你在用浏览器访问手机端的时候,它会做一些验证,然后再让你访问,你通过代码访问,就少了这个验证
      • 草妖:666
        resolvewang: @草妖 谢谢支持
      • 9cb124b67683:我用fiddler抓包时发现了,输入完账号后按TAB键时会发送一个get请求,然后返回nonce,rsakv,retcode等那些东西,然后自己输入密码后点击登录 就抓到了post请求,但是post请求的数据跟预登陆get返回的值没什么关系,我直接用python 模仿fiddler那种顺序报错403, 怎么都解决不了
        改革之路:你的博客访问不了,文章说博客里具体内容,是指分析Http,实现抓包吗?
        resolvewang:@密斯特先生2013 你能抽点时间仔细看看我的文章不?我哪里说了要按tab键的,js直接就能监听你页面离开哪个input框了。su直接就是base64encode后的,我实在是看不懂腻味你会这么写。我的建议是仔细读文章,用能跑的代码跑一下,然后你再去想怎么折腾就怎么折腾,别自己想怎样就怎样做。
        9cb124b67683:顺便说下 预登陆的get请求 中su的值 我是这么写的base64.b64encode(username)[:14] + base64.b64encode(urllib.urlencode({'username': username}))[-14:] ,是用户名base64.后的前14个字符和urlencodede base64后的后14个字符
      • b5826635d777:为什么用js解析出来的su 和post中提交的不一样 0.0
        b5826635d777: @resolvewang 解决了,还有问题就是能否保存session返回的cookie 保存到本地,第二次直接通过cookie访问网页,这种可以实现么
        resolvewang:应该没改啊。我还天天都爬微博,都登录上的啊
        resolvewang:难道不是base64编码?
      • 哈喽jv:楼主威武!😍
        resolvewang: @哈喽jv mac会出现这个问题
        哈喽jv:有个问题,我在pycharm上运行 sina_login_pyexecjs.py 文件,报这样的错误:execjs._exceptions.RuntimeUnavailableError: PhantomJS runtime is not available on this system
        但是,我直接在dos命令行里运行该文件 就能正常登陆,。
        请问这个问题怎么解决啊?
        resolvewang: @哈喽jv 谢谢支持哈
      • 一言不合就自闭:我是小白 看不懂..只会get😑
        resolvewang:@穆天子 是的,那段代码你可以自己去动手抓一下包试试,也可以直接上github看一下我保存的。写爬虫的话,麻烦一点的就需要懂一点js,主要是要看得懂
        穆天子:请问get_pass的这段代码是写到加密文件的function SSOController() 中的吗?
        resolvewang:@鲸鱼先生的先 这篇文章只用了get和post,它们都是属于http协议定义的方法,如果你对爬虫技术感兴趣,http协议是需要去了解和学习的
      • unXeer:好像发现您的手机号了。。3303
        resolvewang:@unxeer 能帮助到大家理解模拟登陆就行了:blush:
        resolvewang:@unxeer 。。。确实是,当时没怎么用github,所以传代码的时候没注意,多谢提醒
      • af6bc258f14d:楼主你好, 我用你的方法实现手机端的模拟登录,显示成功.但是,然后去打开爬取网页,结果似乎是登录界面呢?
        resolvewang:@咕噜噜小胖同学 只有贴代码才看得到问题了,你抓包看过吗?
        af6bc258f14d:@resolvewang 我看了你的代码 基本上和你的是一样的 只是没用随机选择account_password多账号,另外我保存了会话,同时也能取到uid,是否成功判断也是和你一样的也是根据status_code 来判断的 同时我也获取了模拟登陆之后的cookie 打开爬取页面是又写了一次cookie进去.嗯,我把你代码也跑来的也是成功的,应该策略没有改变吧
        resolvewang:@咕噜噜小胖同学 我做的是pc端的登录,手机端的登录好像并没有这么复杂,只需要在把关键字段post就行了,但是我也不清楚现在微博改策略没。对了,虽然显示成功了,你做判断没,判断的依据是什么?在你显示成功了过后你能拿到你自己的账号的ID吗?拿不到的话我估计你是没有登录成功的。登录之前用requests.session()保存了会话吗?如果没有也需要保存会话哦。https://github.com/ResolveWang/smart_login/blob/master/sina_login/sina_login_phone.py 这是我以前写的微博wap端的登录代码
      • W_I_S_E:个人博客的地址好像挂了 - -
        resolvewang: @W_I_S_E 确实,多谢提醒
      • 凛华夜子:楼主你好 我想请问下服务器返回的那段字符串 是在哪查看的 我也是用HTTP Analyzer但是似乎还没找到...
        resolvewang: @凛华夜子 你把浏览器缓存清了,然后再填写用户名,填了鼠标在页面别处停顿几下,然后看httpanayzer的response,应该会有返回。我刚看你那个好像都没返回随机码,我这两天在外面不能用电脑,所以无法验证你的错没有,你可以先把我的程序跑一下,然后自己对着程序抓包看看,我的微博爬虫到现在都运行得很稳定。如果不行我后天给你看看。
        凛华夜子:@resolvewang 是Response Content是吗 那里我仔细看了 发现和楼主的内容有一定差异= =

        sinaSSOController.setCrossDomainUrlList({"retcode":0,"arrURL":["http:\/\/passport.97973.com\/sso\/crossdomain?action=login&savestate=1507947940","http:\/\/passport.weibo.cn\/sso\/crossdomain?action=login&savestate=1"]});}

        sinaSSOController.crossDomainAction('login',function(){location.replace('http://passport.weibo.com/wbsso/login?ssosavestate=1507947940&url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack%26sudaref%3Dweibo.com&ticket=ST-MTc4NDM3Njg3MA==-1476411940-gz-F10F94FC261D58C11CB4410ECB3442DE&retcode=0');});}

        就看到这两句比较长的..但好像没有什么重要内容 读的post数据是http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)
        resolvewang:@凛华夜子 有个response,就是httpanalyzer的下面,挨着请求头信息的,你可以看到,不懂欢迎提问
      • ymengyue:文章很赞,有个小建议。建议楼主用markdown中的反引号去标记代码,用引用加代码,总是自动换行。那样,代码读起来有点累。。。
        resolvewang: @ymengyue 嗯嗯,第一次在这上面写,排版可能是有问题。之前都没用过简书,谢谢建议

      本文标题:超详细的Python实现新浪微博模拟登陆(小白都能懂)

      本文链接:https://www.haomeiwen.com/subject/amqhrttx.html