Mining the Social Web – Example 1-3

實作這個範例時,出現錯誤:TwitterHTTPError: Twitter sent status 404 for URL: trends.json using parameters: ()

有人回報給作者:Example 1-3 fails with 404 errors,也有人去 StackOverflow 上問:Problem with Twitter package by sixohsix,可是都沒有解決問題的答案。

答案在twitter API -GET trends上:因為deprecated了。要改用GET trends/:woeid,也就是像這樣的網址 http://api.twitter.com/1/trends/1.json 才可以取得。

換言之,程式要改為:
[python]import twitter
t=twitter.Twitter(api_version=’1′)
t.trends(id=1)
[/python]

Windows 上的 python + virtualenv + django

安裝上並不難,只是最後有卡到一個問題,特別提出來分享一下。

  1. 下載python 2.7安裝檔,然後安裝
  2. 下載setuptools安裝檔,然後安裝
  3. 打開命令提示字元,先 cd /d c:\python27\scripts ,再 easy_install virtualenv,你公司有 proxy 的話,記得先 set http_proxy=http://your_proxy:port
  4. 安裝好 virtualenv 以後,就可以去創建環境了,假設你的環境都在 c:\envs,那就先 cd /d c:\envs ,再 virtualenv –no-site-packages myenv ,這樣就建好環境了
  5. 啟動你的環境,要先 cd /d c:\envs\myenv ,再輸入 scripts\activate 。Linux 下的activate 是放在 bin 下,這是比較大的不同。
  6. 安裝 django:scripts\pip install django
  7. 使用 django 指令:scripts\django-admin.py startproject myproject ,嗶嗶嗶,卡住了。

哈,我就卡在這裡。django-admin.py 會說找不到 django.core ,我苦思了好久,終於才想到,Windows 下是不鳥 python script 第1行的 sha-bang 的啊,所以雖然 django-admin.py 的第1行指定了說要用 c:\envs\myenv\scripts\python.exe 來處理,可是實際上卻是 .py 註冊在 registry 裡的 c:\python27\python.exe 在處理。因此會有找不到 django.core 的情況,改用 scripts\python scripts\django-admin.py 就可以順利找到 django.core 了。

Python 2 與 3 之字串與檔案

Python 3 裡,很多常用的 package 名稱都變更了,這個倒還好,在 python 2.x 的文件裡,都已經可以看到說 3 的時候,名稱會是什麼,以及要注意什麼,甚至也有 2to3 的工具來輔助轉換。
最近遇到比較麻煩的是字串與檔案的處理,Python 3 裡的字串都是以 unicode 處理,好處當然是不用轉來轉去了,比較麻煩就是讀取檔案跟寫檔案的時候。我的程式有同時用到 subprocess、urllib/urllib2與一般檔案操作,以下是整理:

  1. 進行 subprocess pipe 操作時,讀出時,都是 bytes
  2. 使用 urllib/urllib2 讀取時,都是 bytes
  3. 使用一般檔案操作,沒特別指定的話,檔案編碼會以你當前的環境編碼來讀取,預定是讀取文字檔。

所以在讀取時,為了後續能用一樣的邏輯來讀取,我統一以 binary 來讀取,避掉 encoding 問題(對於 python 3 在 binary mode時,也能正確分行、tokenize這件事上,真的是深感佩服)。是說剛好之後也不需要做精確的內容判斷,所以也不用硬轉成 string(unicode),在 python3 時,都以 bytes 存在。在 python 2,讀出來就都是一般的 string (無 unicode),不是 bytes。
寫入時,也儘量使用 bytes 去寫入,避免encoding轉來轉去的問題。

distutils bdist_rpm

CentOS 5.6 裡的MySQL-python是1.2.1,在用django的時候,它給我吐出需要MySQL-python-1.2.1p2 以後的版本才行。
囧掉,這樣不就要抓MySQL-python新版來包,好像會很麻煩說。上MySQL-python官網去看,發現維護者很有意思,他在Amazon上的wish list裡都是大力水手的DVD,如果要贊助他的話,不妨幫他買DVD,Amazon會送到他家裡去。離題了,網站上最新的版本是1.2.3,就先抓下來吧。
python的moodule照慣例都有 setup.py,就想說打 python setup.py –help-commands 來看看,結果喜出望外,裏面有 bdist_rpm 的指令,這表示我可以直接打 python setup.py bdist_rpm 就可以建出 rpm 了。
於是馬上就來 build,首先裝上 mysql-devel,然後執行 python setup.py bdist_rpm,看起來很順利,但最後卻發現沒有 MANIFEST 檔案,而導致失敗。看了一下檔案,發現有 MANIFEST.in,再看一下裏面,沒有什麼要替換的字串 (一般來說,副檔名是 .in 的,都會需要用 sed 來替換一些字串),就直接 cp MANIFEST.in MANIFEST 補上,再重新執行 python setup.py bdist_rpm 就大功告成了。rpm 會放在 dist 目錄下,收工。

django-nonrel之二

另外一個方法是直接參考這篇 4 things to know for NoSQL Django coders的Setting up the environment,裏面有提供一個 zip 連結,下載以後解開,基本上就可以了。這個 zip 提供的 django 是 1.3 beta1。
我遇到的問題是在執行 python manage.py runserver 時所發生的,錯誤訊息說需要 sass,這個工具是一個輔助 css 撰寫的工具,但 10.04 裡所提供的 sass 是 2.x 版的,而 django 裡的 mediagenerator 需要 3.x 的版本。上網找了一下,果然有人遇到,解法是利用 rubygems 來安裝 (Install SASS on Ubuntu 10.04)。
我稍做了一點更動,因為我不想安裝到 user home 裡,所以使用的指令依序是:

  1. sudo apt-get install rubygems1.8 ruby
  2. sudo gem install haml-edge –no-user-install
  3. sudo ln -s /var/lib/gems/1.8/gems/haml-edge-3.1.79/bin/sass /usr/local/bin/sass
  4. sudo ln -s /var/lib/gems/1.8/gems/haml-edge-3.1.79/bin/sass-convert /usr/local/bin/sass-convert

後2個步驟是作 symbolic link,讓 sass 指令能在 PATH 裡找到。最後是預設網頁的問題,這個就請參考 django tutorial 去修改 urls.py 並在 templates 目錄補上預設網頁就可以了。
有點混亂,我試著參考這個 zip 檔案去設定上一篇所開的專案,但 mediagenerator 就是跑不起來。另外就是試著用 tutorial 的 poll 例子去加 admin,可是卻吐 backend 不支援 max 這個方法,研判應該是 admin module內部處理問題。

django-nonrel

Google AppEngine(之後簡稱GAE)原本就有把django包進去,只是資料庫的使用上,需要自己處理,原本只支援relational database。後來就有人去補這一塊,名字就改稱django-nonrel。GAE官方的文件介紹django時,就直接介紹了這個project:Running Pure Django Projects on Google App Engine
django-nonrel 的官方網頁在:Django-nonrel – NoSQL support for Django,坦白說,從官方網頁我沒找到很清楚的Installation說明,後來才在這一篇Native Django on App Engine裡看到。一般django建立網站的方法是使用django-admin.py startproject your_project來建立,接著再進入專案目錄,使用python manage.py 去做管理。但django-norel建立網站的方法稍微不一樣,是直接checkout一份空的專案骨架來用,而不是使用django-admin.py來建立。步驟如下:

  1. 使用mercurial(hg)去clone以下源碼,我統一都clone到~/hg 下:
    • hg clone https://bitbucket.org/wkornewald/djangoappengine
    • hg clone https://bitbucket.org/wkornewald/django-nonrel
    • hg clone https://bitbucket.org/wkornewald/django-testapp
    • hg clone https://bitbucket.org/wkornewald/djangotoolbox
    • hg clone https://bitbucket.org/wkornewald/django-dbindexer
    • hg clone https://bitbucket.org/twanschik/django-autoload
    • hg clone https://bitbucket.org/wkornewald/django-mediagenerator

    ,依序說明:djangoappengine、django-nonrel、djangotoolbox主要是針對GAE作補完,django-testapp是專案的骨架,dbindexer是實作資料庫處理的底層,autoload負責自動載入library,django-mediagenerator則是可以對css/js做壓縮、加速的library,可有可無。

  2. 複製django-testapp並更名,假設為mysite
  3. 進入mysite目錄下,然後去做symbolic link:
    • ln -s ~/hg/django-nonrel/django
    • ln -s ~/hg/djangoappengine
    • ln -s ~/hg/djangotoolbox/djangotoolbox
    • ln -s ~/hg/django-nonrel/django
    • ln -s ~/hg/django-dbindexer/dbindexer
    • ln -s ~/hg/django-autoload/autoload/
    • ln -s ~/hg/django-mediagenerator/mediagenerator
  4. 大功告成,輸入python manage.py runserver 就可以啟動web server,試著瀏覽 http://localhost:8000 看看吧。如果你想要改用別的 port,跟原來的django不太一樣的,你需要用 python manage.py runserver 0.0.0.0:10080 才可以,原來的 django 可以用 python manage.py runserver 10080 就搞定。

會想試試這個,主要還是因為GAEO後來的開發整個停掉,想說之後也想玩玩django,就乾脆用django-nonrel,以後也對django比較容易上手。

GAE應用程式在哪裡執行

判斷Google Appengine應用程式是在GAE服務上或是本地端,可以這樣用:

from google.appengine.api import conf
app_version, current_config_version, development = conf._inspect_environment()
if development:
print("development")
else:
print("production")

pixnetalbummaker(1)

我環境是ubuntu 10.04,依照GAEO文件,以easy_install安裝gaeo,可以順利安裝。
但在產生專案時,卻會出現:”OSError: [Errno 2] No such file or directory: ‘/usr/local/lib/python2.6/dist-packages/gaeo-0.5-py2.6.egg/oildrum/static'” 的錯誤。
此錯誤應該與easy_install的EGG有關係,原因是因為少檔案,下載官方的 zip 檔案可以發現以 easy_install 安裝以後的 oildrum 跟 zip 裡的 oildrum 檔案數目並不一樣,也就是說少安裝了。解決方法也很簡單,就把 zip 檔案裡的 oildrum 複製過去即可。

plurklib小記之二

因為要取得噗的所有回應,所以我參考dotplurk的getAllResponses()來取,基本上是用Plurk API 的 getResponses。只是,dotplurk應該是誤解了 getResponses 的用法。他的作法是假定getResponses一次傳回五筆,所以有抓到回應的話,就再把offset累加5,然後呼叫getResponses,就這樣重複,直到抓沒有response為止。但是getResponses並不是一次傳回五筆,而是不定筆數,因此offset的累加我改為累加這次取回的responses筆數,於是這樣就對了。
另外,plurkSearch 傳回的 plurk,裏面有 response_seen 跟 response_count 欄位,我想應該也可以利用這兩個欄位事先得知這個噗有多少回應,來決定怎麼去取responses,只是我就沒有去利用了,畢竟我自己的噗浪回應數都沒超過100(目前最高樓應該還是酪梨壽司那一噗吧,記得有上萬)。除了跟 response 有關的值以後,plurk 裡還有 friends 這欄位,表示參與 response 的人有哪些,從這裡就可以取出 user_id 對應的 display_name,而不需要再呼叫 getPublicProfile 去取得,這樣可以少掉很多往返網路的時間。
應該不會再有下篇了,因為我的備份噗浪到blogger的程式完工了。

plurklib小記

plurklibofficial Plurk API的python實作。
原始碼只有兩個檔案,readme.py就是每個function的使用方法,plurklib.py則是主要的實作。
我主要用到 plurkSearch,plurkSearch 傳回的是一個 dictionary,所以就可以用 keys() 去看有哪些 key,大致上有 has_more、plurks、last_offset。has_more 可以用來判斷還有沒有更多的搜尋結果,last_offset 則是可以在下次 plurkSearch 時帶入,表示要搜索更之前的紀錄。plurks 則是一個 list,裏面每個元素則又是 dictionary。完全不使用 class 的好處是,用 python 基礎型別就可以搞定,不需要再多的檔案,其實也算是作者偷懶吧,因為內部是用 json 來解析結果,而 json 解出來的結果就是 dictionary。
再來就是日期,日期的解析,本來已經打算要用 datetime.strptime 來硬轉了,但還好在 StackOverflow: Converting string into datetime 看到可以用 dateutil.parser 來轉換,這樣就輕鬆省事多了。