2010年10月18日 星期一

OPDS Catalog, OpenSearch, and Stanza

OPDS Catalog & OpenSearch OPDS Catalog & OpenSearch


想要產生 OPDS Catalog 以及提供 OpenSearch 的功能,如圖右上角,讓 Stanza 這個閱讀器可以看得懂,但 OPDS Catalog 1.0 的規格還沒有完全支援(今天是 2010/10/18,Stanza 軟體是 3.0.3 版本),因此像是一些 link 中 rel 這個 attribute ,填入 OPDS Catalog 1.0 的規格後,也會導致 Stanza 讀不出來,之前測試的結果,把 rel 留空白應該可以。


最近想要試的是 OpenSearch,在 OPDS Catalog 1.07.5 裡有的定義:


7.5. Search

An OPDS Catalog MAY provide a search facility through an [OpenSearch] description document. Links to [OpenSearch] description documents MUST use the “search” relation value and the “application/opensearchdescription+xml” media type as defined in the “Autodiscovery” section of the [OpenSearch] specification.

<link rel="search"
      href="search.xml"
      type="application/opensearchdescription+xml"/>

In an [OpenSearch] description document, the search interface SHOULD use the media type associated to OPDS Catalogs:

<Url type="application/atom+xml;profile=opds-catalog"
     template="http://example.com/search?q={searchTerms}" />

OPDS Catalog Feed Documents MAY include elements from the [OpenSearch] namespace such as “opensearch:totalResults” or “opensearch:itemsPerPage” in [OpenSearch] responses.


只是我嘗試的結果,那個 type 沒被認出來,倒是直接用 type="application/atom+xml" 就可以看到,以 Feedbooks Catalog 為例:


<link type="application/atom+xml" rel="search" title="Search Feedbooks" href="http://www.feedbooks.com/search.atom?query={searchTerms}"/>


所以,可以很偷懶乾脆一起寫:


<link type="application/opensearchdescription+xml" rel="search" title="Search on Feedbooks" href="http://www.feedbooks.com/opensearch.xml"/>
<link type="application/atom+xml" rel="search" title="Search Feedbooks" href="http://www.feedbooks.com/search.atom?query={searchTerms}"/>


至於 opensearch.xml 描述檔該怎樣寫,也可以直接參考 Feedbooks OpenSearch,甚至我還在想,乾脆全部導到 Feedbooks 也不錯





安裝 cURL、Python 和 PycURL @ Ubuntu Server

由於工作用的桌機有防火牆的問題,所以我必須找一台可以連外的 server,接著又發現他提供的 python 並沒有 PycURL,因此我一路從 cURL 裝起,順便紀錄一下。


其實我有 root 權限,只是機器不是我的,少動為妙 XD



  1. 安裝 Python

    • $ wget http://www.python.org/ftp/python/2.6.6/Python-2.6.6.tar.bz2

    • $ tar -xvf Python-2.6.6.tar.bz2

    • $ cd Python-2.6.6

    • $ ./configure ./configure --prefix=/home/user/tarball && make && make install



  2. 安裝 cURL

    • $ wget http://curl.haxx.se/download/curl-7.21.2.tar.bz2

    • $ tar -xvf curl-7.21.2.tar.bz2

    • $ cd curl-7.21.2

    • $ ./configure --prefix=/home/user/tarball --without-ssl && make && make install



  3. 安裝 PycURL

    • $ wget http://pycurl.sourceforge.net/download/pycurl-7.19.0.tar.gz

    • $ tar -xvf pycurl-7.19.0.tar.gz

    • $ cd pycurl-7.19.0

    • $ /home/user/tarball/bin/python setup.py install




正當我以為一切都很美好,跑了程式後蹦出了訊息:


Fatal Python error: pycurl: libcurl link-time version is older than compile-time version


仔細一看,原來系統已有的 curl 是 7.18.2 版本(可以用 curl -V 查看),比我安裝的還要低,因此會出包,原先想要學其他人更改 lib 的位置,可是這樣惡搞下去不就等於用 root 亂搞了嗎,所以最後挑 curl 7.18.2 和 pycurl-7.18.2 的版本來編就好。


再這之前還試過安裝 curl 7.19.0 和 pycurl-7.19.0,但還是一樣的訊息,所以結論?若系統已有 curl 的話(用 which curl 和 curl -V 來判斷跟得知版本),還是偷懶挑跟系統一樣的版本來裝吧。


2010年10月15日 星期五

Stanza - USER AGENT & OPDS Catalog

Stanza 是在 iPod Touch / iPhone / iPad 上,強大的免費電子書軟體,有興趣可以裝一下


然而,有些電子書的供應網站,有提供 OPDS Catalog,但是僅限於 Stanza 去閱讀,真是令人不方便,因此就先了解一下 Stanza 的 User Agent後,就可以去模擬一下,看到那些 OPDS Catalog 囉!


得知 Stanza 的 User Agent 的方式嘛,就是先寫個 CGI ,例如透過 PHP:


@index.php
<?php
file_put_contents( '/tmp/opds' , print_r( $_SERVER , true ) );
?>


接著使用 Stanza > 獲取書籍 > 分享 > 編輯 > 新增上述 CGI 位置,接著瀏覽一下就可以收集到 Stanza 使用的 User Agent 啦!


Stanza/3.0.3 iPhone OS/4.1/iPhone catalog/3.0.3


最後則是透過瀏覽器的一些 plugin ,例如 Firefox & User Agent Switcher,就可以新增一個 user agent,接著在瀏覽某些網頁就會看到神秘的 OPDS Catalog 囉!


2010年10月13日 星期三

opac.ndl.go.jp 日本書籍資料

研究上,如果要取得書籍資料當作測試,並不是每一家擁有資料者都那麼佛心的!特別是沒有任何關係者。慶幸的,国立国会図書館有提供這種服務!


http://opac.ndl.go.jp/ 網站上,可以透過關鍵字去查詢書籍,查詢完後,旁邊有個小按鈕 "Download" ,之後就可以把這次查詢的資料其 metadata 下載回來。其格式是 tab-delimited format (tsv) 並且最多讓你下載 200 筆資料。


以 Python 語法來處理下載下來的 tsv 檔案:


fd = codecs.open( target_file , 'rb' , 'Shift-JIS' )
rawitems = []
while True:
raw = fd.readline()
if raw is None or raw == '' :
    break
else:
    rawitems.append( raw.split( '\t' ) )
fd.close()

RE_ISBN = re.compile( '[0-9xX\-]{10,}' )

for rawdata in rawitems:

    ISBN = None
    TITLE = None
    PUBLISHER = None
    NOTE = None

    # ISBN
    if len(rawdata) < 17:
        continue
    ISBN = rawdata[16]
    ISBN = re.findall( RE_ISBN , ISBN )
    if len(ISBN) < 1 :
        continue
    ISBN = ISBN[0].replace('-', '')

    # TITLE
    if len(rawdata) < 2:
        continue
    TITLE = rawdata[1]

    # PUBLISHER
    if len(rawdata) < 9:
        continue
    PUBLISHER = rawdata[8]

    if len(rawdata) >= 16 :
        NOTE = rawdata[15]

    #
    # do something ...
    # ...
    
    return


[Python] 使用 cURL (PycURL)

以前常用 PHP cURL 惡搞,最近常寫 Python,終於又碰到了使用 cURL 的時刻了,自己隨意摸索一下筆記。


關於 PycURL 的使用,對照文件:



如此如此,這般這般,心得:



  • 所有 "CURLOPT_" 開頭的設定,在 Python 改用 "pycurl.",例如 CURLOPT_URL 改成 pycurl.URL

  • 以前用 PHP 時,可以 curl_setopt( $ch , CURLOPT_RETURNTRANSFER , true ); 的方式,就可以透過 $result = curl_exec( $ch ); 把網頁資料存在變數中,現在這邊則是要用 b = StringIO.StringIO()、c.setopt(pycurl.WRITEFUNCTION, b.write) 和 b.getvalue() 方式來取得


簡易的範例:


        import urllib
        import pycurl
        import StringIO

        url = 'target_url'
        c = pycurl.Curl()
        c.setopt( pycurl.URL , url )
        c.setopt( pycurl.FOLLOWLOCATION , True )

        c.setopt( pycurl.COOKIEFILE , '/tmp/pycurl' )
        c.setopt( pycurl.COOKIEJAR , '/tmp/pycurl' )
     
        b = StringIO.StringIO()
        c.setopt(pycurl.WRITEFUNCTION, b.write)

        c.perform()

        #print b.getvalue()
        r = b.getvalue()
        b.close()
        b = StringIO.StringIO()
        c.setopt(pycurl.WRITEFUNCTION, b.write)


        check = re.findall( re.compile( '(<form(.*?)</form>)' , flags=(re.IGNORECASE|re.DOTALL) ) , r );
        if len(check) < 1 :
                print "No FORM DATA"
                return

        r = check[0][1]
        out = {}
        for sub_info in re.findall( re.compile( '<input(.*?)(name=[\'"]{0,1}(.*?)[\'"]{0,1}[\s]+value=[\'"]{0,1}(.*?)[\'"]{0,1}[\s>]|value=[\'"]{0,1}(.*?)[\'"]{0,1}[\s]+name=[\'"]{0,1}(.*?)[\'"]{0,1}[\s>])' , flags=re.IGNORECASE ) , r ):
                if len(sub_info) != 6 :
                        continue
                if sub_info[2] != '':
                        out[ sub_info[2] ] = sub_info[3]
                elif sub_info[5] != '':
                        out[ sub_info[5] ] = sub_info[4]

        for key in out :
                print "\t",key,":\t",out[key]

        url = 'target_form_action_url'
        c.setopt( pycurl.URL , url )
        c.setopt( pycurl.FOLLOWLOCATION , True )
        c.setopt( pycurl.POST , True )
        c.setopt( pycurl.POSTFIELDS , urllib.urlencode(out) )

        c.perform()

        #print b.getvalue()
        r = b.getvalue()
        b.close()

        f = open( target_file , 'wb' )
        f.write( r )
        f.close()


這個範例是到某個網頁收集 form 表格中的 input 欄位資料,並且使用 cookie ,最後則是產生 POST 並把結果存在檔案中。