Python刷票小腳本——網絡人氣獎?不好意思,我要了


零、前言

最近參加微軟的kinect大賽,報名之后發現有一個網絡投票,票數最多的項目可以得到網絡人氣獎。

這種事,必然是要搞一搞!

說干就干。

 

 

 

說明:由於本人過於懶惰,所以就不截圖了,讓大家失望了!

重點看一下思想就可以了。

 

 

一、探查敵情

第一步先搞清楚投票的具體流程以及可能的限制條件。

經過研究之后,總結如下:

  • 投票需要登錄
  • 注冊帳號需要驗證郵箱
  • 登錄不需要驗證碼
  • 每個帳號一天可以投一次票,票數可以選擇,從0~10
  • 投票不需要驗證碼

 

注意到紅字了是吧,這就是最關鍵的地方了。

 

好了,我們的初步思路就出來了:

手動注冊好帳號——代碼模擬用戶登錄——登錄之后進行投票

 

思路出來了,下面就是工具的選擇。

 

二、工欲利其事。。。

語言嘛必然是我愛的Python。

工具的話,之前其實做過模擬登錄,簡單來說就是用一個模擬瀏覽器的Python插件,然后進行各種模擬用戶操作,比如點擊按鈕啊輸入信息啊之類的。

但是這類插件主要有兩大問題:

  1. headless的很少
  2. 基本上對於HTML頁面的操作只能應用於form

 

headless是什么呢,可以簡單理解為后台操作。如果做不到headless,那么你運行的時候其實還是需要打開一個瀏覽器,只不過腳本會操作瀏覽器。

所以我們可以看到,做不到headless的話,不僅看起來非常低端(想象一下電腦屏幕上開着一個瀏覽器,然后自動輸入東西,而你之只能傻坐着什么都不能做),並且使用起來很不方便,比如在沒有圖形界面的系統就無法使用了。

 

只能應用於form是什么意思呢,我們拿jQuery來對比吧。jQuery可以選擇所有HTML里出現的東西,但是只能應用於form就意味着只能操作表單,對於其他元素就無能為力了。我不知道為什么會出現這種情況,可能是插件底層有一些限制吧,反正大部分插件都只能操作form。

 

給大家提供三個方案以供參考吧:

 

  • Ghost.py 支持headless並且可以操作所有元素,甚至可以運行js,你就知道這個有多強大了。唯一缺點——依賴PyQt或者PySide,你裝一下這倆貨就知道了,簡直折磨死人。所以如果你不想折騰的話,還是不要用這個了。
  • splinter  半支持headless——splinter默認是不支持headless,但是可以在使用zope的一個插件的前提下headless,因為我用的是默認的,所以具體怎么做到headless沒有研究,感興趣的自己搞搞吧。不過估計八成不給力。。。splinter的功能同樣很強大,可以操作所有元素。
  • mechanize  支持headless但是只能操作form

 

大概就是這樣。

 

三、Just Do It

重復一下我們的思路:

登錄——投票

因為我決定采用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

搞定。

 

五、總結

我們使用了:

  • mechanize  模擬用戶操作  模擬POST請求
  • firebug  獲取POST數據格式
  • lxml  解析HTML內容

 

我們實現了:

  • 自動登錄
  • 自動投票
  • 輸出票數

 

好了,下面只要把這個腳本放到服務器上,並且設置一下每天運行就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM