現在是Web的時代,所有資料都可以在網路上取得,所以能夠自動取用Web資料的Spider程式(Web Robot)相當實用。

開發Spider的過程,需要運用各種Heuristic(摸索體驗)的作法:嘗試你的想法,修正預期以外的錯誤(錯誤通常相當多),一再重複進行,直到Spider可行為止。所以寫Spider程式時,是需要一點點耐心的。

一般的狀況下,Spider程式會先取回一個網頁,從此網頁取出所有「後續的連結」,然後繼續取回這些連結的網頁。網頁的組織方式如果是線性的(例如:每個網頁都有「前一筆資料」與「下一筆資料」的超連結),那麼超連結就不會重複,所以就不需要判斷這些連結有無重複。但組織方式只要不是線性的,都需要判斷網頁超連結有無重複。

你以為HTTP狀態碼(status code)是代表正常的200,就表示能夠順利取回網頁嗎?那可不一定,我發現有些伺服器會限制同時上線的最大連線數目,超出限制,就會送出「伺服器忙碌中」的HTML內容,但HTTP狀態碼(status code)居然還是使用代表正常的200。會不會遇到這種狀況?何時會遇到?很難說得準。如果你想預防這種問題,可以從判斷取回內容的checksum有無重複來下手。

為了防堵Spider,有些網站會限制來自同一個IP的請求頻率。當頻率超過限制,就會對此IP連線請求置之不理,客戶端最後會Timeout,連線失敗。所以,當你遇到連線失敗的狀況,請先更換成新的IP,以確定伺服器是否真的掛了,或者只是你的IP被封鎖了。如果確定IP被封鎖,你可以採用兩種策略:(1)隨時動態更換IP;或者(2)調節Spider的請求頻率。

如果你的電腦上同時有兩三個IP,你當然可以在這些IP之間輪替更換,但這樣其實幫助不大,因為IP被封鎖通常會維持好一段時間,輪完第三個IP之後,恐怕第一個IP也還沒被伺服器從黑名單中去除。如果你要動態更換IP,最好改用ADSL撥接網路,因為ISP業者具有大量的IP,會分配到和之前相同的IP機率很低。一旦你發現目前的IP被封鎖,便可以立刻呼叫相關的API將網路斷線並重新撥接,取得新的IP繼續執行。

如果你不知道該如何呼叫撥接API,或者根本沒有撥接網路,那麼你只好降低Spider發出請求的頻率。頻率太低,取得資料的速度太慢;頻率太高,很快就會被伺服器封鎖。如何調整出一個理想值,通常需要測試好一陣子。

對網頁資料的加工處理方式,通常是先將超連結更新到本地檔案,再萃取重要資料另外儲存於他處。更新超連結其實滿容易的,不容易出錯,但「萃取重要資料」就可能會遇到相當多問題,值得進一步探討。

透過Spider程式取回的網頁資料,通常需要經過加工處理。因此建議你不要一邊取回網頁,一邊加工處理,最好等網頁全部取回之後,再進行資料萃取。為了避免URL名稱不適合用來當成檔名(例如Windows中不能用「con」當檔名),我習慣使用數字序號當檔名,然後再建立一個URL和數字序號的對照表(可以加上超連結,以方便取用)。

在萃取資料前,你需要先花一點時間研究出這些網頁的HTML樣板,接著你就可以取出特定tag的element,或者「以特定字串為識別」的資料。我的經驗是,光看幾個HTML內容,仍不足以推測出完整的樣板,有些狀況可能是一百個或一千個網頁才發生一次(更不用說還有一些是網站本身建構時的疏失)。因此,最好能先寫一個程式掃描所有取回的網頁,證實你構想中的HTML樣板是正確的,然後才開始進行資料萃取。

在研究網頁樣板時,如果發現網頁內出現JavaScript,你應該判斷是否可以對它置之不理。因為許多網頁的JavaScript程式碼是用來處理網頁互動,和我們所關心的網頁內容無關,可以不予理會。但如果遇到和資料相關的JavaScript程式碼(會產生HTTP請求),就必須特別注意。

你可以動用外部的JavaScript Engine(例如Rhino)來處理JavaScript程式碼,但是對Spider程式來說,大多數的時候,其實沒有必要這麼做。你可以先閱讀理解這些JavaScript程式碼,知道這段程式的目的是發出什麼HTTP請求,就可以讓Spider自行模擬這樣的HTTP請求。

當你的電腦跑著Spider程式時,只要有預期以外的事情發生(例如格式不對、網站不通),就需要人的介入。尤其前幾個小時是重要的觀察期,這個時候最好乖乖地坐在電腦前,當出狀況時,Spider可以發出聲音提醒我們進行處理。

我一直覺得,開發Spider是相當實用、有趣、需要技巧的,且Spider程式通常不大,所以很適合當作「下班後的自我挑戰」,或者老師派給學生當作業。如果你沒寫過Spider程式,我建議你馬上試試看。

作者簡介:
蔡學鏞-技術顧問
清華大學資訊工程碩士,曾任華碩集團軟體工程師、元智大學資訊系講師、美商歐萊禮出版社技術編輯、臺灣微軟特約專欄作家。

熱門新聞

Advertisement