在網際網路(尤其是 WWW)發達的現在,我們會從很多 Web 上搜尋想要的資訊或資料,但有時候該 Web 的設計並不友善,沒有很直接的方法取出我們想要得到的資料,或是也沒有提供 RSS 之類的東西,這時就會想要自己寫個程式來抓網頁的資料了。
抓網頁的資料並不困難,尤其是各個語言都有 HTTP 相關的 framework 或是 toolkit,這裡我以抓取中央氣象局發佈的「中央氣象局台灣各地1週天氣預報」作為例子,因為這個網頁沒有提供 RSS(當然可能其它天氣網站會有 XD),所以我想當我的 script 一執行之後,就能從這個網頁擷取出我想要的一週天氣預報。
Ruby 裡有個很好用的 module 叫作 open-uri,這個 module 提供了一個 open 的函式,可以幫你打開 URI 的內容,並且傳回一個 File 物件,如下:
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
執行這段 script ,你會看到像這樣的輸出:
<HTML lang="zh-TW"> <HEAD> <meta http-equiv="Content-Type" content="text/html; charset=big5"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <meta http-equiv="Expires" content="Tue, 20 Aug 1996 14:25:27 GMT"> <TITLE> 台灣各地1週天氣預報 </TITLE> <link rel="stylesheet" href="/V5/css/global.css"> </HEAD> ......略
所以我們可以用 data = ic.iconv(page.read) 把這份網頁的 HTML 全部放進 data 這個變數中,再來就是要分析一下這份網頁的 HTML 來作一些字串處理了。
這個網頁每天都會更新(那還不提供一下 RSS),資料都是當天起未來一週的資料,分析一下這個網頁的 HTML ,我們可以看得出來它是用表格(<table>)來排版的,而且每一個地區是一列(<tr>)來排,這樣事情就單純多了,比方說我只想抓出台北市未來一週的資料,我只要看這一段就可以了:
<tr bgcolor=white><th bgcolor=#f5f5f5>台北市</th> <td align=center valign=middle><img src="/V5/symbol/symbol09.gif" alt="多雲午後短暫雷陣雨" title="多雲午後短暫雷陣雨"><BR>26~33</td> <td align=center valign=middle><img src="/V5/symbol/symbol09.gif" alt="多雲午後短暫雷陣雨" title="多雲午後短暫雷陣雨"><BR>26~34</td> <td align=center valign=middle><img src="/V5/symbol/symbol06.gif" alt="多雲轉陰陣雨" title="多雲轉陰陣雨"><BR>25~32</td> <td align=center valign=middle><img src="/V5/symbol/symbol06.gif" alt="陰陣雨" title="陰陣雨"><BR>24~28</td> <td align=center valign=middle><img src="/V5/symbol/symbol06.gif" alt="陰陣雨" title="陰陣雨"><BR>24~28</td> <td align=center valign=middle><img src="/V5/symbol/symbol09.gif" alt="多雲午後短暫雷陣雨" title="多雲午後短暫雷陣雨"><BR>25~31</td> <td align=center valign=middle><img src="/V5/symbol/symbol09.gif" alt="多雲午後短暫雷陣雨" title="多雲午後短暫雷陣雨"><BR>25~32</td></tr>
所以我們可以寫成這樣:
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 =~ /<tr.*/ break; end if start content = line.scan(/title="(.*)"><BR>(.*?)</)[0] puts content[0] + ", " + content[1] end if line =~ /台北市/ start = true end end
data.each 的用意在於讀進來的 HTML 是一行一行以 array 的型態存好的,所以這裡用一個迴圈一行一行去掃這個網頁的資料,然後當發現這一行有包含「台北市」字串時,把 start 變數設成 true,表示接下來的每一行都是我們要擷取的內容。
因為我想要取得 img 裡 title 的內容,表示天氣的狀況,以及在後面的氣溫分佈,所以我用了 regular expression 取得這兩筆資料的內容,它就會分別放在 content[0] 及 content[1] 裡面了,剩下就是整理成好看的輸出格式而已了,這裡就不多作介紹,在此收工。
如果哪天氣象局改了網頁的格式,那「字串處理」的工作就要再修改囉 :P
歷史上的今天
- 畢業同意書 - 2006
- Windows 下安裝設定 Apache2 + PHP5 + mod_ssl - 2006
- pthread 開的玩笑 - 2005



不提供rss是上面大頭的意思(也就是所謂的政策…) :P
不清楚他們在堅持些什麼…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
唔, 我用的時候沒有這種問題耶 *汗*
您好~
如果網頁需要認證,需要帳號密碼的話,應該要怎麼改比較好,謝謝