2010年8月25日 星期三

[Python] BBS Crawler 筆記

遙想台灣 BBS 的興起,大概是 1997 前後,至少我是那時候開始接觸的?記得那時可還用著 33.6Kb 的數據機,後來又升級到 56 Kb ,當年好像是我姐說想要玩 BBS ,然後家裡就多牽了一條電話線,就這樣開啟玩網路的年代。除了 BBS 外,還有 ICQ 等聊天軟體,另外我則是跟隨同學的腳步,常常去"史萊姆的第一個家"找些新奇的軟體,當然,還有 MIDI 音樂等等的。但最後,還是跌入 BBS 裡頭,在那個青澀的年代裡。


前陣子想到撈一下 BBS 裡頭的資料,於是挑選了 Python 這個語言,它有 telnetlib 跟 expect 可以用,就等於解決撈 BBS 的最大困難之處。


範例一,使用帳號密碼連到指定的站台:


import telnetlib

tn = telnetlib.Telnet( SITE_IP )
q = tn.expect(['使用者帳號:'] , 10)
tn.write( USER_ID + '\r' )
tn.expect(['密碼:'] , 10 )
tn.write( PASSWORD + '\r' )


其中 "使用者帳號:" 跟 "密碼:" 這是兩個很重要的 pattern ,並且依各家 BBS 的情況都不一樣。例如 PTT 就是"以 new 註冊:" 和 "請輸入您的密碼:" 等。上述的程式碼依序是連到 SITE_IP 這個位置的 BBS ,並且收集封包,等碰到第一個 pattern 時,才將 USER_ID + '\r' 的資料丟出去,然後繼續收集資料直到第二個 pattern 出現,在做對應的動作,此處是丟出密碼。


透過上述例子,我想應該就十分清楚了!由於 telnet 等同不間斷地丟資料過來,因此在判斷執行下一個動作前,要去等待某個關鍵 pattern ,以 BBS 之 24X80 的頁面,大部分就是挑換頁完後最後一個 pattern ,如最右下角等。


其實,這個筆記就只有一個範例就收工了 XD 老狗變不出新把戲啦!說說其它的技巧


def skip():
        q = tn.expect( ['pattern1', 'pattern2', 'pattern3'] , 10 )
        if q[0] == 0:
                tn.write('Key1' + "\r")
                skip()
        elif q[0] == 1:
                tn.write('Key2' + "\r")

                skip()

        elif q[0] == 2:

                return True


這個就是直到看到 pattern3 才離開,並且看到 pattern1 或 pattern2 則分別丟出指定的關鍵字出去。這種用法有時會需要。而為啥 expect 後面有接一個數字,那是因為避免收集不到 pattern 而一直卡在那邊,也就是 timeout 的使用,我覺得可以用在特殊情況,像是碰到 Server 掛掉沒丟完資料,或是自己耍蠢沒弄好全部的 pattern ,導致整個連線一直卡在那邊等到天荒地老啦。


其他常用的就是 Regular Expression 吧


import re

raw = re.sub( re_pattern_replace_space , '' , rawData )

out = re.findall( re_pattern_get_items,  raw )
for sub_item in out:
        pass

check = re.search( re_pattern_check , raw )
if check <> None :
        raw_pattern = check.group(0)


另外,還有丟Key 給 BBS Server 的部分,要去找一下對應表,例如上下左右是對應哪個 ASCII code ,我後來偷懶都用英文而已,例如離開可以用左鍵也可以按 q 鍵,如此等等


最後,提醒一下,有時候 BBS 為了效能的關係,每一次並不是吐一整個完整 24X80 的頁面,也就是並非每次都把整個頁面更新,有時候只更新部分資料,例如這次的頁面跟上次的只差一點點,因此 Server 就可能只丟出要更新的資料並利用控制碼去更新,所以,要判斷頁面是否已收集完畢,不一定能靠最右下角那個 pattern 喔!這是我實作上碰到一個很關鍵的地方。如此一來,整個 telnet crawler 就能完工囉!


其他資料請參考 Python - telnetlibPython - re,別忘了留意使用的 Python 版本是否合用喔。


沒有留言:

張貼留言