天天看點

論壇灌水機(續)

大概在2年零兩個月前,我寫過一個論壇灌水機,前幾天,因為朋友要網絡投票,又拿出來用了一次,改了下配置檔案,又可以當投票機用了。

由于工作的關系,現在在UNIX上做開發了,我嘗試了用UNIX重寫了一個投票機,深深的體會到,什麼叫“一行shell相當于1萬行C代碼了”。UNIX天生就是為程式員服務,來幫助他們完成看似不可能的任務的。

下面我以我重寫的這個投票機為例,來闡述下UNIX的做事風格。

一個投票機,或曰灌水機,需要具備這麼些特性:get/post、資料生成、流程控制、并發支援、代理支援、驗證碼識别等等。這些特性基本上是越往後越難的,看看UNIX是怎麼用簡單的方式來實作他們的:

get/post

UINX提倡用短小精悍的小程式組合來完成複雜的任務,對于使用HTTP協定通路網絡,沒有什麼比wget更合用的啦。有UNIX環境的可以直接在shell下開始嘗試,隻有windows的也可以裝一個cygwin的模拟UNIX環境來試驗。

在提示符下直接輸入wget,回車

$ wget

wget: missing URL

Usage: wget [OPTION]... [URL]...

Try `wget --help' for more options.

它提示你缺少URL參數,用--help來獲得更多資訊,注意UNIX絕大多數指令都可以用--help來獲得幫助,而不是dos傳統的/?。

如果你輸入wget --help後,你會得到所有支援的參數清單。這些參數清單對于不怎麼會得人來說,可能還是太簡略了,輸入man wget可以獲得更加詳細的解釋及示例。許多UNIX程式都可以用man加上指令名來得到詳細的使用說明。

man的簡要使用如下:

用上下左右光标鍵浏覽,q鍵退出。g到首行,G到末行,/開始查找,例如/proxy再回車,表示查找含有proxy處,n向下查找下一個,N向上查找下一個。

不看幫助,讓我們來猜想最簡單的用法,沒錯,就是這樣

$wget www.csdn.net

--22:10:01--  http://www.csdn.net/

           => `index.html'

Resolving www.csdn.net... 211.100.21.179

Connecting to www.csdn.net|211.100.21.179|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 128,038 (125K) [text/html]

100%[====================================>] 128,038        4.29K/s    ETA 00:00

22:10:46 (2.90 KB/s) - `index.html' saved [128038/128038]

這是不帶選項的用法,網頁自動儲存到檔案,詳細過程顯示在終端上。好了,基本的get完成了,算算C代碼要幾行?

資料生成

對于灌水來說,上節自然是不夠用的,至少也需要發送POST資料的功能吧?

這個簡單,輸入man wget,搜尋post,就能找到答案,這裡給個例子:

$wget www.xxx.com --post-data='a=1&b=2'

這裡有個地方需要注意的就是,對于指令行中有&的,一定要用''把它引起來,否則會被shell解釋成在背景運作,如上面的例子,如果沒有'',那麼shell認為是在背景執行"wget www.xxx.com --post-data=a=1",然後又執行b=2這樣一個指令。

可以傳遞post資料了,讀者一定還不滿意,因為如果想讓資料變化,例如a要從1變化到1000,總不能手工輸入吧?

流程控制

好了,這要用到基本的shell程式設計了。我這裡就簡要的給出例子:

編輯一個shell檔案start.sh,内容如下

#! /bin/sh

counter=0

while [ $counter -lt $1 ]

do

        counter=`expr $counter + 1`

        wget "www.xxx.com" "--post-data=a=$counter&b=2"

done

儲存後,在shell下執行chmod +x start.sh, 使這個腳本可執行

然後執行./start.sh 1000,就達到了我們的目的。

(這裡沒什麼好解釋的,我也不喜歡shell的這種循環、比較與指派的文法,不過為了它提供的其他好處,隻好忍忍啦,畢竟任何事物都不是完美的,需要參考shell文法時可以查一本書:好像叫<<UNIX和LINUX shell程式設計指南>>,有電子版)

也許讀者看到這裡,還是覺得UNIX沒什麼好的,就剛才這些例子來說,無非是有了一個用C寫好了的wget程式,我用socket或者用WININET來寫,從功能上來說,哪樣都不少,而且寫熟練了,速度也不慢呀,那我們來看看

并發支援

UNIX重來都不考慮多線程這種煩人的東西,諸位把多線程的東西搞清楚了,又調試出了幾個多線程的Bug,估計頭上的白發沒少生。UNIX下把上一節那個腳本在背景多運作幾次,就實作并發了,簡單吧,煩人的事情就該交給作業系統去做,而不是在windows中提倡的去搞一個複雜無比的多線程程式。

代理支援

我知道上面的話一定不能讓人心服,現在我舉這個例子,我覺得能征服至少一半讀者。考慮這樣的任務,你的論壇會限制你灌水的IP,同一個IP有發帖間隔限制,或者你要投票的位址限制每個IP隻能投一票,你怎麼辦,找代理。那麼你覺得需要多長時間能把這個功能完成呢?例如說從www.proxycn.com中取大量的代理位址,1天?1000行代碼?有興趣的讀者可以先不往下看,看看在windows的思維方式下,能否在五分鐘内完成這個任務。

我在剛嘗試這件事時,我也沒考慮要多快,但是我還真就五分鐘内做成了。

第一分鐘,我用浏覽器打開www.proxycn.com,找到左下角的代理綜合搜尋,類型選HTTP,狀态選活動,點選搜尋按鈕,出來3149個結果,共63頁,就是它們了。

第二分鐘,我複制第2頁的快捷方式作為wget的參數

$wget -O result 'http://www.proxycn.com/proxysearch.php?action=proxys&searchsubmit=yes&address=&port=&AddDateBefore=&AddDateAfter=&status=1'/

'&isedu=&type=HTTP&type2=&location=&page=2'

很快,第二頁被下載下傳下來存入result檔案了。

我開始嘗試

$cat result

輸出了整個檔案的内容,翻動一下螢幕,發現了一個好東西onDblClick="clip('219.165.115.186:3128'),運氣還不錯。

接着

$cat result | grep /d{1.3}

無結果

$cat result | grep '/d{1,3}'

無結果

$grep --help | grep perl

 -P, --perl-regexp         PATTERN is a Perl regular expression

$cat result | grep -P '/d{1,3}'

好了,一堆結果

$ cat result | grep -P '/d{1,3}/./d{1,3}'

這下結果很靠譜,把它比對完

$ cat result | grep -P '/d{1,3}/./d{1,3}/./d{1,3}/./d{1,3}:/d{2,5}'

這下比對了整個IP位址加端口了,但是grep是輸出整行的呀,有多餘的輸出,

第三分鐘

$grep --help

翻看Output control那一部分,找到一行

 -o, --only-matching       show only the part of a line matching PATTERN

試一下

$ cat result | grep -P '/d{1,3}/./d{1,3}/./d{1,3}/./d{1,3}:/d{2,5}' -o

203.160.1.47:554

66.240.123.59:3128

221.112.144.13:8080

165.228.129.10:3128

203.198.69.124:3128

203.160.1.44:554

125.247.118.226:3128

203.160.1.43:554

203.160.1.52:554

195.55.133.76:8080

202.146.67.238:8080

...成功了,現在把指令組合一下

第四分鐘

編輯proxy.sh檔案如下

#! /bin/sh

counter=0

while [ $counter -lt $1 ]

do

        counter=`expr $counter + 1`

        wget -O - "http://www.proxycn.com/proxysearch.php?action=proxys&searchsu

bmit=yes&address=&port=&AddDateBefore=&AddDateAfter=&status=1&isedu=&type=HTTP&t

ype2=&location=&page=$counter" 2>/dev/null | grep -P '/d{1,3}/./d{1,3}/./d{1,3}/

./d{1,3}:/d{2,5}' -o

done

然後執行chmod +x proxy.sh

試一下

$./proxy.sh 1

沒有問題,現在正式取了

第五分鐘

$ ./proxy.sh 63 > result &

[1] 1680

這表示任務在背景執行了,

我可以用這個指令來觀察結果

$ tail -f result

大約過了一分鐘,背景的任務執行完了,我統計一下行數

$ wc -l result

1749 result

還真準,剛好3149個結果