剛泡好咖啡。對著電腦,路上無車無人,夜深無聲。沉默太久,傷害也太重,我想該是和大家清楚說幾句話的時候。。
模仿正確的Header
現在 google analytics, mixpanel 各種工具的盛行,在進入網站時,必須先好好裝扮自己的身份,儘管可能開發者開的是 arch、freebsd 等os,一律將自己偽裝成一個正常的windows客戶。有些網站甚至會檢查header中的referer欄位,避免不必要的資源浪費:在 python 中很簡單,使用我們只需要準備好一個正常的header dict,使用發request方法時,當成一個正常的參數傳進去就可以。抓一個數據的任務就是一個 function
通常我會替爬蟲命名為他所要抓的資料名稱,舉例如果是抓台指期日線,那就是 txf_daily,傳進去的參數為日期,雖然有人建議 function 最好都是以動詞當作開頭,也就是 get_txf_daily 。這樣作的好處就是,我們就能製作 high-order function,有時候在 a 狀況的時候,我們需要調動這三支爬蟲,在 b 狀況的時候需要調動另外三支爬蟲,在這樣子的結構下,我們就能把我們的function當作參數傳進去另外的handler function之中,完成日常的任務。爬蟲的結構:
在這個function裡面,通常可以模組化經由三個邏輯層次的處理:
- 準備http request 所需參數,此時你可能需要把日期從西元轉換成中華民國(證交所的api愛來這套),還有剛剛所說的header
- 取得 server 上的 response 之後找到含有資訊的 dom 取出 raw data
- 將raw data轉成自己程式所需的資料格式(string, datetime)回傳
避免抓錯,記得assert
證交所網頁經過些許次的網頁改版,會造成所需資訊在不同的時期query,會在不同的位置,甚至每日運行的爬蟲中,要確保未來是否格式沒變,此時我們就需要利用assert,當資料格式或者是資料標題改變時,提醒開發者。善用logger
除了在平常debug之外,當有特殊狀況的時候,可以利用logger,即時提醒自己。info可以提醒當有新數據增加時,error則是警告爬蟲並沒有正常運作。擁有成交日資料則會更如虎添翼
在某些時間作分析或爬蟲時,能明確知道某一天是否有開盤,會讓工作的流程順許多。python有些套件也有提供此服務,可惜驗證的結果並不是很準確。
有時候寫一個api backend會讓效率更加流暢。
以下範例是以抓取證交所三大法人買賣超當作實際舉例:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
from pyquery import PyQuery as pq | |
from util import conv_to_roc | |
def get_institutions_trading_daily(date): | |
# get three major institutions trading: buy and sell separately. | |
roc = conv_to_roc(date) | |
# http://www.twse.com.tw/ch/trading/fund/BFI82U/BFI82U.php | |
url = ('http://www.twse.com.tw/ch/trading/fund/BFI82U/BFI82U.php?' + | |
'input_date={year}/{month}/{day}').format( | |
year=roc.year, | |
month=roc.month, | |
day=roc.day) | |
html = requests.get(url, headers=headers) | |
html = html.content.decode('big5') | |
pqd = pq(html) | |
trs = pqd('tr.basic2[bgcolor="#FFFFFF"]') | |
three_major={} | |
def get_data_title_text(dom): | |
return pq(dom).find('div').eq(0).text() | |
for i in trs: | |
# after 2014/12/01, 自營商多了自行買賣與避險 | |
if get_data_title_text(i) == '自營商(自行買賣)': | |
three_major['dealers_buy'] = pq(i).find('td').eq(1).text() | |
three_major['dealers_sell'] = pq(i).find('td').eq(2).text() | |
if get_data_title_text(i) == '投信': | |
three_major['trustees_buy'] = pq(i).find('td').eq(1).text() | |
three_major['trustees_sell'] = pq(i).find('td').eq(2).text() | |
if get_data_title_text(i).startswith('外資'): | |
three_major['fi_buy'] = pq(i).find('td').eq(1).text() | |
three_major['fi_sell'] = pq(i).find('td').eq(2).text() | |
for k, v in three_major.items(): | |
three_major[k] = int(v.replace(',','')) | |
assert len(three_major) == 6 | |
assert len(trs) == 5 | |
return three_major |
爬蟲的世界博大精深,在此只分享一些基礎心得,希望能拋磚引玉,跟大家多多交流。
0 意見:
張貼留言