最近參加微軟的kinect大賽,報名以後發現有一個網絡投票,票數最多的項目能夠獲得網絡人氣獎。html
這種事,必然是要搞一搞!編程
說幹就幹。瀏覽器
說明:因爲本人過於懶惰,因此就不截圖了,讓你們失望了!服務器
重點看一下思想就能夠了。cookie
第一步先搞清楚投票的具體流程以及可能的限制條件。網絡
通過研究以後,總結以下:less
注意到紅字了是吧,這就是最關鍵的地方了。ide
好了,咱們的初步思路就出來了:工具
手動註冊好賬號——代碼模擬用戶登陸——登陸以後進行投票網站
思路出來了,下面就是工具的選擇。
語言嘛必然是我愛的Python。
工具的話,以前其實作過模擬登陸,簡單來講就是用一個模擬瀏覽器的Python插件,而後進行各類模擬用戶操做,好比點擊按鈕啊輸入信息啊之類的。
可是這類插件主要有兩大問題:
headless是什麼呢,能夠簡單理解爲後臺操做。若是作不到headless,那麼你運行的時候其實仍是須要打開一個瀏覽器,只不過腳本會操做瀏覽器。
因此咱們能夠看到,作不到headless的話,不只看起來很是低端(想象一下電腦屏幕上開着一個瀏覽器,而後自動輸入東西,而你之只能傻坐着什麼都不能作),而且使用起來很不方便,好比在沒有圖形界面的系統就沒法使用了。
只能應用於form是什麼意思呢,咱們拿jQuery來對比吧。jQuery能夠選擇全部HTML裏出現的東西,可是隻能應用於form就意味着只能操做表單,對於其餘元素就無能爲力了。我不知道爲何會出現這種狀況,多是插件底層有一些限制吧,反正大部分插件都只能操做form。
給你們提供三個方案以供參考吧:
大概就是這樣。
重複一下咱們的思路:
登陸——投票
由於我決定採用headless的方案,因此就使用mechanize。
登陸的話沒問題,登陸框原本就是form。投票嘛。。。先放着!咱們先把登陸搞定。
直接上代碼:
# coding:utf-8
import cookielib import mechanize import urllib br = mechanize.Browser() cj = cookielib.LWPCookieJar() br.set_cookiejar(cj) br.open('http://k4w.cn/user/index.html') br.select_form(nr=0) br.form['mail'] = 'xxxx@xxx.com' br.form['password'] = 'xxxxxxx' br.submit()
cookielib是用來操做cookie的。由於咱們登陸以後須要跳轉到投票頁面,若是咱們不保留cookie,那麼網站就會把咱們當作未登陸——別忘了,你如今是用代碼在模擬登陸,因此不要覺得他會自動給你保存cookie。
代碼很簡單吧,我就不解釋了,總之,打開頁面——輸入用戶名密碼——提交
能夠輸出一下結果看看:
.....同上..... response = br.submit() print response.read()
咱們能夠看到輸出的HTML中有「xxx,歡迎你」這樣的字樣,說明已經成功登陸了
下面就是重頭戲了——如何投票。
先具體化投票的操做:
從下拉列表裏選擇「10」,而後點擊肯定。
咱們已經知道,mechanize只能操做form,對於其餘元素是無能爲力的,因此咱們不能直接來模擬人的操做。
那麼該怎麼辦呢?
你們先思考5秒鐘
。。。。。。。。
。。。。。
。。。
。
好吧我知道你直接翻下來了。
我當時但是思考了半天才想出來的啊!!!
咱們能夠換個思路,投票,表面上是人的操做,可是最終發送給服務器的實際上是一個POST請求!因此,咱們能夠跳過模擬操做,直接發送請求!
好的,這下思路清晰了。咱們先——等等,咱們POST什麼東西?
投票啊,告訴服務器咱們投票了。
可是代碼是一個很嚴謹的東西,格式不對的話服務器是不認的!
好吧,此次不思考了,直接告訴你答案吧。
咱們先手動投一次票,而後查看POST請求中的數據格式。
我用的是firebug,打開firebug,而後選擇票數,按肯定按鈕,能夠看到firebug中出來了此次POST請求的具體信息。
咱們點開信息,能夠看到數據的格式:
z_data : 10 id : 99 sid : 78
一下就看出來了嘛!
z_data是票數,id是項目編號,sid。。。好吧我不知道這是什麼。總之就寫78好了。
數據格式獲取到了,下面咱們回到代碼中,模擬一個POST請求:
parameters = {'z_data' : '10', 'id' : '99', 'sid' : '78' } # POST data
data = urllib.urlencode(parameters) response = br.open('http://k4w.cn/zone/z_num.html', data)
很簡單吧?
別忘了import urllib!
好了,咱們和前面的代碼組合起來實驗一下,看看效果。
發現票數確實增長了,咱們的方法是可行的。
而後呢,咱們改一下,加個for循環,這樣就能夠按照咱們設定好的用戶名密碼,自動登陸全部用戶並投票。
基本功能就是這樣了,可是使用了幾天以後發現了一個不爽的地方:投票完要想查看票數還得手動打開網頁。若是能直接顯示出來當前票數就行了!
因而咱們繼續踏上征程。
首先仍是思路:
打開項目頁面——獲取票數——顯示
打開頁面咱們已經會了,br.open()就行。顯示也很簡單,print。那麼怎麼獲取票數呢?
給你們介紹一個新工具——BeautifulSoup,靚湯!
我認可名字有點。。。。
無論了,繼續咱們編程之路。
靚湯是一個解析HTML的插件,介紹完畢。
咱們能夠把獲取到的HTML用靚湯解析一下,而後找到咱們須要的票數對應的那個元素,就能夠獲取票數了。
很簡單是吧!咱們把HTML傳入靚湯。。。。
我靠怎麼出錯了!
Google了半天,原來是HTML中有不規範的標籤,就解析失敗了。
微軟的頁面原來也不符合標準。。。
好吧,解析不了,怎麼辦呢?
有人給出瞭解決辦法:用lxml。
lxml又是個什麼東西?lxml是解析xml的一個插件,可是能夠解析HTML而且,注意啊,而且能夠忽略不規範的標籤。
正好是咱們須要的!
OK,照着官方文檔使用一下~
亮代碼:
br = mechanize.Browser() response = br.open('http://k4w.cn/level_search/1/78/0/0/0.html') page = etree.HTML(response.read().lower().decode('utf-8')) hrefs = page.xpath(u"//span[@class='number n_99']") print "當前票數:" + hrefs[0].text
依然是很簡單不解釋,看看就明白了。
好的,這樣咱們整個刷票腳本就完工了~~
全部代碼來個合影
# coding:utf-8
import cookielib import mechanize import urllib from lxml import etree all_data = [['username1', 'password1'], ['username2', 'password2']] for i in all_data: br = mechanize.Browser() cj = cookielib.LWPCookieJar() br.set_cookiejar(cj) br.open('http://k4w.cn/user/index.html') br.select_form(nr=0) br.form['mail'] = i[0] br.form['password'] = i[1] br.submit() response = br.open('http://k4w.cn/level_search/1/78/0/0/0.html') parameters = {'z_data' : '10', 'id' : '99', 'sid' : '78' } # POST data
data = urllib.urlencode(parameters) response = br.open('http://k4w.cn/zone/z_num.html', data) print "%s 投票成功!" % i[0] br = mechanize.Browser() response = br.open('http://k4w.cn/level_search/1/78/0/0/0.html') page = etree.HTML(response.read().lower().decode('utf-8')) hrefs = page.xpath(u"//span[@class='number n_99']") print "當前票數:" + hrefs[0].text
搞定。
咱們使用了:
咱們實現了:
好了,下面只要把這個腳本放到服務器上,而且設置一下天天運行就能夠了。