顯示具有 Gevent 標籤的文章。 顯示所有文章
顯示具有 Gevent 標籤的文章。 顯示所有文章

2013年3月29日 星期五

活動:Taipei.py 2013 3 月聚會

聚會結束後,走在路上,看到一台機車的安全帽長這樣 !!(Keith 的)



這次由 Tim 發起了「入場先收 50 塊,稍稍補貼一下茶水費」的活動
對於 The Manx 同時提供「人力、場地、器材、餐點」,只能說感謝了 Orz …

#本次聚會照片、投影片皆可至 Taipei.py 的 Meetup 社群 下載



Talk 1: Scrapy - 網路爬蟲框架

講者為在 Tagtoo 工作的 Theon 學長
演講專業而結合範例,讓人能清晰的了解到 Scrapy 此框架的威力
如果熟 XPath 的話,大概真的參數填一填,實作上不用五分鐘就可以寫出爬蟲了!
由於我前陣子有寫過爬 Ptt 的機器人,去擷取備份文章
對比於自己寫的 糟糕 程式,我馬上就能感受到了此一框架的優良架構
雖然我為 XPath 苦手,不過我想現在的瀏覽器都有相關的工具可供協助找到 XPath
之後若有機會,值得一試
另外,對於小型的抓網頁,讀取特定數值的程式
如丟關鍵字給 google,然後抓出搜尋結果的連結 … 這樣的應用
我蠻推薦使用 pyquery 來處理問題
直接使用:d = pq(url='http://google.com/')
接下來就可以使用類似 jquery 的方式存取 html 元素了:d("#hello") …

Talk 2: 先不談 Django,你聽過 Bottle 嗎?

講者 竟然 是我 XD ... 因為沒有辦法自己幫自己的演講給心得文
那我來檢討一下演講準備過程,與附上補充資料
因為近日專案極忙,這次的演講,我一直拖到演講前兩小時才把投影片做完
對我而言有許多第一次:
  • 第一次用 iPad 的 Keynote 做投影片
  • 第一次用 iPad + 轉接線 投影到螢幕
  • 碩論口試後第一次公開演講(當兵的時候倒是主持過很多次莒光園地 …
  • 第一次在社群中分享自己的經驗
我原本自以為可以用閃電秀的密度,快速的用 15 分鐘把該講的都講清楚
但是做出來投影片的品質太差,又沒有演練過 ... 所以就變成了冗長的碎碎念亂講 … 囧rz
對於這一點,我正在深刻的反省中 …

另外,使用 iPad 製作起來的過程雖然算流暢
但是在投影片內要插入超連結,頗有困難,且輸出成 ppt 或 pdf 以後,格式都容易跑掉
之後得多加注意此問題
這次來不及測試 remote 遙控投影片的功能,小可惜
不然就可以帥氣的走來走去了 …



會後補充:

再度推薦一下 gevent 社群的文件:Gevent Tutorial
值得一讀,讀了以後就會發現,在一般的 Python web framework 中
比較難以實作的 Comet 之類的功能,都能透過 gevent 輕易地達成

我記得 Appier 的朋友有問我 Bottle + gevent 能不能夠做效能調教?
(話說,您已經是此搭配的成功案例了:5000 qps …跪求 Bottle 進階演講)
雖然我不知道怎麼做,但我之前查資料時
有看到過 Douban 釋出與 Python 相關的投影片,或許仍可供參考(2011年的):



補充一下,對於 bottle 要提供 http auth basic 的話,可以這樣做:
def check_user(usr, pwd):
    acc_pw = { "user1" : "pw1", "user2" : "pw2" }
    return True if usr in acc_pw and pwd == acc_pw[usr] else False

@bottle.get('/admin/')
@bottle.auth_basic(check_user)
def test():
    pass
當然, auth_basic 的參數要直接塞 lambda 也是 OK 的
但是不建議用這個當會員系統啊 XDDDD

最後,至於為什麼我講的是 Bottle、用的是 Pyramid、大多數情況推薦的卻是 Flask 
這個傷心的問題就不要再問我了 囧rz  


PS. 這次演講後與許多朋友交換名片,聊: Web 框架、Testing、用數學變魔術的經驗 … 真的有 Level Up 的感覺!
您若也想來個常規或是閃電秀的演講,可以先加入 Taipei.py 的社群,然後直接找 Tim, Keith (或我)報名!

2013年1月8日 星期二

心得:檢索 PTT 的資料


我所撰寫的一個小玩具 =口=

前言


近期因為新專案的關係,需要嘗試去分析 PTT 特定看板的資訊
於是我陸陸續續撰寫了一些小程式:例如「推文分析器」、「發 P 幣機」、「PTT 尋寶機」
本文將針對「PTT 尋寶機」的開發,分享自己的心得! 以下先簡要的列出一些我對 PTT 的觀察:
  • PTT 的看板與文章,其實都有對應的 Web 網頁 (兩者之間有時間上的誤差)
  • 每篇文章的 Web 網頁中 <pre> … </pre> 之間的內容就是文章原文
  • 每篇文章的 Web Url 都不重複
  • PTT 的 Web 介面,可接受 1~2 秒間隔的 query 頻率(我沒有 try 到底線)
  • PTT 的看板有文章數限制,對應到 Web 網頁的話,大約有 900 頁左右(頁數或變動)
  • 透過 PTT 的 Web 介面連到已刪除的文章時,伺服器會回噴 404
  • PTT 上的控碼跑到 Web 網頁會呈現亂碼,壞掉!
  • 因為有「修文」的情況,所以文章的內文格式會「非、常、不、固、定」

心得


而在製作 「PTT 尋寶機」的實務上,我的心得為:
  • 我採取透過 Web 介面檢索文章,並沒有使用 telnetlib 透過 telnet 進行檢索(懶惰!)
  • 我並沒有使用 Scrapy 來協助抓取文章,而選擇自幹
    • 時間有點趕,沒空玩新玩具了 Orz
    • 加上我之前其實有寫過一些 Checkers 去鎖定交易文 … (爆!)
  • 推薦使用老字號的 httplib2 … 雖然我覺得他也有些小問題 Orz
    • 如果是抓取一般「正常的英文」網頁,其實我推薦使用 pyquery,支援直接填入 Url 當參數,然後就可以使用類似 jquery 的語法直接取得內容,方便度最高
    • 如果是抓取一般「正常的各國」網頁,其實 requests 寫起來很順手,讀取抓到的值時還會根據 header 自動做 decode 的動作
    • 我會建議使用 httplib2 是因為 PTT 的 Web 網頁編碼為 Big-5 ,且可能包含一些壞掉的控碼字元。因此,無論在做 decode 或 encode 時,都必須要手動加上 "ignore" 的選項,不然一遇到那些壞掉的字元就會噴出 exception … 。而 pyquery, requests 在使用上較為不方便(恩 … 後者也是支援讀取 socket 的 raw data 啦 … ),所以我就繼續使用 httplib2 了。( 我猜測 Scrapy 應該會對這種包含壞掉的字元的資料來源有處理的函式?)
  • 對於 parse data 而言:
    • pyquery 很方便,一句話就可以從網頁中抓出文章內容:
      • article = d("div#mainContent div pre").text() #possible be None
    • 對於之後文章的 parsing 我採用「硬幹」 + 「regular expressions」,其實如果後者強的話,就一切都沒問題了 …
  • 對於資料庫文章與 PTT Web 介面文章的同步而言,我採用懶人政策:
    • 每天看看最近 100 篇文章有沒有變動
    • 當有人要下載指定文章時,我才會將該文章同步到最新狀態

補充


資料庫我使用 mongodb,因為我常常亂改欄位(攤手),反正就一個極簡單 collection 而已
我並沒有使用專業檢索用的套件去分析文章,抓出關鍵字等等
我僅只是將資料庫內的文章做一些社交上的簡單統計
然後開了 nginx + gevent + bottle 的簡單組合提供 Web 介面
就完成小玩具了!(其實迴響還不錯 XD)

有趣(發人省思?)的社交分析

過程中,技術困難點大概還是在抓資料這一件事情
雖然我前端也卡了不少時間 … ( 囧rz 我不會寫前端啊啊啊
我是用 google 寫的啊
效能的話,我則是完全沒有優化 XDDDD
玩具的目的很簡單,就只是協助板友備份文章、以及提供查詢自己的資料
以使用率來看,不會有讓伺服器有什麼負擔的可能性
兩天的使用情況是不重複訪客 800 人瀏覽(畢竟是耳機、音響還算小眾市場)
總之,寫個小玩具,能讓我多摸到一些 python 的 module 及被強迫摸前端的東西
然後又能創造出一些價值給板友、鄉民
也算是皆大歡喜了!

新版的個資法實在非常嚴厲
各位如果有撰寫相關程式請務必小心 Orz
雖然我自認此服務,不營利、不為蒐集特定對象而寫且純粹出於善意
但是我還是願意提供反檢索功能 (目前是沒有人跟我說他不要被檢索啦 … )
歡迎有興趣的大大與我一起交流相關技術 ~~

-----------------------------------------------------------------
2014.05.28 本文補充說明:

由於 ptt 的 web 版在 2013 年有多次的改版
所以本文內容已經不適用現在的情況
只能當做是一個記錄

目前 ptt 的 web 版已經是輸出 utf8 編碼的內容
且作者、標題、推文等等資訊都已經被存放在特定的 xpath 路徑之內
所以可以用  pyquery 等套件,用類似 jquery 的方式輕鬆取得內容

又,上述說明了這麼多
其實強者我學長 c3h3 已寫好 crawler 且 open source
需要的朋友請取用!

https://github.com/c3h3/PlaYnlp-Corpus/tree/master/crawlers/ptt_crawler


2012年3月13日 星期二

筆記:[Gevent + Bottle] How to detect client disconnection

已使用了 bottle 這一個小巧輕便的 framework 一陣子
加上了 gevent 提供的 pywsgi server 功能之後
算是一定程度解決了想實作出的long-polling的功能
程式結構可以不用有太大的變更,也不用過度擔心 io-blocking 的問題


不過前一陣子卻苦於無法得知 client 與 server 之間的連線是否已經中斷
翻閱 api 文件,皆無法找到相關敘述
甚至還找到有人寫了一個 test-wsgi-disconnect 的專案
來說明gevent好像還不行 ... 囧rz


儘管如此
自己經過土法煉鋼還是發現其實只要直接送資料出去
就可以知道連線是否還存在
但是這樣的作法,實在有點小蠢
無奈之下,還是決定爬一下 bottle.py 以及 pywsgi.py 的 code 
了不起就乖乖從 socket 面解決問題
爬 code 過程中,意外發現了這個 solution




之後我 trace pywsgi.py 後發現有這麼一行:

514 env['wsgi.input'] = self.wsgi_input

因此一切就迎刃而解了:


solution here:

 58     import select
 59     socket = bottle.request["wsgi.input"].rfile._sock
 60     time.sleep(10)
 61     r, w, e = select.select([socket],[],[socket], 0)
 62     if r or w:
 63         print "detect disconnect"
 64     else:
 65         print "not detect"

     Done !!


#2012.09.03 補充:
如果在 59  行之前使用過 bottle.request.body.buf 類似的方法來讀取 HTTP POST 的資訊
那麼 59 行就有可能出現錯誤(無 rfile 此屬性)
原因我推測應該是因為 bottle 的 framework 順手拿掉了不必要的屬性