2012年12月30日

利用 Groovy + Selenium 輕鬆進行批次網頁擷圖(Web Page ScreenShot Capture)

Selenium 是用來自動化測試網頁的工具,它會實際開啟瀏覽器、載入網頁,並依照自定的流程進行網頁互動操作。

Selenium 提供 Web ScreenShot 功能,可以擷取網頁畫面,並包括可見區域及完整網頁兩種模式。網頁擷圖功能原本是用於測試,讓開發者可以幫 Web App 製作一個自動化測試腳本,當測試發生失敗(Exception)時,就可以利用擷圖功能自動捕捉網頁錯誤發生時的畫面。不過使用上有個限制:這個 ScreenShot 功能必須搭配 Firefox 瀏覽器。

由於 Selenium 是 Java-based 的測試工具,因此搭配 Groovy 就可以藉助 Selenium 的 ScreenShot 功能簡單地進行網頁擷圖。

例如本站的其中一個頁面:http://blog.lyhdev.com/p/by-lyhcode.html

使用 Selenium 的完整擷取模式取得畫面:


這個範例每次執行都會先啟動一個 Selenium Server,所以速度比較慢。如果有大量擷圖的需求,可以另以一個 VM 安裝長駐的 Selenium Server 及 Firefox 瀏覽器,就能減少大量截圖所花費的時間。

範例原始碼

續談 Groovy 輕鬆擷取網頁內容,使用 jsoup: Java HTML Parser

這個系列教學的上一篇,我們談到 Groovy + NekoHTML 用於網頁內容擷取;接下來我們將繼續分享更多來自 Java 的好用函式庫,這些強大的函式庫只要搭配 Groovy 這個 JVM Scripting Language,就可以變成輕便好用、開發快速的利器。

jsoup 是很先進的 HTML 解析函式庫,它支援 WHATWG HTML5 的標準,可以將 HTML 源碼解析成類似現代瀏覽器使用的 DOM 結構;簡單地說,有了 jsoup 只要使用類似 jQuery Selector 的語法,就可以輕鬆解析網頁內容。

以下是來自 jsoup 官網的一段簡介。

---
jsoup is a Java library for working with real-world HTML. It provides a very convenient API for extracting and manipulating data, using the best of DOM, CSS, and jquery-like methods.
jsoup implements the WHATWG HTML5 specification, and parses HTML to the same DOM as modern browsers do.
  • scrape and parse HTML from a URL, file, or string
  • find and extract data, using DOM traversal or CSS selectors
  • manipulate the HTML elements, attributes, and text
  • clean user-submitted content against a safe white-list, to prevent XSS attacks
  • output tidy HTML
jsoup is designed to deal with all varieties of HTML found in the wild; from pristine and validating, to invalid tag-soup; jsoup will create a sensible parse tree.
---

Groovy 使用 jsoup 超級方便,只要透過一行 @Grab 宣告,就可以自動取得相關函式庫檔案。

    @Grab('org.jsoup:jsoup:1.7.1')

我們擷取的網頁範例仍為 Google News,網址是「https://news.google.com/nwshp?hl=zh-TW&tab=wn」。

透過 Google Chrome 瀏覽器的 Elements 網頁元素觀察,可以發現目標區域「發燒新聞」的 DOM 結構,我們先以 jQuery 的 Selector 觀念來思考怎麼取得標題:

在前端 jQuery JavaScript 程式中,若想取得標題可以透過以下的 Selector 語法,其中 #s_POPULAR 指的是一個 id="s_POPULAR" 的 DOM 標籤節點,而後面的 .titletext 則是指
在 #s_POPULAR 範圍內 class 屬性包含「titletext」的子節點。

    $("#s_POPULAR .titletext")

透過 jsoup 解析一個指定網頁,只需要一行:

    def doc = org.jsoup.Jsoup.connect("https://news.google.com/nwshp?hl=zh-TW&tab=wn").get()

jsoup 有了 jQuery-like selector 的設計,取得我們想要的發燒新聞標題(List),也只需要一行程式碼:

    doc.select("#s_POPULAR .titletext")

上面的 select() 可以取得一個集合,所以透過 .each 語法就能將標題內容印出:

    doc.select("#s_POPULAR .titletext").each {
        node->
        println "title=${node.text()}"
    }

完整程式碼

Raspberry Pi 新手上路,安裝作業系統、設定無線網路與加裝 Node.js 筆記

Raspberry Pi (Model B)
收到 Raspberry Pi 後,第一步是先安裝作業系統,需要準備兩項東西:
  1. Raspbian “wheezy” (Debian Linux for Raspberry Pi / ARM 架構)
    下載 *-wheezy-raspbian.zip (例如 2012-12-16-wheezy-raspbian.zip)
  2. SD 記憶卡一張(讀寫愈快愈好)
    *關於記憶卡讀寫速度實測請參考「RPi Performance SD Card Test Result」

解壓縮:

unzip 2012-12-16-wheezy-raspbian.zip

解壓縮後會得到 2012-12-16-wheezy-raspbian.img 檔案。

將 SD 卡插入,以下是 Mac OS X 下將 *.img 映像檔寫入 SD 卡的方法(直接複製檔案沒有用喔)!

1) 先卸載 SD 卡

sudo umount /dev/disk3s1


diskutil unmount /dev/disk3s1

2) 利用 dd 指令將映像檔寫入記憶卡

sudo dd bs=1m if=2012-12-16-wheezy-raspbian.img of=/dev/rdisk3

完成後將 SD 卡退出,並插入 Raspberry Pi 的卡槽。

將 Pi 連接 HDMI 線(接到電視或外接螢幕),接上 USB 連接線到  Micro USB 母座(電源),還有 USB 鍵盤,就會進入開機程序。

第一次開機會進入設定畫面,建議在這邊先將 Keyboard 設定好,並且打開 SSH 方便日後遠端連線登入。

從第二次之後的開機,需要帳號密碼登入:

Username: pi
Password: raspberry

關於顯示器

如果小有預算,可以考慮國產的 GeChic 2510M 行動顯示器,它的優點是內建鋰電池、可用 USB 供電,最重要的是提供 HDMI 接線,所以跟 Raspberry Pi 搭配很理想。

無線網路設定

由於 Raspbian 是 Linux 作業系統,並非每張無線網路卡都能正常驅動,有的卡還要加裝驅動程式很麻煩。因為現在的 USB 802.11n 迷你型無線網卡非常便宜(幾百元解決),所以最省事的作法就是先爬文,然後找一張免驅動的網卡,這樣就不用再花時間搞驅動設定。

剛好手邊之前給網樂通(已故?!)用的 EDIMAX USB 網卡相容性極高,插上 Raspberry Pi 開機後就已驅動完成。
  • EDIMAX EW-7711UTn (訊舟) <--經筆者測試免裝驅動可正常使用
  • ... 其他請參考 Raspberry Pi 相容無線網卡列表

要測試驅動是否通過,作法有幾種:

1) 執行 ifconfig 或 iwconfig,看到 wlan0 就代表無線網卡已可用
2) 執行 dmesg | grep usb 指令,找尋類似 usb 1-1.3: Product: 802.11 n WLAN 的訊息

接著使用 iwlist 掃描範圍內可用的基地台訊號:

sudo iwlist wlan0 scan | grep ESSID

接著修改 wlan0 的設定,因為 Rasbian 預設並沒有 vim,這時候 nano 加減用:

sudo nano /etc/network/interfaces

找到 wlan0 的設定區,將設定改成以下:

allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid SSID
wpa-psk PASSWORD

其中 SSID / PASSWORD 填入基地台訊號的 SSID 名稱與密碼,將預設的 manual 改為 dhcp(自動取得 IP / DNS);原有一行「wpa-roam」設定可將它移除。

Nano 的簡易操作提示:
  • Ctrl + O 存檔(需要再確認檔名後多按一次 ENTER 才寫入)
  • Ctrl + X 離開

再來重新啟動無線網路介面。

sudo ifdown wlan0
sudo ifup wlan0

等待 DHCP 取得 IP,成功會顯示「bound to 192.168.......」訊息。

輸入「ifconfig」確認 wlan0 取得的 IP 位址。

wlan0     Link encap:Ethernet  HWaddr 00:1f:1f:a8:c6:85
          inet addr:192.168.0.105  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2618 errors:0 dropped:0 overruns:0 frame:0
          TX packets:709 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:566345 (553.0 KiB)  TX bytes:123308 (120.4 KiB)

再用 ping 確認網路已連線。

$ ping google.com
PING google.com (74.125.128.102) 56(84) bytes of data.
64 bytes from hg-in-f102.1e100.net (74.125.128.102): icmp_req=1 ttl=46 time=36.4 ms

到這邊就已經完成無線網路連線設定了,需要了解更多 Pi 的無線網路設定可參考:

Raspberry Pi A Quick-Start Guide
http://media.pragprog.com/titles/msraspi/wifi.pdf

遠端登入

除非想要使用 PI 的 X Window 桌面,否則直接用筆電遠端連線到 Pi 還是比較省時省力的方式,這邊只要用一般的 SSH 連線登入:

ssh pi@192.168.0.100

因為 Raspbian 已經內建 X Window / LXDE 桌面軟體,利用 SSH 的 -X 選項可以建立 X11 Forwarding,也就是讓 Pi 機器上執行的 X 應用程式,遠端傳送到本地的畫面。Linux 桌面系統可以直接執行:

ssh -X pi@192.168.0.100

Mac OS X 的使用者,需要先安裝「XQuartz」這套軟體,才能擁有可執行 X11 桌面的環境。

Mac OS X + Raspberry Pi Using SSH X11 Forwarding
Raspberry Pi X11 Forwarding

安裝套件(以 Node.js 為例)

Raspbian 以 Debian Linux 為基礎,代表著我們有機會用 apt-get 取得資源豐富的軟體套件,而不用再自己動手編譯軟體。畢竟 Raspberry Pi 是 ARM 處理器架構,用習慣高速桌機筆電的開發者,在 Pi 上編譯軟體應該會覺得慢到吐血;一般來說,我們並不會真的在 Pi 這種嵌入式裝置上面編譯軟體,而是透過 GCC Cross-Compiler 在開發端先將軟體編譯打包好,再丟給 Pi 安裝使用。

幸好 Raspbian 的 Package Repositories 已經有豐富的 DEB 套件可用,以安裝 Node.js 來說,只需要下一行指令:

sudo apt-get install nodejs

裝好之後就可以擁有 Node.js 執行環境。

當然其他還有很多常用軟體,也都可以用 apt-cache search 尋找及 apt-get 搞定安裝。

apt-cache search vim
sudo apt-get install vim

到這裡相信讀者應該已經能想到不少 Pi 的應用啦?!讓我們一起來「Raspberry Pi 的奇幻漂流」吧~~

Mac OS X 電影字幕 SRT 檔案轉碼(BIG5 to UTF-8)使用 iconv

網路下載的電影繁體中文字幕通常是 BIG5 編碼,這在 Mac OS X 下使用許多播放器開啟,字幕顯示都會變成亂碼,就像以下的擷取畫面。
繁體中文(BIG5編碼)的 SRT 字幕呈現亂碼

亂碼主要的原因是播放器預設是以 UTF-8 編碼讀取,雖然有些播放器可以切換編碼選項,只要調成 BIG5 或 MS950 即可;但是有愈來愈多播放器或多媒體機上盒都是預設為 UTF-8,所以也有編碼轉換的需求。

在 Mac OS X 或 Linux 系統下,轉換編碼(BIG5 to UTF-8)並不需要藉助第三方工具,使用內建的 iconv 指令就能達成任務,這需要在終端機下操作。

使用 iconv 指令進行轉碼

查看 iconv 支援哪些編碼格式:

iconv -l

因為我們已經知道原始編碼是 BIG5,所以可以用 -f 指定來源編碼,進行轉碼測試:

iconv -f big5 the_movie.cht.srt



iconv -f big5 -t utf-8 the_movie.cht.srt

(-t 指定轉換目的編碼,因為系統預設本來就是 UTF-8,故可省略)

先測試一次的原因是轉碼可能會失敗,例如上述指定 BIG5 轉換成系統預設(UTF-8),可能會因為某些中文字元沒有對應字碼,造成轉換失敗,訊息類似以下。

iconv: the_movie.cht.srt:57:10: cannot convert

這種情況我們可以用 -f big5-2003 或 -f cp950 重新測試一次:

iconv -f big5-2003 the_movie.cht.srt



iconv -f cp950 the_movie.cht.srt

確認字幕轉換完整後,再存成新檔案。

iconv -f big5-2003 the_movie.cht.srt > the_movie.cht.utf8.srt



iconv -f cp950 the_movie.cht.srt > the_movie.cht.utf8.srt

* CP950 與 Big5-2003 是擴充 BIG5(大五碼),所以字集比較完整。

經過 iconv 轉碼後,影片播放就能正確顯示中文字幕

切換 Jekyll 的 Markdown 轉換引擎

Jekyll 是靜態網站產生工具,支援 Markdown 寫作是它的一大特色;在 Markdown 轉 HTML 的處理,Jekyll 支援多種 Markdown 轉換引擎。

近期使用 Jekyll 製作一些商業、公益網站,很快(通常只要 2~3 小時)就能把網站雛形做出來(使用 jekyll-bootstrap + wrapboostrap)。不過在預設情況下,Jekyll 使用 Maruku 將 Markdown 轉出 HTML 卻使用單引號(single quote) ,這和我們在樣板中慣用的雙引號(double quote)顯然不同,所以一份 HTML 文件同時存在兩種引號。

當然這並不影響網頁瀏覽,不過對 HTML 的潔癖讓我相當在意這個問題。

Jekyll with Maruku (default)

因為很懶得研究 Maruku 的參數怎麼設定(Google 第一頁找不到解法),所以今天突發奇想乾脆直接把 Markdown 引擎換掉;沒想到一改就順利解決,RDiscount 預設就是雙引號的輸出。

Jekyll with RDiscount

設定方式超簡單,只要在 _config.yml 加上一行:

markdown: rdiscount

就可以切換不同的 Markdown 引擎。

幾個比較常用的 Ruby Markdown implementation 有:

  1. BlueCloth
  2. Maruku
  3. RDiscount

因為 RDiscount 是 C 語言開發的版本,所以速度比其他兩個 Ruby 實作的版本還要快上很多。換成 RDiscount 之後除了解決雙引號問題,同時也讓網頁轉換速度提昇一些。

2012年12月29日

開啟 Mac OS X 外接硬碟 NTFS 讀寫支援 OSXFUSE + NTFS-3G

升級到 Mac OS X Mountain Lion 之後,如果要支援外接硬碟 NTFS 格式的讀寫(預設只能讀不能寫),可以依序安裝以下三套軟體(都是免費版)!

OSXFUSE
http://osxfuse.github.com/

請注意以下的設定步驟一定要將「MacFUSE Compatibility Layer」選項打勾,否則可能會出現錯誤訊息:

dyld: Library not loaded: /usr/local/lib/libfuse.2.dylib
Reference from /usr/localbin/ntfs-3g
Reason: image not found

MacFUSE Compatibility Layer 一定要"打勾"

NTFS-3G for Mac OS X
http://macntfs-3g.blogspot.tw/2010/10/ntfs-3g-for-mac-os-x-2010102.html

優化 Blogger 文章分享至 Facebook 的摘要內容

將發表在 Blogger 的文章連結轉貼至 Facebook,會自動擷取標題、圖片及簡介等,但是到目前為止,Blogger 內建的佈景主題(樣板),並沒有支援 Facebook 的 Open Graph 標籤,所以轉貼連結後,一直都是沒有簡介文字。


目前要做到內文摘要比較困難,但是應急的方式就是自訂一段固定的介紹文字;作法是直接修改 Blogger 的樣板 HTML 原始碼,在 <head> 之後加入 Open Graph 的相關設定:

    <!--open graph-->
    <b:if cond='data:blog.pageType == &quot;index&quot;'>
        <meta content='blog' property='og:type'/>
        <meta expr:content='data:blog.title' property='og:title'/>
    <b:else/>
        <meta content='article' property='og:type'/>
        <meta expr:content='data:blog.pageName' property='og:title'/>
    </b:if>
    <meta expr:content='data:blog.url' property='og:url'/>
    <meta expr:content='data:blog.title' property='og:site_name'/>
    <meta content='玩物尚誌是一個內容多元的部落格,分享閱讀、輕旅行及軟體創作的心得筆記。' property='og:description'/>

如果想要檢查設定結果是否符合期待,可以用  Facebook 提供的 Debugger 服務:

http://developers.facebook.com/tools/debug

將網誌的網址輸入後,進行偵錯就可以得到這些訊息:


更直接簡單的測試方法,就是直接將網址貼到 Facebook 的塗鴉牆;不過要注意到可能有快取(cache)的問題,所以盡量選一個沒貼過的網址來測試會比較準確。



[Grails 開發筆記] 變更 Session Timeout 時間設定


在 grails-app/conf/Config.groovy 無法找到 Session Timeout 的相關設定,如果需要修改則有以下方式:

方法一、修改 Grails Templates

Templates 是 Grails 用來產生 web.xml 等相關設定的範本,在打包成 .war 檔案時,會依照 Templates 的內容產生;預設的專案資料夾並不會包含 Templates,需要先執行「grails install-templates」將檔案複製一份到專案下。

grails install-templates

執行後會產生「src/templates」資料夾,在「src/templates/war/web.xml」可以找到 Session Timeout 設定。

 72     <session-config>
 73         <!-- 30 minutes -->
 74         <session-timeout>30</session-timeout>
 75     </session-config>

方法二、修改 AppConstants.groovy

在「grails-app/conf」資料夾下建立或修改 AppConstants.groovy 程式碼,加入一行常數值設定。

public static final Integer SESSION_TIMEOUT = 3600    //3600 sec. = 60min.

方法三、在 Controller 使用 setMaxInactiveInterval 設定

這是在執行階段可以動態修改 Session Timeout 時間的方法。

session.setMaxInactiveInterval(AppConstants.SESSION_TIMEOUT);


*歡迎訂閱 Groovy Taiwan 臉書專頁,可以得到更多 Groovy / Grails 訊息分享。

2012年12月27日

[記錄] 等待三個月終於收到 Raspberry Pi 超迷你電腦

Raspberry Pi 是 2012 年很熱門的超迷你電腦,它的體積只比名片盒稍大一些,但是塞進了有現網路孔、SD 讀卡機、USB 連接埠、耳機孔、HDMI ...只需要 USB 提供電力,它就能變成一個有趣的 Linux 主機或多媒體播放器。

這麼可愛的小電腦要價多少錢呢?只要美金 $35 元就能帶回家。

雖然 Raspberry Pi 在年初就開賣,產量也已經提高、解除一人限購一台的限制;但是到目前為止仍處於有錢還不一定買得到現貨,想買的只能乖乖排隊等候;筆者在 10 月下單後,就音訊全無...直到聖誕節前一個星期,才收到這個遠從英國飄洋過海來台的禮物 : )

這次下單一次訂了兩台,外加兩組專用外殼,有趣的是 Raspberry Pi 主板是 Made In China(世界工廠嘛!)但塑料外殼居然是 Made In United Kingdom!!!

至於 Raspberry Pi 有什麼用處?

對於只要 VIM 就能工作的 Geek,把這塊電路板放進襯衫口袋就能當行動辦公室 : )

或者,灌好 XBMC 就能變成客廳的多媒體播放盒。

電子積木玩家也可以拿它來串接 Arduino : )

如果口袋夠深,一次訂購 64 台組成超級電腦?!




使用 Groovy + NekoHTML 快速開發網頁原始碼資料分析程式

Java 有很強悍的 XML 與 HTTP Client 函式庫,所以可以看到不少爬蟲引擎都是 Java-based 設計;但是如果只想要寫一個非常簡單的網頁原始碼資料分析,使用 Java 開發相當麻煩,通常許多開發者會選擇比較簡易的作法,例如市售書籍有介紹 PHP + CURL 的作法。

不過有了 Groovy 這個 Java 的 Scripting 語言,只要簡單地搭配 NekoHTML Library 就能快速做出簡易源碼分析程式。前幾天曾介紹過「Groovy + XmlParser」用來擷取 Google 新聞 RSS 的內容,但是這個作法並不適用於一般網頁,因為一般的 HTML 很少能通過標準 XML 的解析,所以我們只另找對 HTML/XHTML 有更強悍解析能力的函式庫。

這個範例使用 CyberNeko 的 NekoHTML,這是個相當管用的函式庫,搭配 Groovy 服用只需要不到十行程式碼就能達成目的。

此範例的目標是擷取 Google 新聞首頁側邊欄的「發燒新聞」列表標題,雖然用 RSS 或 API 存取也能達成相同目的;但本文的範例對某些用途來說比較敏感,所以只好挑個比較沒爭議的資料來源 : )

view-source:https://news.google.com/nwshp?hl=zh-TW&tab=wn
本範例擷取右邊側欄「發燒新聞」的文字內容

第一個要解決的問題,是傳統 Java 需要先加載 .jar 函式庫檔案到 CLASSPATH 的麻煩,這對 Groovy 來說,只需要一行程式碼就解決了,使用 Grape / Grab 自動從 Maven Repositories 取得相依的套件庫:

@Grab('net.sourceforge.nekohtml:nekohtml:1.9.16')

接下來開始建立 NekoHTML 的 SAXParser(),它用來解析 HTML/XHTML 文件。


def parser = new org.cyberneko.html.parsers.SAXParser()
parser.setFeature('http://xml.org/sax/features/namespaces', false)

從某個 URL 載入原始碼並完成解析只要一行:

def page = new XmlParser(parser).parse('https://news.google.com/nwshp?hl=zh-TW&tab=wn')

接著利用網頁除錯工具或打開原始碼,找到發燒新聞的 DOM 標籤。

使用 Google Chrome 內建的網頁除錯工具

以這個範例來說,我們的目標就是這個 <DIV> 標籤:

<div class="small-section section-POPULAR" ...

所以利用深度優先(depthFirst)搜尋將節點找到,這裡搭配 grep 進行資料篩選,只有 class 屬性包含 small-section 與 section-POPULAR 才會被取出:

page.depthFirst().DIV.grep{ it.'@class'?.contains('small-section') }

上面的傳回結果是 List 型態,所以可以用 each 做迴圈:

    page.depthFirst().DIV.grep{ it.'@class'?.contains('small-section section-POPULAR') }.each {
        div->
        println div
    }

下一步開始修改迴圈內容,將裡面包含的標題找出來,標題清單位於這個 <DIV> 標籤內:

<div class="contents" s="t">

同樣使用 depthFirst 方式搜尋:

    def contents = div.depthFirst().DIV.grep{ it.'@class'=='contents'&&it.'@s'=='t' }

這個結果也是 LIST,我們只需要取出一個:

    if (contents.size() > 0) {
        contents.first().depthFirst().DIV.grep{ it.'@class'=='title' }.each {
            div_title->
            println div_title
        }
    }

其中 div_title 的資料結構如下:

DIV[attributes={class=title}; value=[A[attributes={target=_blank, class=article usg-AFQjCNGshI48ZItUXdT9SuCtCCz76f-tGA did--2335265617202207122, href=http://www.espnstar.com.tw/news/basketball/2012/1227/256409.htm, url=http://www.espnstar.com.tw/news/basketball/2012/1227/256409.htm, id=-2335265617202207122}; value=[SPAN[attributes={class=titletext}; value=[險勝灰狼豪自評打得難看]]]]]]

到這邊已經很容易直接將文字內容取出:

        println div_title.A.SPAN.text()

目前完成的程式碼如下,已經可以解析出標題文字:

    @Grab('net.sourceforge.nekohtml:nekohtml:1.9.16')
 
    def parser = new org.cyberneko.html.parsers.SAXParser()
 
    parser.setFeature('http://xml.org/sax/features/namespaces', false)
 
    def page = new XmlParser(parser).parse('https://news.google.com/nwshp?hl=zh-TW&tab=wn')
 
    page.depthFirst().DIV.grep{ it.'@class'?.contains('small-section section-POPULAR') }.each {
        div->
     
        def contents = div.depthFirst().DIV.grep{ it.'@class'=='contents'&&it.'@s'=='t' }
     
        if (contents.size() > 0) {
            contents.first().depthFirst().DIV.grep{ it.'@class'=='title' }.each {
                div_title->
                println div_title.A.SPAN.text()
            }
        }
    }

輸出結果參考如下:

印度政府把巴士強暴案女大學生送新加坡治療
險勝灰狼豪自評打得難看
金溥聰:總統堅持對的事氛圍會改善
黃淑琦不熟新家墜樓賈永婕哭喊:妳趕快回來!
創舉! 飢童可免費到4大超商吃到飽
京廣高鐵通車陸媒瘋狂連線
宏達電蝴蝶機Butterfly(2498-TW)熱銷
披肩殺人! 捲入機器勒斃女子
Kobe狂飆40分湖人兵敗丹佛
總統:希望每年新生兒不少於18萬


上面的程式碼落落長,其實只是為了說明 NekoHTML 的用法,實際上程式碼可以化簡成不到十行:

    @Grab('net.sourceforge.nekohtml:nekohtml:1.9.16')
    def parser = new org.cyberneko.html.parsers.SAXParser()
    def page = new XmlParser(parser).parse('https://news.google.com/nwshp?hl=zh-TW&tab=wn')
    page.depthFirst().DIV.grep{ it.'@class'=='title' }.each {
        println it.A.SPAN.text()
    }

Groovy 很值得 Java 開發者學習,即使沒機會在專案派上用場,它平時也能化簡很多工作上繁雜的電腦操作程序啊 : ) 歡迎加入 Groovy Taiwan 的學習社群~

原始碼分享於 Gist:
https://gist.github.com/4387321



超簡易電器維修之超音波清洗機電容更換篇

數年前網購買回一台 CODYSON CD-3800A 超音波清洗機,一千元有找很便宜,拿來洗錶帶、眼鏡、電腦及單車小零件,搭配特X屋的生物酵素清潔劑很好用,三分鐘就可以讓大部分的汙漬分離。但是這種電器只有店家保固一年,過保固幾乎只能重新買一台~

好不容易最近它終於壞掉了,原本心想終於可以買台新款、容量大一些,結果搜尋一下發現網拍已經沒有這個系列,可能是因為它本來就只做外銷,國內經銷商不容易找~

既然變成故障品,剛好可以滿足我想知道超音波清洗機內部構造的好奇心,二話不說就把它整台拆開,結果發現故障的原因很明顯是一顆塑膠電容爆漿了。

超音波清洗機的電路板~


更換電容需要的工具:電烙鐵、吸錫器、焊錫~


這顆爆漿的電容,外殼已經碎裂,還好勉強可以看出標示:CL21 355K/250V。不過跑遍台中電子街的電子材料行根本找不到相同規格,只好買一顆規格比較接近的 3.3uf 麥拉電容(335J/250V),價格只要 $25 元就拿來碰碰運氣,死馬當活馬醫啦!


國中工藝課學的電焊技術又派上用場,雖然焊得很爛,但畢竟小小一顆電容不致於焊壞啦!


新的塑膠電容上陣,比原本的電容還大顆,所以接腳翹了一邊~


重新接上電源,登!登!亮登了~歷久彌新的超音波清洗機大復活~只花了 $25 元和十分鐘!(不過光是找電容就花掉兩個小時@@)


心得:過保固的電器,如果只是保險絲燒掉、電容爆漿或按鈕失靈等問題,自己更換電子零件只要花少少的材料費;雖然很多時候「買新的比較快」,但是修好還能用的東西不要丟掉,環保、愛地球無價!

新片推薦:人再囧途之泰囧(人在囧途)

人再囧途之泰囧(Lost In Thailand)
年底(2012年12月)新上映的《人再囧途之泰囧(Lost In Thailand)》,據說才三天票房就破億,目前已傳出破七億的消息,這部中國的商業大片,到底有什麼樣的魅力呢?

《人在囧途》相信看過的人不少,以中國春運的特殊情景(CCTV形容為「全球罕見的人口流動現象」),由兩位社會地位與生活背景對比極大的主角,譜出十分搞笑逗趣但又流露人間真情的故事橋段。

《“泰”囧》的劇情與《人在囧途》並無延續性,但對比鮮明的內容十分相似;故事場景則搬到安逸的泰國,演員的浮躁與荒誕和安逸的泰國拍攝背景,有了更大的反差;這是由喜劇演員徐崢首次自編自導自演的電影,同樣由一位富有商人搭配一位高度反差的傻蛋市井小民,他們追求的人生價值顯然有極大的落差;大多數的人不管社會地位、價值觀與想法,都是介於兩者之間,或者說兩種特質都是交互存在,所以片中的暗喻,其實很容易能讓影迷開始思考什麼是「真正的幸福?」

新華網對《人再囧途之泰囧》的介紹文章:
(內有劇情,慎入!)
http://big5.xinhuanet.com/gate/big5/news.xinhuanet.com/newmedia/2012-12/21/c_124127400.htm

愈來愈多泰囧的相關新聞報導:
http://goo.gl/Scn5n

台灣什麼時候看得到呢?目前不得而知,有消息再更新啦~如果不想等,就打開迅雷吧!

2012年12月26日

美觀好用的免費資源下載工具 - 迅雷 for Mac OS X

迅雷 for Mac OS X

迅雷是很管用的網路資源下載工具,它最強大的地方就在於對各種協定廣泛支援,舉凡基本的 HTTP/FTP 到 P2P 類型的 eMule(ed2k)、BitTorrent ... 都能通吃。最棒的是,它提供 Mac OS X 版本,不用再為了下載網路資源,而多養一台  Windows 動物機 : )


趕快安裝就對了!

http://mac.xunlei.com/

Grails / Groovy 使用 XmlParser 快速產生測試用的範例內容

在 Grails 的開發階段,我們習慣將 development 與 production 分別使用不同資料庫來源(DataSource)。在開發階段我喜歡保留預設的 H2 Database Engine,這是純 Java 開發的資料庫引擎,畢竟是 Grails 官方的選項,它與 Grails 的 GORM(底層是 Hibernate)一起運作不太會有問題。H2 相當輕量易用,可以只將開發階段測試用的資料放在記憶體,重新啟動測試伺服器後就會一切從頭開始。

這是預設的 H2 DataSource 設定(DataSource.groovy)。

    development {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }
    }

但是在開發階段,我們仍希望有一些資料,這樣比較容易設計 Controller 及 Web UI 介面。假設有一個 Model (Grails 的 Domain Class)是 Post(Post.groovy):

    class Post {
        String title
        String content
    }

這個時候有幾種方式,可以在開發階段建立測試資料:
  1. 自己動手 KEY-IN...但是這太蠢了,萬一想要建一百筆,每次重新啟動 Server 都要打字打到手抽筋。
  2. 改用 MySQL 或其他資料可以永久保存的 DataSource,但這樣會讓開發環境的建立變得麻煩。
  3. 在 BootStrap.groovy 使用樣板或隨機產生的資料來灌水,這樣一切就變得更自動化。

當然,我們會使用第三種作法,這樣可以保持開發環境容易建立、使用與可攜性,但如果能再加入一點手腳,讓產生的資料看起來稍微有點意義,這樣一切就更美好了。

以 Post (發佈文章)的內容來說,我們可以直接找個 RSS/ATOM 來源撈資料,再把內容灌到資料庫,有了 Groovy 超簡單的 XmlParser 幫忙,這項需求的處理只要簡單的幾行 code 就搞定:

資料來源範例(Google 新聞):
https://news.google.com/news/feeds?pz=1&cf=all&ned=tw&hl=zh-TW&output=rss

先用 Groovy 寫一小片段 Scripting 測試程式:

```groovy
    def url = 'https://news.google.com/news/feeds?pz=1&cf=all&ned=tw&hl=zh-TW&output=rss'
 
    def xml = new XmlParser().parse(url)
 
    def items = [:]
 
    xml.channel[0].item.each {
        item->
     
        items << [
            title: item.title[0].value().first(),
            content: item.description[0].value().first().replaceAll("<(.|\n)*?>", '')
        ]
    }
```

接下來在 Grails 的 BootStrap.groovy 設定開發階段(development environment)專用的文章自動擷取,Groovy 的 XmlParser 搭配 Grails 的 GORM 非常簡單!這個範例順便將 HTML 原始碼的標籤,利用 Groovy 內建的字串 Regular Expression 清理乾淨。

```grails
    class BootStrap {
        def init = { servletContext ->
            environments {
                development {
                    //自動產生文章 RSS from Google News
                    def url = 'https://news.google.com/news/feeds?pz=1&cf=all&ned=tw&hl=zh-TW&output=rss'
                    def xml = new XmlParser().parse(url)
                    def i = 0
                    xml.channel[0].item.each {
                        item->
                     
                        new Post(
                            title: item.title[0].value().first(),
                            content: item.description[0].value().first().replaceAll("<(.|\n)*?>", ''),
                        ).save(flush: true)
                    }
                }
            }
        }
    }
```

2012年12月12日

使用 Sketch Up 及 Sweet Home 3D 建構室內設計模型

上一篇談到 Sweet Home 3D 這套軟體,它對於家具模型的擺設及 3D 渲染有著簡單易用的特色;但如果有些木作、系統櫃或家具,想要量身打造,要怎麼做比較容易呢?

對於自己建立家具模型,Sketch Up 就是相當好的選擇,它也有免費版本可供選擇,對於繪製 3D 模型提供了很友善的介面,只要稍微了解幾項基本的繪製工具,就可以開始建立自己的 3D 模型。

例如一個量身訂做的系統吧台,依照空間訂製的尺寸,包含電器櫃收納的櫃身設計,這個時候只要用 Sketch Up 就可以很快將模型繪製出來。

吧台模型櫃身收納設計

吧台模型背面退縮設計
使用 Sketch Up 選單的「File / Export / 3D Model...」將模型匯出成  *.dae(COOLADA File),就可以在 Sweet Home 3D 使用「傢俱 / 插入傢俱」將模型匯入。






匯入後就會列入模型區,拖曳到平面圖即可將自製的吧台模型加入圖面。


調整好位置及方向,最後再利用 Sweet Home 3D 渲染成 3D 模擬圖。


Sweet Home 3D 免費室內設計軟體,適合初學者入門的好工具

Sweet Home 3D

Sweet Home 3D 是免費的室內設計軟體,你只要在 2D 平面圖規劃好空間尺寸與家具配置,它就能幫你同時產生 3D 透視圖,並且可以在三維空間中移動、切換視角,更棒的是它也內建渲染功能,可以輸出擬真的照片,或是利用錄影功能拍攝在室內走動的影片。

除了免費之外,跨平台也是 Sweet Home 3D 的一大特色(使用 Java 開發),它提供免安裝版(Portable),只要放在隨身碟,不管你的電腦是 Windows、Linux 或 Mac OS X 都能執行。

Sweet Home 3D 的介面操作很適合一般大眾,即使沒有室內設計繪圖的技能,也可以玩得很愉快。雖然自己建立 3D 家具物件不容易,但 Sweet Home 3D 的好處就是可以找到不少現成的模型,可以找到比較接近的顏色、樣式或尺寸,試著在空間中擺放看看感覺。

另外 Sketch Up 有大量的模型庫,例如部分熱門的 IKEA 家具模型,也可以透過匯入的方式加到 Sweet Home 3D 使用。

第一次使用的朋友,可以先參考 Mobile01 這篇文章,將常用的家具模型及外掛一次準備到位;建議用隨身碟儲存免安裝版,日後再使用或拷貝分享給他人就會相當方便。

最近剛好許多朋友都買了新房子,也剛好都沒預算聘請設計師,就趁機會一起研究這套軟體,也順便將練習過程分享。

取得室內建築的 2D 平面圖是最快的方式;如果沒有就需要自己用卷尺慢慢量!

右上方的 2D 圖面是自己動手繪製的區塊,先繪製空間(地面)區塊大小,再建立牆面,然後擺上家具。右下方會即時顯示 3D 透視圖,並可切換視角。

選單的照相機按鈕,可以從目前的 3D 視角拍照(出圖),設定高解析度並選擇高畫質,就能輸出渲染後的照片。如果想知道 Sweet Home 3D 能做到什麼樣的效果,可以參考這個相簿

以下是第一次練習的出圖。

用現成模型擺出的客廳空間

另一個視角

現成模型組合的臥室空間

另一個視角

2012第五屆iT邦幫忙鐵人賽...鐵人優選獎!

鐵人優選獎
iT 邦幫忙是 iThome 經營的社群網站,有點類似 Yahoo! 奇摩知識+,不過內容是以 IT 技術方面為主,也可以說是台灣的 StackOverflow,舉凡資安、MIS、程式設計的各類疑難雜症,只要上去問...就有機會得到解答。

iT 邦幫忙對於鼓勵台灣資訊圈的分享風氣,可以說是相當盡心盡力,舉辦的鐵人賽已經邁入第五屆,讓不少人進到這個社群,進而分享各種資訊領域的知識。

鐵人賽的規則,簡單說就是參加者必須連續三十天、每天都至少分享一篇文章,且內容必須以作者原創為主。貼文時間必須在當天,不能提早或延遲發佈,如果中途因故沒有發表文章,就會失去完賽資格。

今年我報名參加鐵人賽,其中人生組因為第23天發文貼錯組別,結果就失去資格;但技術組的部份順利完成三十篇,並且入圍決賽。直到前幾天最終成績揭曉,意外發現拿到「鐵人優選獎」,因此得到一個不一樣的聖誕節禮物。

發現身邊有不少朋友仍不知道鐵人賽這活動,希望明年有機會大家在一同參加!以下分享本次參加鐵人賽的心得。

  1. 寫自己最感興趣、擅長或最近想研究的主題。
  2. 提早七天開始寫作,增加BUFFER。
  3. 練習用 Markdown 之類的文件格式快速寫作。
  4. 分享、分享、熱愛分享。
  5. 和同伴一起參加,互相提醒:「你今天貼文了沒?」(鐵人賽期間每天的問候方式)
  6. 三十天可以養成很多習慣:早起、晨讀、夜讀、持續寫作、...
  7. 三十天可以累積不少東西,也許是你的第一本書或下一本書的素材。
  8. 重點不在得獎,而是真正完成一個自己設定的目標。

Sublime Text 2 安裝 Zen Coding 外掛

Zen Coding 是用來加速 HTML 開發的程式撰寫輔助工具,它利用類似 CSS Selector 的概念,讓開發者只要鍵入少許語法,就可以自動快速產生對應的 HTML 代碼。

Sublime Text 2 是跨平台(支援 Windows、Linux、Mac OS X)的文字編輯器,深受許多開發者喜愛。

Sublime Text 2 只要簡單地安裝外掛就能享受 Zen Coding 的極速快感,為了方便安裝我們同時需要 Sublime Package Control 這個套件,它利用 Repositories 的概念提供大量 Sublime 適用的外掛!

Zen Coding(Set of plugins for HTML and CSS hi-speed coding)
http://code.google.com/p/zen-coding/

Sublime Package Control
http://wbond.net/sublime_packages/package_control

安裝步驟:

打開 Sublime Text 2(以下簡稱 Sublime),按下「ctrl(control) + `」叫出 console 畫面,輸入以下安裝指令。

import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print 'Please restart Sublime Text to finish installation'


安裝好之後重新啟動 Sublime。

在選單列找到 Preferences / Package Control 執行。


輸入「install package」。



按下 ENTER 後,會列出可用的套件清單,再輸入「zencoding」。



按下 ENTER 就會開始安裝,完成後會顯示一份 README 說明。

再次重新啟動 Sublime,編輯一個 .html 檔案。以下是兩個簡易的 Zen Coding 用法說明。

輸入「cc:ie6」並按下 TAB 鍵,會自動產生:

<!--[if lte IE 6]>
<![endif]-->

輸入「table>tr*3>td*4」並按下 TAB 鍵,會自動產生:

<table>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>

如此一來,開發者寶貴的生命又可以節省不少分秒。
lyhcode by lyhcode
歡迎轉載,請務必註明出處!