|  | 
 
 
上一篇:PHP上传最大限制的注意事项下一篇:PHP5.2、5.3、5.4、5.5的memcache dll扩展下载| 0×00 背景
 红包纷纷何所似?兄子胡儿曰:“撒钱空中差可拟。”兄女道韫曰:“未若姨妈因风起。”背景大家都懂的,要过年了,正是红包满天飞的日子。正巧前两天学会了Python,比较亢奋,就顺便研究了研究微博红包的爬取,为什么是微博红包而不是支付宝红包呢,因为我只懂Web,如果有精力的话之后可能也会研究研究打地鼠算法吧。
 因为本人是初学Python,这个程序也是学了Python后写的第三个程序,所以代码中有啥坑爹的地方请不要当面戳穿,重点是思路,嗯,如果思路中有啥坑爹的的地方也请不要当面戳穿,你看IE都有脸设置自己为默认浏览器,我写篇渣文得瑟得瑟也是可以接受的对吧……
 我用的是Python 2.7,据说Python 2和Python 3差别挺大的,比我还菜的小伙伴请注意。
 
 0×01 思路整理懒得文字叙述了,画了张草图,大家应该可以看懂。 首先老规矩,先引入一坨不知道有啥用但又不能没有的库:
 [mw_shl_code=java,true]import re import urllib import urllib2 import cookielib import base64  import binascii  import os import json import sys  import cPickle as p import rsa[/mw_shl_code]然后顺便声明一些其它变量,以后需要用到:
 
 [mw_shl_code=java,true]reload(sys)sys.setdefaultencoding('utf-8&') #将字符编码置为utf-8luckyList=[] #红包列表lowest=10 #能忍受红包领奖记录最低为多少[/mw_shl_code]这里用到了一个rsa库,Python默认是不自带的,需要安装一下:https://pypi.python.org/pypi/rsa/
 
 下载下来后运行setpy.py install安装,然后就可以开始我们的开发步骤了。
 
 0×02 微博登陆抢红包的动作一定要登陆后才可以进行的,所以一定要有登录的功能,登录不是关键,关键是cookie的保存,这里需要cookielib的配合。 [mw_shl_code=java,true]cj = cookielib.CookieJar()opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))urllib2.install_opener(opener)[/mw_shl_code]这样凡是使用opener进行的网络操作都会对处理cookie的状态,虽然我也不太懂但是感觉好神奇的样子。
 接下来需要封装两个模块,一个是获取数据模块,用来单纯地GET数据,另一个用来POST数据,其实只是多了几个参数,完全可以合并成一个函数,但是我又懒又笨,不想也不会改代码。
 [mw_shl_code=java,true]def getData(url) :        try:                req  = urllib2.Request(url)                result = opener.open(req)                text = result.read()                text=text.decode("utf-8").encode("gbk",'ignore')                return text        except Exception, e:                print u'请求异常,url:'+url                print e def postData(url,data,header) :        try:                data = urllib.urlencode(data)                 req  = urllib2.Request(url,data,header)                result = opener.open(req)                text = result.read()                return text        except Exception, e:                print u'请求异常,url:'+url[/mw_shl_code]有了这两个模块我们就可以GET和POST数据了,其中getData中之所以decode然后又encode啥啥的,是因为在Win7下我调试输出的时候总乱码,所以加了些编码处理,这些都不是重点,下面的login函数才是微博登陆的核心。
 [mw_shl_code=java,true]def login(nick , pwd) :        print u"----------登录中----------"        print  "----------......----------"        prelogin_url = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=%s&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.15)&_=1400822309846' % nick        preLogin = getData(prelogin_url)        servertime = re.findall('"servertime":(.+?),' , preLogin)[0]        pubkey = re.findall('"pubkey":"(.+?)",' , preLogin)[0]        rsakv = re.findall('"rsakv":"(.+?)",' , preLogin)[0]        nonce = re.findall('"nonce":"(.+?)",' , preLogin)[0]        #print bytearray('xxxx','utf-8')        su  = base64.b64encode(urllib.quote(nick))        rsaPublickey= int(pubkey,16)        key = rsa.PublicKey(rsaPublickey,65537)        message = str(servertime) +'\t' + str(nonce) + '\n' + str(pwd)        sp = binascii.b2a_hex(rsa.encrypt(message,key))        header = {'User-Agent' : 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'}        param = {                'entry': 'weibo',                'gateway': '1',                'from': '',                'savestate': '7',                'userticket': '1',                'ssosimplelogin': '1',                'vsnf': '1',                'vsnval': '',                'su': su,                'service': 'miniblog',                'servertime': servertime,                'nonce': nonce,                'pwencode': 'rsa2',                'sp': sp,                'encoding': 'UTF-8',                'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',                'returntype': 'META',                'rsakv' : rsakv,                }        s = postData('http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)',param,header)         try:                urll = re.findall("locatio去掉n.replace\(\'(.+?)\'\);" , s)[0]                login=getData(urll)                print u"---------登录成功!-------"                print  "----------......----------"        except Exception, e:                print u"---------登录失败!-------"                print  "----------......----------"                exit(0)[/mw_shl_code]这里面的参数啊加密算法啊都是从网上抄的,我也不是很懂,大概就是先请求个时间戳和公钥再rsa加密一下最后处理处理提交到新浪登陆接口,从新浪登录成功之后会返回一个微博的地址,需要请求一下,才能让登录状态彻底生效,登录成功后,后面的请求就会带上当前用户的cookie。
 
 0×03 指定红包抽取成功登录微博后,我已迫不及待地想找个红包先试一下子,当然首先是要在浏览器里试的。点啊点啊点啊点的,终于找到了一个带抢红包按钮的页面了,F12召唤出调试器,看看数据包是咋请求的。 
 可以看到请求的地址是http://huodong.weibo.com/aj_hongbao/getlucky,主要参数有两个,一个是ouid,就是红包id,在URL中可以看到,另一个share参数决定是否分享到微博,还有个_t不知道是干啥用的。
 好,现在理论上向这个url提交者三个参数,就可以完成一次红包的抽取,但是,当你真正提交参数的时候,就会发现服务器会很神奇地给你返回这么个串:
 [mw_shl_code=java,true]{"code":303403,"msg":"抱歉,你没有权限访问此页面","data":[]}[/mw_shl_code]这个时候不要惊慌,根据我多年Web开发经验,对方的程序员应该是判断referer了,很简单,把请求过去的header全给抄过去。
 [mw_shl_code=java,true]def getLucky(id): #抽奖程序        print u"---抽红包中:"+str(id)+"---"        print  "----------......----------"         if checkValue(id)==False: #不符合条件,这个是后面的函数                return        luckyUrl="http://huodong.weibo.com/aj_hongbao/getlucky"        param={                'ouid':id,                'share':0,                '_t':0                }         header= {                'Cache-Control':'no-cache',                'Content-Type':'application/x-www-form-urlencoded',                'Origin':'http://huodong.weibo.com',                'Pragma':'no-cache',                'Referer':'http://huodong.weibo.com/hongbao/'+str(id),                'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 BIDUBrowser/6.x Safari/537.36',                'X-Requested-With':'XMLHttpRequest'                }        res = postData(luckyUrl,param,header)[/mw_shl_code]这样的话理论上就没啥问题了,事实上其实也没啥问题。抽奖动作完成后我们是需要判断状态的,返回的res是一个json串,其中code为100000时为成功,为90114时是今天抽奖达到上限,其他值同样是失败,所以:
 [mw_shl_code=java,true]hbRes=json.loads(res)if hbRes["code"]=='901114': #今天红包已经抢完        print u"---------已达上限---------"        print  "----------......----------"        log('lucky',str(id)+'---'+str(hbRes["code"])+'---'+hbRes["data"]["title"])        exit(0)elif hbRes["code"]=='100000':#成功        print u"---------恭喜发财---------"        print  "----------......----------"        log('success',str(id)+'---'+res)        exit(0) if hbRes["data"] and hbRes["data"]["title"]:        print hbRes["data"]["title"]        print  "----------......----------"        log('lucky',str(id)+'---'+str(hbRes["code"])+'---'+hbRes["data"]["title"])else:        print u"---------请求错误---------"        print  "----------......----------"        log('lucky',str(id)+'---'+res)[/mw_shl_code]其中log也是我自定义的一个函数,用来记录日志用的:
 [mw_shl_code=java,true]def log(type,text):        fp = open(type+'.txt','a')        fp.write(text)        fp.write('\r\n')        fp.close()[/mw_shl_code]
 
 
 | 
 |