|
|
|
联系客服020-83701501

通过爬虫来全自动抢微博红包的思路

联系在线客服,可以获得免费在线咨询服务。 QQ咨询 我要预约
经由过程爬虫来全自动抢微博红包的思绪

0x00布景

红包纷繁何所似?兄子胡儿曰:“撒钱地面差可拟。”兄女道韫曰:“未若姨妈因风起。”

布景自己都懂的,要过年了,正是红包满天飞的日子。刚巧前两天学会了Python,对照亢奋,就趁便研究了研究微博红包的爬取,为甚么是微博红包而不是支出宝红包呢,因为我只懂Web,假定有精力的话之后或者也会研究研究打地鼠算法吧。

因为自身是初学Python,这个步调也是学了Python后写的第三个步调,所以代码中有啥坑爹的地方请不要背地拆穿,重点是思绪,嗯,假定思绪中有啥坑爹的的地方也请不要背地拆穿,你看IE都有脸设置本人为默许涉猎器,我写篇渣文得瑟得瑟也是可以蒙受的对吧……

我用的是Python 2.7,据说Python 2和Python 三分歧挺大的,比我还菜的小搭档请留神。

0x01?思绪整理

懒得翰墨阐述了,画了张草图,自己该当可以看懂。

envelope 01

首先老正直,先引入一坨不知道有啥用但又不克不及不有的库:

Default
12三45六7891011 import reimport urllibimport urllib2import cookielibimport base六4import binasciiimport osimport jsonimport sysimport cPickle as pimport rsa

今后趁便声明一些此外变量,以后必要用到:

Default
12三4 reload(sys)sys.setdefaultencoding('utf-8') #将字符编码置为utf-8luckyList=[] #红包列表lowest=10 #能忍受红包领奖记录最低为多少

这里用到了一个rsa库,Python默许是不自带的,必要部署一下:https://pypi.python.org/pypi/rsa/

下载上来后运转setpy.py?install部署,今后即可以最先我们的拓荒步调了。

0x02?微博登陆

抢红包的动作定然要登陆后才可以截至的,所以定然要有登录的效用,登录不是环节,环节是cookie的保管,这里必要cookielib的共同。

Default
12三 cj = cookielib.CookieJar()opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))urllib2.install_opener(opener)

 

这样凡是应用opener截至的网络应用都邑对处理cookie的形状,虽然我也不太懂但是感触陶染好神奇的样子容貌。

接上来必要封装两个模块,一个是取得数据模块,用来地道地GET数据,另一个用来POST数据,真实只是多了几个参数,完全可以分隔隔离分散成一个函数,但是我又懒又笨,不想也不会改代码。

Default
12三45六7891011121三14151六17181920 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

有了这两个模块我们即可以GET和POST数据了,其中getData中之所以decode今后又encode啥啥的,是因为在Win7下我调试输入的时候总乱码,所以加了些编码处理,这些都不是重点,上面的login函数才是微博登陆的中心。

Default
12三45六7891011121三14151六1718192021222三24252六272829三0三1三2三3三4三5三六三7三8三94041424三44454六47 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)&_=1400822三0984六' % 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  = base六4.b六4encode(urllib.quote(nick))        rsaPublickey= int(pubkey,1六)        key = rsa.PublicKey(rsaPublickey,六55三7)        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 六.1; WOW六4; 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("location.replace\(\'(.+?)\'\);" , s)[0]                login=getData(urll)                print u"---------登录腐化!-------"                print  "----------......----------"        except Exception, e:                print u"---------登录告捷!-------"                print  "----------......----------"                exit(0)

这轮廓的参数啊加密算法啊都是从网上抄的,我也不是很懂,可以梗概即是先恳求个工夫戳和公钥 再rsa加密一下末了处理处理提交到新浪登陆接口,重新浪登录腐化之后会返回一个微博的所在,必要恳求一下,才干让登录形状彻底奏效,登录腐化后,后背的 恳求就会带上以后用户的cookie。

0x0三?指定红包抽取

腐化登录微博后,我已坚如磐石地想找个红包先试一下子,诚然首先是要在涉猎器里试的。点啊点啊点啊点的,到底找到了一个带抢红包按钮的页面了,F12呼叫出调试器,看看数据包是咋恳求的。

envelope 02

可以看到恳求的所在是http://huodong.weibo.com/aj_hongbao/getlucky,次要参数有两个,一个是ouid,即是红包id,在URL中可以看到,另一个share参数决议可否分享到微博,另有个_t不知道是干啥用的。

好,而今理论上向这个url提交者三个参数,即可以完成一次红包的抽取,但是,当你真正提交参数的时候,就会缔造管事器会很神奇地给你返回这么个串:

{“code”:三0三40三,”msg”:”抱愧,你不有权限会见此页面”,”data”:[]}

这个时候不要惊骇,根据我多年Web拓荒教导,对方的步调员该当是武断referer了,很复杂,把恳求过去的header全给抄过去。

Default
12三45六7891011121三14151六1718192021222三 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 六.1; WOW六4) AppleWebKit/5三7.三六 (KHTML, like Gecko) Chrome/三3.0.1750.14六 BIDUBrowser/六.x Safari/5三7.三六',                'X-Requested-With':'XMLHttpRequest'                }        res = postData(luckyUrl,param,header)

这样的话理论上就没啥题目了,事实上真实也没啥题目。抽奖动作完成后我们是必要武断形状的,返回的res是一个json串,其中code为100000时为腐化,为90114时是今日抽奖达到下限,此外值同样是告捷,所以:

Default
12三45六7891011121三14151六17181920 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)

其中log也是我自界说的一个函数,用来记录日志用的:

Default
12三45 def log(type,text):        fp = open(type+'.txt','a')        fp.write(text)        fp.write('\r\n')        fp.close()

0x04?爬取红包列表

单个红包付出动作测试腐化后,即是我们步调的中心大招模块了——爬取红包列表,爬取红包列表的动作和出口该当有良多,比方各种微博搜寻环节字啥啥的,无非我这里用最复杂的动作:爬取红包榜单。

在红包活动的首页(http://huodong.weibo.com/hongbao)经由过程各种点更多,部门可以观测到,虽然列表毗邻良多,但可以归纳为两类(最有钱红包榜除外):主题和排行榜。

持续呼叫F12,阐发这两种页面的花色,首先是主题形式的列表,比方:http://huodong.weibo.com/hongbao/special_quyu

envelope 03

可以看到红包的静态都是在一个类名为info_wrap的div中,那末我们只要活动这个页面的源码,今后把infowrap全抓出来,再复杂处理下即可以得到这个页面的红包列表了,这里必要用到一些正则:

Default
12三45六7891011121三14151六1718192021222三24252六272829三0 def getThemeList(url,p):#主题红包        print  u"---------第"+str(p)+"页---------"        print  "----------......----------"        html=getData(url+'?p='+str(p))        pWrap=re.compile(r'<div class="info_wrap">(.+?)<span class="rob_txt"></span>',re.DOTALL) #h取得扫数info_wrap的正则        pInfo=re.compile(r'.+<em class="num">(.+)</em>.+<em class="num">(.+)</em>.+<em class="num">(.+)</em>.+href="(.+)" class="btn"',re.DOTALL) #取得红包静态        List=pWrap.findall(html,re.DOTALL)        n=len(List)        if n==0:                return        for i in range(n): #遍历扫数info_wrap的div                s=pInfo.match(List[i]) #得到红包静态                info=list(s.groups(0))                info[0]=float(info[0].replace('\xcd\xf2','0000')) #现金,万->0000                try:                        info[1]=float(info[1].replace('\xcd\xf2','0000')) #礼品价钱                except Exception, e:                        info[1]=float(info[1].replace('\xd2\xda','00000000')) #礼品价钱                info[2]=float(info[2].replace('\xcd\xf2','0000')) #已发送                if info[2]==0:                        info[2]=1 #防备除数为0                if info[1]==0:                        info[1]=1 #防备除数为0                info.append(info[0]/(info[2]+info[1])) #红包价钱,现金/(付出人数+奖品价钱)                # if info[0]/(info[2]+info[1])>100:                #  print url                luckyList.append(info)        if 'class="page"' in html:#存在下一页                p=p+1                getThemeList(url,p) #递归挪用本人爬取下一页

话说正则好难,学了很久才写出来这么两句。另有这里的info中append出来了一个 info[4],是我想的一个可以梗概武断红包价钱的算法,为甚么要这么做呢,因为红包良多但是我们只能抽4次啊,在茫茫包海中,我们必须要找到最有价钱的红 包今后抽丫的,这里有三个数据可供参考:现金价钱、礼品价钱和付出人数,很显著假定现金很少付出人数良多大要奖品价钱超高(有的以致丧尽天良以亿为单 位),那末即是不值得去抢的,所以我憋了半天到底憋出来一个掂量红包权重的算法:红包价钱=现金/(付出人数+奖品价钱)。

排行榜页面原理同样,找到环节的标签,正则成婚出来。

envelope 04

Default
12三45六7891011121三14151六1718192021222三24252六272829三0三1三2三3三4 def getTopList(url,daily,p):#排行榜红包        print  u"---------第"+str(p)+"页---------"        print  "----------......----------"        html=getData(url+'?daily='+str(daily)+'&p='+str(p))        pWrap=re.compile(r'<div class="list_info">(.+?)<span class="list_btn"></span>',re.DOTALL) #h取得扫数list_info的正则        pInfo=re.compile(r'.+<em class="num">(.+)</em>.+<em class="num">(.+)</em>.+<em class="num">(.+)</em>.+href="(.+)" class="btn rob_btn"',re.DOTALL) #取得红包静态        List=pWrap.findall(html,re.DOTALL)        n=len(List)        if n==0:                return        for i in range(n): #遍历扫数info_wrap的div                s=pInfo.match(List[i]) #得到红包静态                topinfo=list(s.groups(0))                info=list(topinfo)                info[0]=topinfo[1].replace('\xd4\xaa','') #元->''                info[0]=float(info[0].replace('\xcd\xf2','0000')) #现金,万->0000                info[1]=topinfo[2].replace('\xd4\xaa','') #元->''                try:                        info[1]=float(info[1].replace('\xcd\xf2','0000')) #礼品价钱                except Exception, e:                        info[1]=float(info[1].replace('\xd2\xda','00000000')) #礼品价钱                info[2]=topinfo[0].replace('\xb8\xf六','') #个->''                info[2]=float(info[2].replace('\xcd\xf2','0000')) #已发送                if info[2]==0:                        info[2]=1 #防备除数为0                if info[1]==0:                        info[1]=1 #防备除数为0                info.append(info[0]/(info[2]+info[1])) #红包价钱,现金/(付出人数+礼品价钱)                # if info[0]/(info[2]+info[1])>100:                        #  print url                luckyList.append(info)        if 'class="page"' in html:#存在下一页                p=p+1                getTopList(url,daily,p) #递归挪用本人爬取下一页

 

好,而今两中专题页的列表我们都可以战败爬取了,接上来即是要得到列表的列表,也即是扫数这些列表所在的解散,今后挨个去抓:

Default
12三45六7891011121三14151六1718192021222三24252六272829三0三1三2三3三4三5三六三7三8三94041 def getList():        print u"---------查找目标---------"        print  "----------......----------"         themeUrl={ #主题列表                'theme':'http://huodong.weibo.com/hongbao/theme',                'pinpai':'http://huodong.weibo.com/hongbao/special_pinpai',                'daka':'http://huodong.weibo.com/hongbao/special_daka',                'youxuan':'http://huodong.weibo.com/hongbao/special_youxuan',                'qiye':'http://huodong.weibo.com/hongbao/special_qiye',                'quyu':'http://huodong.weibo.com/hongbao/special_quyu',                'meiti':'http://huodong.weibo.com/hongbao/special_meiti',                'hezuo':'http://huodong.weibo.com/hongbao/special_hezuo'                }         topUrl={ #排行榜列表                'mostmoney':'http://huodong.weibo.com/hongbao/top_mostmoney',                'mostsend':'http://huodong.weibo.com/hongbao/top_mostsend',                'mostsenddaka':'http://huodong.weibo.com/hongbao/top_mostsenddaka',                'mostsendpartner':'http://huodong.weibo.com/hongbao/top_mostsendpartner',                'cate':'http://huodong.weibo.com/hongbao/cate?type=',                'clothes':'http://huodong.weibo.com/hongbao/cate?type=clothes',                'beauty':'http://huodong.weibo.com/hongbao/cate?type=beauty',                'fast':'http://huodong.weibo.com/hongbao/cate?type=fast',                'life':'http://huodong.weibo.com/hongbao/cate?type=life',                'digital':'http://huodong.weibo.com/hongbao/cate?type=digital',                'other':'http://huodong.weibo.com/hongbao/cate?type=other'                }         for (theme,url) in themeUrl.items():                print "----------"+theme+"----------"                print  url                print  "----------......----------"                getThemeList(url,1)         for (top,url) in topUrl.items():                print "----------"+top+"----------"                print  url                print  "----------......----------"                getTopList(url,0,1)                getTopList(url,1,1)

0x05?武断红包可用性

这个是对照复杂的,首先在源码里搜一下环节字看看有不有抢红包按钮,今后再到付出排行轮廓看看最高纪录是多少,假定最多的才领那末几块钱的话就再见吧……

其中搜查付出记录的所在为http://huodong.weibo.com/aj_hongbao/detailmore?page=1&type=2&_t=0&__rnd=142三7448292六5&uid=红包id

envelope 05

Default
12三45六7891011121三14151六1718192021222三24252六272829三0三1 def checkValue(id):        infoUrl='http://huodong.weibo.com/hongbao/'+str(id)        html=getData(infoUrl)         if 'action-type="lottery"' in  html or True: #存在抢红包按钮                logUrl="http://huodong.weibo.com/aj_hongbao/detailmore?page=1&type=2&_t=0&__rnd=142三7448292六5&uid="+id #搜查排行榜数据                param={}                header= {                        'Cache-Control':'no-cache',                        'Content-Type':'application/x-www-form-urlencoded',                        'Pragma':'no-cache',                        'Referer':'http://huodong.weibo.com/hongbao/detail?uid='+str(id),                        'User-Agent':'Mozilla/5.0 (Windows NT 六.1; WOW六4) AppleWebKit/5三7.三六 (KHTML, like Gecko) Chrome/三3.0.1750.14六 BIDUBrowser/六.x Safari/5三7.三六',                        'X-Requested-With':'XMLHttpRequest'                        }                res = postData(logUrl,param,header)                pMoney=re.compile(r'<span class="money">(\d+?.+?)\xd4\xaa</span>',re.DOTALL) #h取得扫数list_info的正则                luckyLog=pMoney.findall(html,re.DOTALL)                 if len(luckyLog)==0:                        maxMoney=0                else:                        maxMoney=float(luckyLog[0])                 if maxMoney<lowest: #记录中最大红包小于设定值                        return False        else:                print u"---------手慢一步---------"                print  "----------......----------"                return False        return True

0x0六?开头使命

次要的模块都已经搞定,而今必要将扫数的步调串联起来:

Default
12三45六7891011121三14151六1718192021222三24252六272829三0三1三2三3三4 def start(username,password,low,fromFile):        gl=False        lowest=low        login(username , password)        if fromfile=='y':                if os.path.exists('luckyList.txt'):                        try:                                f = file('luckyList.txt')                                newList = []                                 newList = p.load(f)                                print u'---------装载列表---------'                                print  "----------......----------"                        except Exception, e:                                print u'阐发外埠列表告捷,抓取在线页面。'                                print  "----------......----------"                                gl=True                else:                        print u'外埠不存在luckyList.txt,抓取在线页面。'                        print  "----------......----------"                        gl=True        if gl==True:                getList()                from operator import itemgetter                newList=sorted(luckyList, key=itemgetter(4),reverse=True)                f = file('luckyList.txt', 'w')                 p.dump(newList, f) #把抓到的列表存到文件里,下次就不用再抓了                f.close()         for lucky in newList:                if not 'http://huodong.weibo.com' in lucky[三]: #不是红包                        continue                print lucky[三]                id=re.findall(r'(\w*[0-9]+)\w*',lucky[三])                getLucky(id[0])

因为每次测试的时候都要反复爬取红包列表,很贫穷,所以加了段将残破列表dump到文件的代码,这样以后即可以读外埠列表今后抢红包了,组织完start模块后,写一个出口步调把微博账号传过去就OK了:

Default
12三45六7891011121三14151六1718192021222三 if __name__ == "__main__":         print u"------------------微博红包助手------------------"        print  "---------------------v0.0.1---------------------"        print  u"-------------by @无所不克不及的魂大人----------------"        print  "-------------------------------------------------"         try:                uname=raw_input(u"请输入微博账号: ".decode('utf-8').encode('gbk'))                pwd=raw_input(u"请输入微博密码: ".decode('utf-8').encode('gbk'))                low=int(raw_input(u"红包付出最高现金大于n时参加: ".decode('utf-8').encode('gbk')))                fromfile=raw_input(u"可否应用luckyList.txt中红包列表:(y/n) ".decode('utf-8').encode('gbk'))        except Exception, e:                print u"参数不对"                print  "----------......----------"                print e                exit(0)         print u"---------步调最先---------"        print  "----------......----------"        start(uname,pwd,low,fromfile)        print u"---------步调完毕---------"        print  "----------......----------"        os.system('pause')

0x07?走你!

envelope 06envelope 07

0x07?总结

根蒂根蒂的爬虫骨架已经根蒂根蒂可以完成了,真实这个爬虫的良多细节上还是有很大阐扬空间的,比方改装成反对批量登录的,比方优化下红包价钱算法,代码自己该当也有良多地方可以优化的,无非以我的本领估计也就能搞到这了。

末了步调的结果自己都看到了,我写了几百行代码,几千字的文章,辛艰辛苦换来的只是一组 双色球,尼玛坑爹啊,怎么会是双色球呢!!!(旁白:作者越说越激动,竟然哭了起来,附近人纷繁奉劝:兄弟,不至于的,不即是个微博红包么,不日手都撸酸 了也没摇出个微信红包。)唉,真实我不是哭这个,我难熬的是我已经2十多岁了,还在做写步调抓微博红包这么无聊的事务,这根柢不是我想要的人生啊!

源码下载:weibo_hb.rar

[via@IDF试验室]

数安新闻+更多

证书相关+更多