新浪微博爬虫:模拟登陆+爬取原始页面

来源:互联网 发布:mac哪个国家的缩写 编辑:程序博客网 时间:2024/05/20 12:25



最近搞科研,总要有数据,奈何新浪API限制太多。。。。。


网上的新浪爬虫教程太杂乱,就不能简单点让大家都看懂吗????


主要参考:

http://blog.csdn.net/bcj296050240/article/details/46685947

http://www.jianshu.com/p/36a39ea71bfd




用爬虫爬取新浪数据的两个大步骤:

模拟浏览器登录;

爬取数据;

解析数据;




模拟浏览器登录必不可少,像新浪这种动态反扒网站,大致登录流程是:

1)客户端向服务器发送预登陆申请,又服务器动态的为客户端生成servertime, nonce, pubkey等信息。

2)用户名、密码配合返回的servertime, nonce, pubkey等动态信息,生成动态秘钥,并且和其他参数一起POST给服务器。

3)服务器验证用户名、密码正确后,给客户端发送一个真正的登录地址。

4)客户端登录该真正的地址,才算登陆成功。。。。。。。。






1)如何获取服务器为客户端生成servertime, nonce, pubkey等动态的信息:

笼统地说,使用Fiddler抓包分析。具体的:

1)下载Fiddler,安装后打开即可。

2)使用(IE)浏览器登录一次微博,发现Fiddler抓包的记录如下:

右边,五个椭圆信息是动态生成的,具体的,实在请求【server_URL = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)"】时生成的;所以代码应该如下:

server_URL = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)"
response = urllib2.urlopen(server_URL).read()   # 获取网页内容
print 'response', response

解析response就可以得到servertime, nonce, pubkey, rsakv这四个信息了。




2)用户名、密码配合返回的servertime, nonce, pubkey等动态信息,生成动态秘钥,并且和其他参数一起POST给服务器:

具体的,post给服务器的参数包括(就是Fiddler左上角的所有参数):

    post_param = {        "entry": "weibo",        "gateway": "1",        "from": "",        "savestate": "7",        "useticket": "1",        "pagerefer": "",        "vsnf": "1",        "su": s_username,        "service": "miniblog",        "servertime": servertime,        "nonce": nonce,        "pwencode": "rsa2",        "rsakv": rsakv,        "sp": s_password,        "sr": "1920*1080",        "encoding": "UTF-8",        "prelt": "119",        "url": "http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack",        "returntype": "META",        }
其中s_username和s_password是加过密的。


那么加密过程如何呢?

首先我们要在未登录状态到http://login.sina.com.cn/signup/signin.php?entry=sso 这个页面,并得到http://login.sina.com.cn/js/sso/ssologin.js 这个js文件.
查看ssologin.js的makeRequest函数, 原型如下:

var makeRequest = function(username, password, savestate) {    var request = {      entry: me.getEntry(),      gateway: 1,      from: me.from,      savestate: savestate,      useticket: me.useTicket ? 1 : 0    };    if (me.failRedirect) {      me.loginExtraQuery.frd = 1    }    request = objMerge(request, {      pagerefer: document.referrer || ""    });    request = objMerge(request, me.loginExtraFlag);    request = objMerge(request, me.loginExtraQuery);    request.su = sinaSSOEncoder.base64.encode(urlencode(username));    if (me.service) {      request.service = me.service    }    if ((me.loginType & rsa) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.RSAKey) {      request.servertime = me.servertime;      request.nonce = me.nonce;      request.pwencode = "rsa2";      request.rsakv = me.rsakv;      var RSAKey = new sinaSSOEncoder.RSAKey();      RSAKey.setPublic(me.rsaPubkey, "10001");      password = RSAKey.encrypt([me.servertime, me.nonce].join("\t") + "\n" + password)    } else {      if ((me.loginType & wsse) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.hex_sha1) {        request.servertime = me.servertime;        request.nonce = me.nonce;        request.pwencode = "wsse";        password = sinaSSOEncoder.hex_sha1("" + sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(password)) + me.servertime + me.nonce)      }    }    request.sp = password;    try {      request.sr = window.screen.width + "*" + window.screen.height    } catch (e) {}    return request  };
其中我们关心的是:

request.su = sinaSSOEncoder.base64.encode(urlencode(username));if ((me.loginType & rsa) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.RSAKey) {    request.servertime = me.servertime;    request.nonce = me.nonce;    request.pwencode = "rsa2";    request.rsakv = me.rsakv;    var RSAKey = new sinaSSOEncoder.RSAKey();    RSAKey.setPublic(me.rsaPubkey, "10001");    password = RSAKey.encrypt([me.servertime, me.nonce].join("\t") + "\n" + password)}


从代码中我们可以知道su就是经过html字符转义再转成base64编码。

weibo登录对密码有两种加密方式:rsa2与wsse,从上面的截图的pwnencode=rsa2可知, js处理走的是这一部分逻辑。

我们只要把这部分js在python中转义就行了。

加密代码如下:

# 根据明文的用户名信息获取加密后的用户名def get_su(username):    s_username = urllib.quote(username) # html字符转义    s_username = base64.encodestring(s_username) #    return s_username[:-1]    # 根据明文的密码信息以及rsa加密算法的规则生成密码的密文def get_sp(password, servertime, nonce, pubkey):    message = str(servertime) + '\t' + str(nonce) + '\n' + str(password) # 拼接明文加密文件中得到    rsaPublickey = int(pubkey, 16)    key = rsa.PublicKey(rsaPublickey, 65537) #创建公钥,10001对应的10进制    s_password = rsa.encrypt(message, key)  #加密    s_password = binascii.b2a_hex(s_password)  #将加密信息转换为16进制。    return s_password


知道POST参数后,还需要向服务器提交,这次的提交地址是:login_URL = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)"

所以,代码应该如下:

    request = urllib2.Request(url=login_URL, data=post_data, headers=post_Header)    result = urllib2.urlopen(request)    text = result.read() # 读取内容    print "text==>", text
如果成功,text打印出来的信息如下(就是Fiddler的右下角信息):

<html><head><meta http-equiv="Content-Type" content="text/html; charset=GBK" /><title>新浪通行证</title><script charset="utf-8" src="http://i.sso.sina.com.cn/js/ssologin.js"></script></head><body>正在登录 ...<script>try{sinaSSOController.setCrossDomainUrlList({"retcode":0,"arrURL":["http:\/\/passport.97973.com\/sso\/crossdomain?action=login&savestate=1509095303","http:\/\/passport.weibo.cn\/sso\/crossdomain?action=login&savestate=1"]});}catch(e){var msg = e.message;var img = new Image();var type = 1;img.src = 'http://login.sina.com.cn/sso/debuglog?msg=' + msg +'&type=' + type;}try{sinaSSOController.crossDomainAction('login',function(){location.replace('http://passport.weibo.com/wbsso/login?ssosavestate=154553454503&url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%234543D1%43543callback%243Dparent.sinaSSOController.feedBackUrlCallBack%334sudaref%3Dweibo.com&ticket=ST-NjA0MgaewMjQ1MA==-1343359303-xd-7FdfarwtD0D1FBA2634A18BC615D8419&retcode=0');});}catch(e){var msg = e.message;var img = new Image();var type = 2;img.src = 'http://login.sina.com.cn/sso/debuglog?msg=' + msg +'&type=' + type;}</script></body></html>




3)服务器验证用户名、密码正确后,给客户端发送一个真正的登录地址。


如果上一步返回的retcode=0,那么text打印出来的内容中,

sinaSSOController.crossDomainAction('login',function(){location.replace

后面的那个地址就是我们真正想要的登录地址。。。。。。。获取它,并登陆。


4)客户端登录该真正的地址,才算登陆成功。。。。。。。。

第3)步不抛异常,就说明真的登陆成功了,然后请求你要的网页吧。记住,不要太频繁,最好换账号,多个机器一起抓。。。。。




数据解析不讲了,不同页面方法不同。。。。。。。





源码不给了,其实上面已经写了全部的关键代码。有问题的留言,等我这个工作做完了,一并把所有代码放出来。


2 1
原创粉丝点击