驗證碼識別與自動灌水

近來,一個朋友請我幫他在某個網站投票。投票程序設立了驗證碼,並且限制每個IP每天只能投一票。我是在debian sarge 3.1下面通過ADSL撥號上網的,IP限制可以通過重新撥號輕鬆搞定。網上有人說使用代理也可以,但是我找了很久,發現網上列出的大部分代理服務器都已經無法訪問。好了,下面的問題主要就是識別驗證碼和自動投票了。

網上有很多關於驗證碼識別的方法和思路,不過大部分都是在windows下面運行的。在linux下面有一個很有名的圖片處理軟件叫imagemagick。這個軟件支持非常多的圖片格式已經更多的圖片處理方法,請看這裏的圖片效果:

我的思路是,首先找到含有驗證碼的圖片,把背景、雜色、條紋等干擾因素去掉,並把圖片轉化爲黑白象素,以便於處理。然後分析圖片上每個文字的位置,精確的把整個圖片分割成包含每個文字的小圖片。我關注的這個投票網站上的驗證碼是有0到9這十個數字構成了,我就用GIMP——是的,GIMP是linux下面不可多得的圖像處理軟件——打開驗證碼圖片,把十個數字一一截取下來,並且分別命名爲0.jpg到9.jpg。截取的時候一定要注意,每個文字最好留一點邊框,並且在截取後的小圖片上要居中,這樣更利於排除干擾,提高識別率。爲了提高準確率,我把用GIMP把驗證碼放大到1600倍以後對每個象素進行處理。等要識別圖片上驗證碼的時候,使用相同的位置截取圖片上的文字,然後和剛纔保存的十個小圖片一一對比,與之差異最小的那個圖片的序號就是該位置上的文字了。ImageMagick在命令行下面運行,支持MAE,MSE,PSE,PSNR,RMSE等多種比較方式。根據圖片中干擾的情況,選擇一種最合適的方式,或者用多種方式逐步處理以後進行比較,驗證碼就可以輕鬆識別了。放大1600倍獲取準確位置

至於識別驗證碼後進行自動灌水就很簡單了。linux下面有一個更強大的工具curl,它可以通過HTTP,FTP,HTTPS等多種方式訪問遠程服務器,自動上傳或下載數據。首先用curl查看其HTTP頭信息

* About to connect() to xxxx.com port 80
* Trying xxx.xxx.xxx.xxx... * connected
* Connected to xxxx.com (xxx.xxx.xxx.xxx) port 80
> GET / HTTP/1.1
User-Agent: curl/7.13.1 (debian-linux-gnu) libcurl/7.13.1 OpenSSL/0.9.7e zlib/1.2.2.2 libidn/0.5.13
Host: xxxx.com
Pragma: no-cache
Accept: */*

< HTTP/1.1 302 Moved Temporarily
< Via: 1.1 PROXY
< Connection: Keep-Alive
< Proxy-Connection: Keep-Alive
< Transfer-Encoding: chunked
< Date: Tue, 04 Jul 2006 05:55:16 GMT
< Location: http://xxxx.com/queryVote.do?type=netvotes&Group=1
< Content-Type: text/html;charset=gb2312
< Server: WebLogic Server 8.1 SP2 Fri Dec 5 15:01:51 PST 2003 316284
< Set-Cookie: JSESSIONID=EqCEDyCC2JGex2sLoT231l6NP38OStZaFf9zLSHUxb2MxrqLBE1i!1559900188; path=/

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>xxxx</title>
</head>
<body bgcolor="#FFFFFF">
...
</body>
</html>

</html>
* Connection #0 to host xxxx.com left intact
* Closing connection #0

從第19行中可以看出,改站點使用了JSESSION這個cookie。查看投票頁面的源代碼,我發現投票時使用了POST方法,有五個表單項目需要提交。我把這些都記錄下來,構成一個POST字符串就可以了。

上面所說的很羅嗦,還是看我寫的代碼吧(源網址被改成了xxxx.com)





parse

=
=
convert .jpeg -crop 9x13++ -a.jpeg
convert .jpeg -crop 9x13++ -b.jpeg
convert .jpeg -crop 9x13++ -c.jpeg
convert .jpeg -crop 9x13++ -d.jpeg
pic a,b,c,d

=
=
num ,,,,,,,,

=
=

=
=


=

-fr -abcd.jpeg




=
iii++

pon dsl-provider /dev/null curl.log

curl /
cookie /
/
/
http://xxxx.com/MakeEXPWD code.jpeg
=
curl /
cookie /
/
/
/
/
/
/
http://xxxx.com/VoteForm.jsp?= /
/
http://xxxx.com/vote.

=



-fr code.jpeg
poff dsl-provider /dev/null curl.log





代碼中第三行表示把整個程序的輸出重定向到文件,可以用於無人值守的批量運行時。如果程序中有很多輸入,這樣做就可以不必逐一對每個輸出的重定向了。
下面是parse函數,用於對獲取到的圖片進行識別。分析時,首先截取圖片的預定區域,並與準備好的小圖片逐一比較,取參數中的最值,其對應的小圖片就是該位置的文字了。比較時使用到了浮點運算,這是bash的弱勢所在,所以要用bc進行高精度計算。比較兩個圖片所用的compare命令支持很複雜的參數和諸如MAE,MSE,PSE,PSNR,RMSE等多種方式,這裏只是用了其中一種。
函數之後就是程序的主循環部分。每次循環時都把adsl斷線並重新撥號。從撥號成功到數據能夠正常傳輸之間可能有一段延誤時間,所以要sleep一會兒。
下面的第一個curl有兩個作用:首先,它從目標網站獲取含有驗證碼的圖片;另外,它還取得了當前連接的cookie,並且初始化服務器端的session。其中的-j參數表示每次撥號都拋棄以前的cookie。
第二個curl使用了剛纔取得的cookie,使用post方法向目標站點提交投票數據。其中的name是投票人的姓名,投票程序規定相同的名字只能投一票,所以我乾脆把用時間來表示了。在投票以後的返回頁面中檢查“投票成功”四個字,如果有則表示本次投票已成功,計數器加一。第55行的$?就表示上一個命令的返回值:找到關鍵詞時返回0。
每次操作結束以後都要把臨時文件刪除,同時更新狀態行。echo命令加上-n參數表示輸出信息後不換行;再加上一個控制字符/r,可以不斷更新當前的提示行,而不是一行一行的輸出程序運行結果,這樣看起來更簡潔一些。
發佈了59 篇原創文章 · 獲贊 0 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章