2013年1月4日

Groovy 使用 HttpBuilder 簡化 HTTP 網頁資料存取設計

HttpBuilder 是 Groovy 用來簡化網頁 HTTP 協定存取資料的 DSL(Domain Specific Language,領域描述語言),它大幅簡化 Http Client 端應用程式的設計。

在 Java 程式中,要存取 HTTP 資料通常很麻煩,需要好幾行才能搞定。

    URL url = new URL("http://google.com");
    URLConnection conn = url.openConnection();
    //...略

如果要做到進階的網頁資源存取,一個簡單的動作有可能需要用上錯綜複雜的程式碼。一般來說,Java 開發者會先加入 Apache Commons HttpClient 這個套件,來補強 Java 內建網路相關類別功能不足。

由於 Java 實在太麻煩,我們就別浪費時間看它怎麼做。

在 Groovy 的世界中,存取網頁原始碼最短只需要一行:

    new URL('http://google.com').text

實際上在存取網頁時,我們需要加上 GET / POST 的參數資料,設定 HTTP Header 以及判斷伺服器的回傳的代碼等;如果加上這些考量,就需要額外的函式庫輔助才行。在 Groovy  程式設計中;Builder 是一個相當棒的設計,它可以讓一段比較複雜的程式碼用清楚表達的描述語言來撰寫,例如 HttpBuilder 官方的範例:

    @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.6' )
    import groovyx.net.http.*
    import static groovyx.net.http.ContentType.*
    import static groovyx.net.http.Method.*

    def http = new HTTPBuilder( 'http://ajax.googleapis.com' )

    http.request( GET, JSON ) {
      uri.path = '/ajax/services/search/web'
      uri.query = [ v:'1.0', q: 'Calvin and Hobbes' ]

      headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'

      response.success = { resp, json ->
        println resp.statusLine

        json.responseData.results.each {
          println "  ${it.titleNoFormatting} : ${it.visibleUrl}"
        }
      }

      response.failure = { resp ->
        println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
      }
    }

上面這段程式碼存取 Google 搜尋的 API,設定了 v 與 q 兩個參數,也依照伺服器回傳結果,依照 success(通常代碼為 200)或 failure(例如 404 錯誤),分別執行不同的處理(利用 Groovy 的 Closure 撰寫)。這個範例也設定了 HTTP Request Header,在送出請求時偽裝成 Ubuntu 下的 Firefox 瀏覽器(雖然這個偽裝很鳥);比較特別的地方,在於我們不僅指定 HTTP 請求方式為 GET,同時也指定回傳資料類型為 JSON。

由於 Groovy 本身已支援 JSON 的資料結構,所以回傳的結果 json 變數,可以直接透過 json.titleNoFormatting 這樣的方式取得 value。

將 http.request 的回傳資料類型改成 HTML,傳回的結果 html 變數,就是 Groovy Slurper 解析過的 NodeChild 物件,可以進一步存取標籤的值(範例是取得 <head> 中 <title> 標籤的標題文字)。

    @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.6' )
    import groovyx.net.http.*
    import static groovyx.net.http.ContentType.*
    import static groovyx.net.http.Method.*

    def http = new HTTPBuilder( 'http://google.com' )

    http.request( GET, HTML ) {
      uri.path = '/search'
      uri.query = [ q: '蘋果' ]

      headers.'User-Agent' = 'Mozilla/5.0 .................'

      response.success = { resp, html ->
        println resp.statusLine
        println html.HEAD.TITLE
      }

      response.failure = { resp ->
        println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
      }
    }

在 User-Agent 的部份要填入什麼,才能把 HTTP 存取偽裝成比較像瀏覽器呢?到 www.myhttp.info 網站可以查詢目前所用瀏覽器的 User-Agent,複製到程式碼使用就行了。


沒有留言:

張貼留言

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