發表文章

目前顯示的是 一月, 2015的文章

取得執行檔所在的目錄名稱

有時自己寫的程式, 會在執行檔所在的位置放其它資源檔或設定檔。如果偷懶直接用相對路徑讀檔, 可能因為先前有用 chdir 切換 process 所在的位置, 而讀不到檔案。保險見起, 可以改用執行檔所在的位置作為起始路徑來讀檔。這裡有取得執行檔所在的目錄的程式碼, 重點是利用 /proc/self/exe 找出產生目前 process 的執行檔的路徑。平時需要寫 shell script 也可用同樣方法取得路徑2015/02/06 更新原本寫用 /proc/PID/exe, 經 Kito Cheng 提醒, 改為 /proc/self/exe 更方便。

The Python Standard Library By Example

看到不錯的書: The Python Standard Library By Example, Table of Contents 有不少有用的關鍵字,知道要做什麼事的時候,可以用什麼內建模組。另外, 這裡有書上附的範例碼, 玩玩小程式比看文件快上手。

抓網站內容和使用 lxml.html 讀取 DOM 內容

lxml 功能強大, 不過提供太多 API, 不太容易在官網找資料 (或是我太沒耐性吧...)。記錄一下抓網站取內容常用的 code snippet: 下載網頁內容轉成 lxml.html 的 Element objectimport sys import requests import lxml.html DEBUG = False def get_web_content(link): if not link: return None, lxml.html.fromstring(u'<html></html>') try: r = requests.get(link) try: content = r.content.decode('UTF-8') except UnicodeDecodeError, ude: if DEBUG: msg = ( 'The content is not in UTF-8 (ude=%s). ' 'Try ISO-8859-1 instead.\n' % ude ) sys.stderr.write(msg) # Try another encoding. If fail, just let it fail. content = r.content.decode('ISO-8859-1') if DEBUG: sys.stderr.write('Get content of link %s: %s\n' % (link, content[:50])) return r.status_code, lxml.html.fromstring(content) except Exception, e: …

python multiprocessing 小記

因為 CPython 有 GIL 的緣故, 需要提升 CPU 效率時, 不會用 multi-thread, 會改用 multi-process。內建模組 multiprocessing 提供許多好東西, 實作 multi-process 簡單許多。習慣用 multiprocessing 後,有時不是 CPU bound 而是 I/O bound, 我還是用 multiprocessing。反正....不是 CPU bound 的話, 多耗 CPU 也無所謂。 之前寫 crawling 的程式,為了增加同時抓網頁的數量,就用 multiprocessing 加速 [*1]。以下是兩個例子: 取出台北熱門電影的 IMDB 分數 (使用 Pool)取出 Google Play 相似 app 的分數分佈 (沒用 Pool, 有用 Lock。Btw, Pool 感覺沒有很方便) 從例子裡找片段程式碼來用比看文件快。這裡記錄一下相關心得: 若要讓不同 process 共享資料,需要用 multiprocessing 訂的物件, 有含 list, dict 等,單一物件 (如 int, float, str) 則是用 Value 指定 typecode, 如: shared_integer = multiprocessing.Value('i', 0) 使用 shared data 會有 race condition, 要用 Lock 保護,不然就直接用 Queue 或 Pipe。還有 EventSemaphore 等物件,要作比較複雜的機制時,可以拿來用。 有提供跨機器的 multi-processing, 有需要再來細看。 程式架構照 producer-consumer 的方式寫比較容易, 也就是各個 process 共用 Queue, 然後 producer 用 blocking put, consumer 用 blocking get, 另有一個 main process 監控情況, 確保程式會結束 (這大概是最麻煩的地方)。 注意量大的時候 put 會因 queue full 卡住,所以不能在 main process 用 blocking put。即使很容易填入 Queue 的初始資料,用另外的 process 填入初始資料比較保險, 因…

用 jQuery load 跨 HTML 檔使用重覆的 HTML 內容

寫網頁到一定規模後, 會抽出重覆的 JavaScript 到獨立的 JavaScript 檔, 再用 <script src="FILE.js"></script> 載入, 以供不同 HTML 使用; CSS 則是用 <link rel="stylesheet" type="text/css" href="FILE.css"> 載入外部檔案。那 HTML 怎麼辦? 若是會寫 PHP 的人, 會使用 include 載入重覆使用的 HTML; 用 Python/Ruby/Perl 寫 CGI 的話, 會搭配 web framework 內 template language 的語法, 所以也沒問題。但若是只會寫 HTML + CSS + JavaScript 的人該怎麼辦? 查了一下, 發覺用 jQuery load 可以輕易做到 [*1]。唯一的問題是, 在本機電腦實作, 用瀏覽器開啟本機檔案後會發現行不通。有如下的 JavaScript 錯誤訊息:XMLHttpRequest cannot load file:///C:/.../FILE.html. Cross origin requests are only supported for HTTP. 這是因為瀏覽器基於安全考量, 禁止 JavaScript 讀取本機檔案。 解套方式是在本機跑 web server, 透過 http (而不是 file://) 讀取檔案。 於是問題變成: 如何讓這類不擅長程式設計或系統管理的人, 能在自己的電腦測試 jQuery load? 畢竟會有這種需求的人, 大概也不擅長在 Windows 或 Mac 裝 apache2 或 lighttpd。從這裡看到有人推薦用 mongoose。 作法如下: 下載 mongoose 執行檔 執行檔放在網頁目錄下 執行它就可以連到 port 8080 看到結果 (即連往 http://localhost:8080/ 瀏覽目錄下的網頁)。也可參考官網的教學了解更多設定。 要關掉 mongoose 的話, 可以從右下角的系統選單找到 mongoose 的圖示, 按右鍵再選 Exit。或從系統管理員直接結束它。 Bt…

網頁顯示彈出畫面同時禁止捲動主畫面的技巧

作法應該有相當多種,這裡提兩種我從一些網站中觀察到的作法。 設定 body 為 overflow:hidden線上觀看的例子完整原始碼 準備兩個 div, 一個是 main content (id=main), 一個是 pop-up (彈出畫面), 平常隱藏 pop-up, 要顯示 pop-up 時,設 body 的 overflow: hidden,並顯示 pop-up。這樣主頁面就不能捲了。 關掉 pop-up 時再設 body 的 overflow: visible (預設值), 主頁面就可以捲了。 程式碼像這樣:var popup = document.getElementById('popup'); function show_popup() { popup.style.display = 'block'; document.body.style.overflow = 'hidden'; } function close_popup() { popup.style.display = 'none'; document.body.style.overflow = 'visible'; } 優點: 簡單,很多網站這麼作 缺點: 部份瀏覽器不支援, 例如 iOS 6對 main content 為 position:fixed線上觀看的例子 (我有修改 #popup 的 height, 讓它可以在這網站正常顯示,其餘和下行的原始碼一樣)完整原始碼 這個作法比較複雜,是拆解 facebook 彈出照片的頁面得知的。 準備兩個 div, 一個是 main content (id=main), 一個是 pop-up (彈出畫面), 平常隱藏 pop-up, 要顯示 pop-up 時,設 main content 的 position: fixed,並顯示 pop-up。這樣主頁面就不能捲了。但是因為 scroll offset 歸零 (content height 改變的副作用), 要自己維護 scroll offset (後述)。 這個作法與上個作法有幾點差異: 網頁主動管理頁面大小, 造成主頁面不能捲; 上個作法是設 body 為 overflow: …

Python 處理 UTF-16 的 CSV

Python 內建的 csv 模組預設無法處理 UTF-16, 直接讀的話會出現Error: line contains NULL byte 自行轉換編碼成 UTF-8 即可,作法如下: import codecs import csv # 用 codecs 解碼 utf-16 為 unicode object f = codecs.open(filename, 'rU', 'utf-16') # 再轉回 utf-8 給 csv.reader 用 cr = csv.reader(line.encode('utf-8') for line in lines) for row in cr: # row 的內容就是 CSV parse 完的結果 或是先用 iconv 轉檔, 再用 Python csv 模組處理亦可: $ iconv -f utf-16 -t utf-8 file_in_utf16 > file_in_utf8 備註: Python csv 模組不接受 unicode 的輸入,若來源不是檔案,也要記得轉成 utf-8 再傳入 csv.reader()

自動統計 app 在 Google Play 內各版本的的分數和常見問題

最近想統計 app 在 Google Play 上各版的分數,了解最近版本是否比較不穩定。如果有問題的話,統計一下問題分成那幾類。透過 Google Play 觀看 review,如果沒有邊看邊統計分類,看過只會有個模糊印象,不知道那類問題比較嚴重。但是.......又懶得邊看邊記。 為了自動分類 reviews, 首先要抓下 Google Play 上的 review。幸好 Google Play 存放 reviews 和其它資料在 Google Cloud Storage, 並提供工具 gsutil 可以從命令列取出 Google Cloud Storage 的資料, 作起來並不費工。官方說明在這裡的 "Export ratings and reviews"。摘要步驟如下: 1. Mac 或 Linux 下載解開 gsutil: https://cloud.google.com/storage/docs/gsutil_install 2. 更新、設定 gsutil: $ export PATH=$PATH:/path/to/gsutil $ gsutil update $ gsutil config 其中 gsutil config 會認證帳號, 照著作即可。最後要求輸入 project id 的時候, 輸入 app package name,例如 com.mycompany.myapp。相關說明見這裡。 3. 下載 review 從 Google Play App Console -> App -> Ratings & Reviews 最下方得知 reviews 存放的位置 Ratings and reviews are also available for programmatic access through Google Cloud Storage and the gsutil tool. Your data, updated daily, is stored in this private bucket: pubsite_prod_rev_NUMBER 接著用 gsutil 列出目錄下的檔案$ gsutil ls gs://pubsite_prod_rev_NUMBER 再來就簡單了,gs…

線上刷卡流程的簡介

同事介紹關於線上刷卡流程的介紹文章, 滿淺顯易懂的, 改天有需要再複習一下:Credit Card Processing Diagram: How Credit Card Processing Works - Authorize.Netprimer:the_pieces [FoxyCart! Wiki

git 常用指令

有鑑於一兩年沒用 hg 就忘得差不多了, 還是備忘一下目前覺得好用的 git 指令, 比較長的就加到 alias 裡了。 搜尋全部內容包含 diff 中出現過的字: git log -G ( -S 速度較快, 但可能會漏東西, 見 "git log -S" does not show all commits 的說明 ) 顯示所有 branch: git log --graph --branches --decorate --oneline 顯示 utf-16 的字串: 讓 git diff 顯示 utf-16 (或其它binary) 檔案的差異 還沒實際用過, 先記著: 從目前的 git repository 裡切出一個子目錄成新的 git repository 並保留歷史記錄: Splitting a subfolder out into a new repository ( 聽 Wens 說的 )