在網際網路(尤其是 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”]
……略
[/code]
所以我們可以用
data = ic.iconv(page.read)
把這份網頁的 HTML 全部放進 data
這個變數中,再來就是要分析一下這份網頁的 HTML 來作一些字串處理了。這個網頁每天都會更新(那還不提供一下 RSS),資料都是當天起未來一週的資料,分析一下這個網頁的 HTML ,我們可以看得出來它是用表格(
)來排版的,而且每一個地區是一列(
)來排,這樣事情就單純多了,比方說我只想抓出台北市未來一週的資料,我只要看這一段就可以了:
[code lang=”xml”]
台北市

26~33

26~34

25~32

24~28

24~28

25~31

25~32
[/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 =~ /
(.*?))[0]
puts content[0] + ", " + content[1]
end
if line =~ /台北市/
start = true
end
end
[/code]
data.each
的用意在於讀進來的 HTML 是一行一行以 array 的型態存好的,所以這裡用一個迴圈一行一行去掃這個網頁的資料,然後當發現這一行有包含「台北市」字串時,把 start
變數設成 true
,表示接下來的每一行都是我們要擷取的內容。
因為我想要取得 img
裡 title
的內容,表示天氣的狀況,以及在後面的氣溫分佈,所以我用了 regular expression 取得這兩筆資料的內容,它就會分別放在 content[0]
及 content[1]
裡面了,剩下就是整理成好看的輸出格式而已了,這裡就不多作介紹,在此收工。
如果哪天氣象局改了網頁的格式,那「字串處理」的工作就要再修改囉 😛
11 comments
Comments are closed.
不提供rss是上面大頭的意思(也就是所謂的政策…) 😛
不清楚他們在堅持些什麼…orz
想不到居然有來自 CWB 的朋友…XD
如果是做找網頁,應該用 scrubyt 會比較方便吧,該網站有一些例子,只要你提供了網址和一些關鍵字,它就會做比對,找到適合的方法來找取相關的資料
http://scrubyt.org/
moming2k:
其實我平常用到這招的時候是在幹相簿網站圖的時候 XD
其實中央氣象局有提供 RSS 啊~
首頁 → 多元服務 → RSS
不過它的 RSS 裡面只放了一個 link ,一點屁用也沒有……。
你是怎么让ruby识别中文的字符串?(即“台北市”这个字符串)
[quote comment=””]你是怎么让ruby识别中文的字符串?(即“台北市”这个字符串)[/quote]
直接寫在 code 裡的…XD 所以程式碼檔案要注意編碼
[quote comment=”14349″]
直接寫在 code 裡的…XD 所以程式碼檔案要注意編碼[/quote]
谢谢 XD
还有好像用了iconv后,多行字符就变成单行了。
each也变成对整个字符串的处理了
@pipi
唔, 我用的時候沒有這種問題耶 *汗*
您好~
如果網頁需要認證,需要帳號密碼的話,應該要怎麼改比較好,謝謝