我抓網頁資料的方法(使用 Ruby)

在網際網路(尤其是 WWW)發達的現在,我們會從很多 Web 上搜尋想要的資訊或資料,但有時候該 Web 的設計並不友善,沒有很直接的方法取出我們想要得到的資料,或是也沒有提供 RSS 之類的東西,這時就會想要自己寫個程式來抓網頁的資料了。

抓網頁的資料並不困難,尤其是各個語言都有 HTTP 相關的 framework 或是 toolkit,這裡我以抓取中央氣象局發佈的「中央氣象局台灣各地1週天氣預報」作為例子,因為這個網頁沒有提供 RSS(當然可能其它天氣網站會有 XD),所以我想當我的 script 一執行之後,就能從這個網頁擷取出我想要的一週天氣預報。

Ruby 裡有個很好用的 module 叫作 open-uri,這個 module 提供了一個 open 的函式,可以幫你打開 URI 的內容,並且傳回一個 File 物件,如下:
[code lang="ruby"]
require 'open-uri'
require 'iconv'

ic = Iconv.new('UTF-8', 'BIG5') # 因為這個網頁是用 big5 編碼,我要轉成 UTF-8 編碼
page = open('http://www.cwb.gov.tw/V5/forecast/taiwan/week.htm')
data = ic.iconv(page.read)
puts data
[/code]

執行這段 script ,你會看到像這樣的輸出:
[code lang="xml"]






台灣各地1週天氣預報


......略
[/code]

所以我們可以用 data = ic.iconv(page.read) 把這份網頁的 HTML 全部放進 data 這個變數中,再來就是要分析一下這份網頁的 HTML 來作一些字串處理了。

這個網頁每天都會更新(那還不提供一下 RSS),資料都是當天起未來一週的資料,分析一下這個網頁的 HTML ,我們可以看得出來它是用表格(

)來排版的,而且每一個地區是一列(
)來排,這樣事情就單純多了,比方說我只想抓出台北市未來一週的資料,我只要看這一段就可以了:
[code lang="xml"]

[/code]
所以我們可以寫成這樣:
[code lang="ruby"]
require 'open-uri'
require 'iconv'

ic = Iconv.new('UTF-8', 'BIG5')

page = open('http://www.cwb.gov.tw/V5/forecast/taiwan/week.htm')
data = ic.iconv(page.read)
start = false
data.each do |line|
if start && line =~ /
break;
end

if start
content = line.scan(/title="(.*)">
(.*?) puts content[0] + ", " + content[1]
end

if line =~ /台北市/
start = true
end
end
[/code]
data.each 的用意在於讀進來的 HTML 是一行一行以 array 的型態存好的,所以這裡用一個迴圈一行一行去掃這個網頁的資料,然後當發現這一行有包含「台北市」字串時,把 start 變數設成 true,表示接下來的每一行都是我們要擷取的內容。

因為我想要取得 imgtitle 的內容,表示天氣的狀況,以及在後面的氣溫分佈,所以我用了 regular expression 取得這兩筆資料的內容,它就會分別放在 content[0]content[1] 裡面了,剩下就是整理成好看的輸出格式而已了,這裡就不多作介紹,在此收工。

如果哪天氣象局改了網頁的格式,那「字串處理」的工作就要再修改囉 :P

  • Crazylion

    不提供rss是上面大頭的意思(也就是所謂的政策…) :P
    不清楚他們在堅持些什麼…orz

  • http://blog.ericsk.org/ ericsk

    想不到居然有來自 CWB 的朋友…XD

  • http://blog.rssconnect.net/ moming2k

    如果是做找網頁,應該用 scrubyt 會比較方便吧,該網站有一些例子,只要你提供了網址和一些關鍵字,它就會做比對,找到適合的方法來找取相關的資料

    http://scrubyt.org/

  • http://blog.ericsk.org/ ericsk

    moming2k:
    其實我平常用到這招的時候是在幹相簿網站圖的時候 XD

  • http://twitter.com/EricX Eric (エリック)

    其實中央氣象局有提供 RSS 啊~
    首頁 → 多元服務 → RSS
    不過它的 RSS 裡面只放了一個 link ,一點屁用也沒有……。

  • pipi

    你是怎么让ruby识别中文的字符串?(即“台北市”这个字符串)

  • http://blog.ericsk.org/ ericsk

    [quote comment=""]你是怎么让ruby识别中文的字符串?(即“台北市”这个字符串)[/quote]
    直接寫在 code 裡的…XD 所以程式碼檔案要注意編碼

  • pipi

    [quote comment="14349"]
    直接寫在 code 裡的…XD 所以程式碼檔案要注意編碼[/quote]

    谢谢 XD

  • pipi

    还有好像用了iconv后,多行字符就变成单行了。
    each也变成对整个字符串的处理了

  • http://blog.ericsk.org/ ericsk

    @pipi
    唔, 我用的時候沒有這種問題耶 *汗*

  • wenyen

    您好~
    如果網頁需要認證,需要帳號密碼的話,應該要怎麼改比較好,謝謝

台北市 多雲午後短暫雷陣雨
26~33
多雲午後短暫雷陣雨
26~34
多雲轉陰陣雨
25~32
陰陣雨
24~28
陰陣雨
24~28
多雲午後短暫雷陣雨
25~31
多雲午後短暫雷陣雨
25~32