2009年1月23日

Java輕鬆玩 - 網頁資料擷取以FunP哈部落最愛為例

Java輕鬆玩(Java for Fun)」 系列文章,想要讓一些有電腦基礎、但不太會寫程式的朋友,也能夠在喝杯咖啡的午後時光,悠閒地利用Java創作電腦程式。寫程式是件有趣的事,就像小時候玩的積木,能夠訓練邏輯思考及培養創造力,也純粹就是為了好玩而已。有趣的前提必須是「為自己的樂趣寫程式(Coding for Fun)」,自己能夠做出工具解決問題,將會有充滿成就感的快樂。我們假設你每天都能有30分鐘的時間可以"玩樂",先花個10分鐘把我們的教學短文看 完,跟著完成設定及範例程式碼,接著就能用20分鐘把它重新組合,用您獨特的想法創作出自己的程式。

關於本篇《網頁資料擷取以FunP為例》
難易度:★★☆☆☆ (入門)
內容涵蓋:網頁存取、正規表示式
背景需求:電腦已經安裝JDK與Groovy,並且閱讀過第一課的教學。

個案分析(Case Study)
有一天,你正在「FunP哈部落」尋找有趣的新部落格,發現在許多頁列表中,每個都很想「加入最愛」。在你未曾閱讀過《Java輕鬆玩》的時候,你會一個接一個去點擊「最愛」按鈕,如果有一百個,天啊!你要點一百次。下方的「最愛」,您就點點看吧:D

當你開始接受「Java輕鬆玩」告訴你的『偷懶至上』觀念,你一定知道Groovy可以讓這件事情變得更輕鬆,其實在認識語法就已經提供相當接近的範例,在這篇教學中,將更清楚地告訴你該怎麼做。

別想得太複雜
你可以為了證明自己的程式設計功力,做出一個全自動的「加入最愛」小程式,它幫你完全模擬瀏覽器的操作行為,甚至還可以…。
如果你還記得我們講過的原則,應該會很清楚這種小事情,沒必要寫超過十行程式碼。

讓一切更簡單吧
在哈部落選擇一個部落格列表,例如「熱門部落格」,在最愛按鈕上使用右鍵選單的「複製鍊結網址」,就可以知道「最愛」點下去之後會執行什麼動作,範例如下(數字的部份是部落格代碼)。
javascript:addFavoBlog('26849',%20'tagFavoBlog(26849)');
打開網頁的原始碼,用addFaveBlog尋找相關段落,搜尋結果的範例如下。
<a id="bButton_26849" href="javascript:addFavoBlog('26849', 'tagFavoBlog(26849)');" class="buttonPlugin" style="background-position:0 -200px;"><img style="width:56px;height:24px;background-position:0px -200px;" src="/base/images/tb.gif"/></a>
因此我們可以從這個段落推斷,只要執行以下這段語法,就會完成加入最愛的動作。
javascript:addFavoBlog('26849', 'tagFavoBlog(26849)');
回到哈部落的列表網頁,在網址列貼上剛找到的語法,按「Enter」測試一下,如果結果正確,將會看到畫面中有個貼紙的「最愛」變成「我最愛」。


定義程式功能需求
從上面的小測試,我們得到一個結論,就是只要將某個哈部落網址的HTML原始碼從頭到尾掃描一遍,找出每個出現的addFavoBlog語法,重新組合起來,再拿到瀏覽器的網址列去貼上,就可以簡單地解決個案中提到的問題。

玩玩看以下的程式碼,它可以將網址(粗體字部份)的HTML原始碼下載,然後用println逐行顯示在螢幕上。
url = new URL("http://funp.com/blogs/list.php")
conn = url.openConnection()
conn.setRequestProperty('User-Agent', 'Mozilla/5.0')
conn.inputStream.eachLine 'UTF-8', {
  println it
}
其中
conn.setRequestProperty讓我們可以自訂User-Agent的HTTP表頭,用來讓網站伺服器以為我們用的瀏覽器是Mozilla,如果不加上這一行,很可能被拒絕回應。雖然可以偽裝成正常的瀏覽器,但請不要拿來惡搞,否則會直接被列入黑名單。UTF-8則是則是指定網頁回傳結果的編碼,繁體中文網頁一般都是UTF-8與Big5兩種。
接著是加入正規表示法(Regular Expression,簡稱Regex),在Groovy使用Regex很容易,試試以下修改過的程式碼。
url = new URL("http://funp.com/blogs/list.php?time=&page=1")
conn = url.openConnection()
conn.setRequestProperty('User-Agent', 'Mozilla/5.0')
conn.inputStream.eachLine 'UTF-8', {
    (it =~ /addFavoBlog\(\'[0-9]+\',\ \'[^']+\'\);/).each {
        println it
    }
}
這個程式碼將所有addFavoBlog的語法找出來,粗體字的部份,可以比對HTML原始碼的每一行,是否出現我們指定的樣式(Pattern)「
addFavoBlog\(\'[0-9]+\',\ \'[^']+\'\);」,由於「'」、「(」、「 」等文字屬於Regex的特殊文字,所以必須加上倒斜線「\」,才會被當作一般文字處理,[0-9]+用來表示一段數字,而[^']+則表示除了「'」以外的文字皆可。用Regex我們可以輕鬆地描述一段有規則的文字,雖然其中某些內容會變動,但仍可以描述出來,得到的結果就是所有符合這個樣式的字串。
最後只要在加上三行修改,就完成這個小程式。
links = []
url = new URL("http://funp.com/blogs/list.php?time=&page=1")
conn = url.openConnection()
conn.setRequestProperty('User-Agent', 'Mozilla/5.0')
conn.inputStream.eachLine 'UTF-8', {
    (it =~ /addFavoBlog\(\'[0-9]+\',\ \'[^']+\'\);/).each {
        links << it
    }
}
println "javascript:"+links.join('')
陣列的教學中,我們已經講過[]用來宣告陣列,而<<則把新的元素放進去,這邊還使用join語法,把陣列中所有元素重新組合成字串,並在前面加上javascript:的文字。


將程式執行結果複製,貼到瀏覽器的網址列,按下「Enter」,如果結果正確,將會看到一堆部落格被設定為「最愛」。

* 本文發表於玩物尚誌,《Java輕鬆玩》系列文章的網址為「http://blog.lyhdev.com/search/label/JavaForFun」。版權所有,採用「創用CC授權」條款,歡迎非商業用途之分享與引用,並請保留作者或出處之標示。

5 則留言:

  1. 泥嘛幫幫忙…要玩就好好玩嘛…
    在外面趴趴造…居然還用3.5G來寫blog…
    厚厚~~~

    回覆刪除
  2. 哈…花蓮的公路實在太長了,好不容易才到台東,已經下午四點多,為了打發時間,一路上都在玩FunP。

    回覆刪除
  3. 你好,我的Funp粉絲的圖片都是直的..
    不像顯示的..要能並排.

    請問是何原因??

    回覆刪除
  4. 你好,我的Funp粉絲的圖片都是直的..
    不像顯示的..要能並排.

    請問是何原因??

    回覆刪除
  5. 哈…花蓮的公路實在太長了,好不容易才到台東,已經下午四點多,為了打發時間,一路上都在玩FunP。

    回覆刪除

lyhcode by lyhcode
歡迎轉載,請務必註明出處!