Python使用cookielib和urllib2模拟登陆新浪微博并抓取数据

我们都知道HTTP是无连接的状态协议,但是客户端和服务器端需要保持一些相互信息,比如cookie,有了cookie,服务器才能知道刚才是这个用户登录了网站,才会给予客户端访问一些页面的权限。

用浏览器登录新浪微博,必须先登录,登陆成功后,打开其他的网页才能够访问。用程序登录新浪微博或其他验证网站,关键点也在于需要保存cookie,之后附带cookie再来访问网站,才能够达到效果。

这里就需要Python的cookielib和urllib2等的配合,将cookielib绑定到urllib2在一起,就能够在请求网页的时候附带cookie。

具体做法,首先第一步,用firefox的httpfox插件,在浏览器衷开始浏览新浪微博首页,然后登陆,从httpfox的记录中,查看每一步发送了那些数据请求了那个URL;之后再python里面,模拟这个过程,用urllib2.urlopen发送用户名密码到登陆页面,获取登陆后的cookie,之后访问其他页面,获取微博数据。

具体代码,来自豆瓣的一篇文章:地址

本人加了点注释,欢迎大家一起品尝该同学的完美代码:

 

# coding=utf8
import urllib
import urllib2
import cookielib
import base64
import re
import json
import hashlib

# 获取一个保存cookie的对象
cj = cookielib.LWPCookieJar()
# 将一个保存cookie对象,和一个HTTP的cookie的处理器绑定
cookie_support = urllib2.HTTPCookieProcessor(cj)
# 创建一个opener,将保存了cookie的http处理器,还有设置一个handler用于处理http的URL的打开
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
# 将包含了cookie、http处理器、http的handler的资源和urllib2对象板顶在一起
urllib2.install_opener(opener)

postdata = {
    'entry': 'weibo',
    'gateway': '1',
    'from': '',
    'savestate': '7',
    'userticket': '1',
    'ssosimplelogin': '1',
    'vsnf': '1',
    'vsnval': '',
    'su': '',
    'service': 'miniblog',
    'servertime': '',
    'nonce': '',
    'pwencode': 'wsse',
    'sp': '',
    'encoding': 'UTF-8',
    'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
    'returntype': 'META'
}

def get_servertime():

    url = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=dW5kZWZpbmVk&client=ssologin.js(v1.3.18)&_=1329806375939'
    data = urllib2.urlopen(url).read()
    p = re.compile('\((.*)\)')
    try:
        json_data = p.search(data).group(1)
        data = json.loads(json_data)
        servertime = str(data['servertime'])
        nonce = data['nonce']
        return servertime, nonce
    except:
        print 'Get severtime error!'
        return None

def get_pwd(pwd, servertime, nonce):
    pwd1 = hashlib.sha1(pwd).hexdigest()
    pwd2 = hashlib.sha1(pwd1).hexdigest()
    pwd3_ = pwd2 + servertime + nonce
    pwd3 = hashlib.sha1(pwd3_).hexdigest()
    return pwd3

def get_user(username):
    username_ = urllib.quote(username)
    username = base64.encodestring(username_)[:-1]
    return username

def main():
    username = 'www.crazyant.net'  # 微博账号
    pwd = 'xxxx'  # 微博密码
    url = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.18)'
    try:
        servertime, nonce = get_servertime()
    except:
        return
    global postdata
    postdata['servertime'] = servertime
    postdata['nonce'] = nonce
    postdata['su'] = get_user(username)
    postdata['sp'] = get_pwd(pwd, servertime, nonce)
    postdata = urllib.urlencode(postdata)
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'}
    # 其实到了这里,已经能够使用urllib2请求新浪任何的内容了,这里已经登陆成功了
    req = urllib2.Request(
        url=url,
        data=postdata,
        headers=headers
    )
    result = urllib2.urlopen(req)
    text = result.read()
    # print text
    p = re.compile('location\.replace\(\'(.*?)\'\)')
    try:
        login_url = p.search(text).group(1)
        print login_url
        # print login_url
        urllib2.urlopen(login_url)
        print "login success"
    except:
        print 'Login error!'
    # 测试读取数据,下面的URL,可以换成任意的地址,都能把内容读取下来
    req = urllib2.Request(url='http://e.weibo.com/aj/mblog/mbloglist?page=1&count=15&max_id=3463810566724276&pre_page=1&end_id=3458270641877724&pagebar=1&_k=134138430655960&uid=2383944094&_t=0&__rnd=1341384513840',)
    result = urllib2.urlopen(req)
    text = result.read()
    print len(result.read())
    # unicode(eval(b),"utf-8")
    print eval("u'''" + text + "'''") 
main()

其实获取了模拟登陆后的urllib2,可以做抓数据等任何事情,你甚至可以写一个多线程的爬虫来爬遍新浪微博,我一直有这个想法,可从来没有实现。如果您有什么进展,请联系我共同进步。

40 thoughts on “Python使用cookielib和urllib2模拟登陆新浪微博并抓取数据”

  1. 测试了一下。显示login error。 print出来登录内容。提示retcode=4049错误,是要输入验证码。你有遇到吗

    回复
  2. 我试了,可以使用的。代码里的微博账号填写邮箱。给点证据:dhcp-128-194-161-127:~] laocubu% python sinablog.py http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack&ssosavestate=1358630049&ticket=ST-MjAxMDM0MTY4Nw==-1358025249-gz-2EBACFFF073CA3B261FECED20166811B&retcode=0login success0{“key”:”134138430655960″,”code”:”100000″,”msg”:””,”data”:” 【堪培拉天气】今日天气预报:多云;最高气温37°,最低气温20°;降水概率10%;【更多澳洲本土信息,资讯,生活,潮流,时尚尽在澳洲千百度http://t.cn/zOq3IZN</a>】</p&gt; </li>

    回复
  3. sinaSSOEncoder.RSAKey){
    d["servertime"]=k.servertime;
    d["nonce"]=k.nonce;
    d["pwencode"]="rsa2";
    d["rsakv"]=k.rsakv;
    var e=new sinaSSOEncoder.RSAKey();
    e.setPublic(k.rsaPubkey,’10001′);
    b=e.encrypt([k.servertime,k.nonce].join("t")+"n"+b)
    }
    else if((k.loginType&M)&&k.servertime&&sinaSSOEncoder&&sinaSSOEncoder.hex_sha1)
    {
    d["servertime"]=k.servertime;
    d["nonce"]=k.nonce;
    d["pwencode"]="wsse";
    b=sinaSSOEncoder.hex_sha1(""+sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(b))+k.servertime+k.nonce)
    }
    d["sp"]=b;
    return d
    };
    这时新的JS文件 不知道楼组有否研究

    回复
  4. python操作rsa,
    pubkey = page[‘pubkey’]
    n=string.atol(pubkey,16)
    pubkey = rsa.PublicKey(n,65537)
    passwd = rsa.encrypt(passwd.encode(‘utf-8’), pubkey)
    到这一步了,貌似还是不行,求交流,QQ251650053

    回复
  5. 网上找了篇帖子说是和qqmail的rsa一样,就下了qq的javascript版的rsa模拟了一下,和python的一样,加密文件一直再变。python使用的是easy_install 装的rsa,密文也是每次都不一样,据说是使用了填充,sina的脚本还没研究通,提取出来一直运行错误。交流,QQ2507913981

    回复
  6. 如果密文没问题的话,就剩对passwd的输出了,用b2a_hex(passwd)处理后正好256位,但登录还是失败。

    回复
  7. 现在不搞这个了,直接用 sqlite3和cookielib加载chrome或firefox的cookies,一劳永逸,随它登录方式怎么变,只要判断一下cookie提交给那些个网址就行了,最多2,3个urlopen就解决了。

    回复
  8. 你好,我最近模拟登陆也出现了这个问题,请问你解决了吗,是如何解决的。。
    貌似我试过在登陆区域不用验证码。还是不行

    回复
  9. I was wondering if you ever considered changing the structure of your site?

    Its very well written; I love what youve got to say.
    But maybe you could a little more in the
    way of content so people could connect with it better.

    Youve got an awful lot of text for only having one or 2 pictures.
    Maybe you could space it out better?

    回复

回复 周某某 取消回复