我覺得@鮮宏 說的對, "咱是程序員,搶書也得科學", 下午3點多登錄到博客園看到@湯姆大叔 的火爆送書場面還有@鮮宏 的自動搶書工具時, wid也開始琢磨寫個自動搶書的腳本, 經過將近2個小時的努力, Python版的搶書工具也終於成型了, 開始進入正題。
·在寫這個腳本時wid所使用的相關環境介紹:
語言: Python (v2.6)
IDE: PyScripter
·算法原理介紹:
搶評的原理是根據手機版的評論工具對湯姆大叔送書的那篇隨筆進行評論, 嘿嘿~反正大叔沒有說來自手機評論的不算, 用手機模式評論, 提高靈活度嘛, 對不。
第一步: 模擬瀏覽器登錄到博客園, 進行帶cookies的頁面瀏覽;
第二步: 首先從手機模式的某一個評論頁面抓取數據進行分析, 之所以要抓取其中一個評論頁面是因為在手機上的評論默認是顯示第一頁, 而不是最后一頁, 並且沒有直接到達最后一頁的鏈接, 當這個頁面的評論達到30條后就繼續順着頁面向下找, 一直找到最后一個頁面, 也就是最新的評論頁面。
第三步: 獲取最新頁面的評論條數, 在手機模式下的博客園評論每頁至多現在30條, 當最新頁面的評論條數不足30條時使用正則表達式獲取該頁所有評論的發表時間;
第四步: 判斷, 當獲取到的最后一條評論的分鍾數為59, 並且在 10, 12, 14, 16, 18, 20這個幸運小時數內, 執行倒計時60秒評論, 具體倒計時多少秒可以根據自己估算的誤差進行調節, 評論完成后等待55分鍾准備下一輪的搶書.
看具體代碼:
#!/usr/bin/python #------------------------------------------------------------------------------- # Name: GrabBook.py # Purpose: # # Author: Mr.Wid # # Created: 22-10-2012 # Copyright: (c) Mr.Wid 2012 # Licence: GNU GPL #------------------------------------------------------------------------------- import re import time import urllib import urllib2 import httplib import cookielib username = 'mr_wid' #這里是你的用戶名, 改成自己的 password = 'xxxxxxxx' #你的密碼 #先定義好編碼轉換函數 def en(x): return x.encode('utf-8') def cn(x): return x.decode('utf-8') #登錄博客園 def cnblogs_login(): """登錄博客園 cnblogs_login() -> None """ params_post = urllib.urlencode({ '__EVENTTARGET': '', '__EVENTARGUMENT': '', '__VIEWSTATE': r'/wEPDwULLTE1MzYzODg2NzZkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBQtjaGtSZW1lbWJlcm1QYDyKKI9af4b67Mzq2xFaL9Bt', '__EVENTVALIDATION': r'/wEWBQLWwpqPDQLyj/OQAgK3jsrkBALR55GJDgKC3IeGDE1m7t2mGlasoP1Hd9hLaFoI2G05', 'tbUserName':en(username), 'tbPassword':en(password), 'btnLogin':en('登錄') }) cookie=cookielib.CookieJar() opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) urllib2.install_opener(opener) login_response=urllib2.urlopen('http://passport.cnblogs.com/login.aspx?',params_post) #給大叔發表一條評論 def PuhsishContent( content ): """給大叔發表一條評論 PuhsishContent( string content ) -> None """ comment_post = urllib.urlencode({ '__VIEWSTATE':en('/wEPDwUJNDYwODU2NjU1ZGQ='), 'txbComment': en(content), 'btnSubmint': en('提交評論') }) page = urllib2.urlopen( r'http://m.cnblogs.com/mobileAddComment.aspx?id=101461&entry=2733027', comment_post ) data = page.read() page.close() print cn( data ) #正則表達式獲取服務器時間, 實際上是獲取最后一個評論的時間 def GetServerTime( lastPage ): reTime = re.compile( r'(\d.\:\d.)' ) data = urllib2.urlopen( r'http://m.cnblogs.com/101461/comments/2733027.html?p=%s'%lastPage ) txt = data.read() return reTime.findall(txt) #開始搶書啦~ def PuhsishContentInTime(): luckHour = [ 10, 12, 14, 16, 18, 20 ] #這是幸運小時數 lastPage = 71 #假設最新的評論頁面為71, 這個不太重要, 為只要不超過最新的評論頁面程序都會自動找到最新的評論頁面 cnblogs_login() #登錄博客園 while True: timeList = GetServerTime(lastPage) #獲取最新評論時間列表 if len(timeList) >= 30: #當該頁的評論數超過30條數評論頁面自動向下跟進 lastPage += 1 continue currentHour = int( timeList[len(timeList)-1][:2] ) #獲取最新評論的小時數 currentMinute = int( timeList[len(timeList)-1][3:] ) #獲取最新評論的分鍾數 print currentMinute if currentHour in luckHour and currentMinute == 59: #當最新評論的分鍾數為59時開始進入倒計時搶書 for i in range(60): i += 1 time.sleep(1) print '搶書進入倒計時:%d秒'%( 60 - i ) PuhsishContent( '大叔我來搶書啦~搶搶搶搶搶......' ) print '搶書任務完成, 下一輪搶書任何將在55分鍾后自動執行, 等待...' time.sleep(55 * 60) #休息55分鍾, 湯姆大叔說了, 連評無效 #執行搶書動作 PuhsishContentInTime() #掛這慢慢搶吧, 掛三天說不定就...?
·不足之處
本段代碼最大的不足之處就是依然無法獲取服務器的准確時間, 要是能獲取准確的服務器時間那豈不是..? 嘿嘿~ 還有一點就是當59分鍾時如果沒人評論, 而是都是搶着直接從00開始評, 那這段代碼就無效了, 解決的方案也很簡單, 如果59分鍾時真沒人評論, 可以根據本地時間作出發出的評論響應, 還可以多設幾處監測點進行判斷, 這里有興趣的朋友可以自行實現, wid在這就不再多說了。 代碼寫的匆忙, 相關的異常捕獲之類的也沒有進行, 代碼也有不規范之處, 還望大家多多指點!
本段代碼的優點就是搶書的人越多, 換句話說或者是數字59出現的越准確, 搶到書的可能性就越大, 根據現場的勘查, 59分鍾時發出的評論那是相當多啊...!
筆者雖說寫了這段代碼, 但是實際的搶書效果還沒有測試, 僅僅是做了下簡單的實驗, 更完善的搶書方案, 期待您的發布!
最后, 感謝湯姆大叔給了大家一個免費學習JavaScript的機會, 謝謝!
--------------------
wid, 2012.10.22