利用程式從台灣證券交易所-基本市況報導網站讀取即時股價

台灣證券交易所-基本市況報導網站提供即時的股價資訊,如果是要查訊特定股票代號的即時股價,可以查詢 http://mis.twse.com.tw/stock/fibest.jsp?stock=6230,網址最後的stock=就是所要查詢的代號,但是透過程式則是要進一步,先研究網站提供的jsp網頁,需要送出哪些query,來模擬網頁送出的request,才能取得我們想要的資訊,最近基本市況網站又做了更新,所以需要多了一些迂迴的方式才能取得 (2017/1/9~2017/1/13)。

Update: 2017/1/16
沒想到才過了一週,取得股價又回復原來的方式,不需要再做還原資料的動作,這邊文章就當作參考了

1 取得Cookie

/stock/fibest.jsp?stock=5269

/stock/api/getSTKInfo.jsp?ex_ch=tse_5269.tw&json=1&delay=0&_=1484040519551

Update: 2017/1/16
/stock/api/getStockInfo.jsp?ex_ch=tse_5269.tw&json=1&delay=0&_=1484040519551

觀察web browser,這兩個request是跟取得json資料必須要送的request,而送到第二個request取得json資料之前,必須先要取得cookie,而取得cookie需要在第一個request的response中找到Set-Cookie的header,並將內容設成Cookie header帶在第二個request中。

2 取得即時股票資訊

/stock/api/getSTKInfo.jsp?ex_ch=tse_5269.tw&json=1&delay=0&_=1484040519551

Update: 2017/1/16
/stock/api/getStockInfo.jsp?ex_ch=tse_5269.tw&json=1&delay=0&_=1484040519551

送出這個request後,我們會得到json的資料,然而我們得到的資料,是已經先經過一些資料混亂的步驟,所以裡面有還要再經過還原的步驟

3 還原原始資料

從2017/1/9開始,抓回來的json數值,有經過多一層的處理,讓資料無法直接讀取,key的部分經過置換,值的部分多了一些多餘的隨機字串需要消除,才能得到正確的值

舉例來說,從getSTKInfo.jsp抓回來的原始資料長這樣

{u'msgArray': [{u'bM6': u'304LN6vq.50LN6vq',
u'bR8': u'2_1VP8q_1_3_5_VP8q',
u'c': u'5269',
u'cJ3': u'295BC3bp.50BC3bp',
u'cP7': u'292VQ7.00VQ7',
u'ch': u'5269.tw',
u'd': u'20170110',
u'ex': u'tse',
u'fv': u'7',
u'gV1': u'325HC1qq.00HC1qq',
u'hB2': u'3_1QQ24_21_16_9_QQ2',
u'i': u'24',
u'ip': u'0',
u'it': u'12',
u'lH11': u'296WF11.00WF11',
u'lM12': u'293HB12jr.50HB12jr',
u'mW0': u'293MG0h.50MG0h',
u'mt': u'000000',
u'n': u'u7965u78a9',
u'nV13': u'918JR13vJR13v',
u'nf': u'u7965u78a9u79d1u6280u80a1u4efdu6709u9650u516cu53f8',
u'ot': u'14:30:00',
u'p': u'0',
u'pH17': u'291PM17p.00_290.50_290.00_289.50_289.00_PM17p',
u'pH9': u'290QZ9m.00QZ9m',
u'ps': u'67',
u'qJ15': u'292HT15.50_293.00_293.50_294.50_295.00_HT15',
u'qP5': u'291VL5.00VL5',
u'qQ4': u'459BP4vlBP4vl',
u't': u'13:30:00',
u'tk0': u'5269.tw_tse_20170110_B_9999288746',
u'tk1': u'5269.tw_tse_20170110_B_9999267733',
u'tlong': u'1484029800000',
u'ts': u'0',
u'tv': u'67',
u'vB16': u'6HR16pm7HR16pm',
u'vR14': u'291VM14.00VM14',
u'vT10': u'266MV10.00MV10'}],
u'queryTime': {u'sessionFromTime': -1,
u'sessionKey': u'tse_5269.tw_20170110|',
u'sessionLatestTime': -1,
u'sessionStr': u'UserSession',
u'showChart': False,
u'stockInfo': 42144,
u'stockInfoItem': 222,
u'sysDate': u'20170110',
u'sysTime': u'17:23:37'},
u'referer': u'http://mis.twse.com.tw/stock/fibest.jsp?stock=5269',
u'rtcode': u'0000',
u'rtmessage': u'OK',
u'userDelay': 5000,
u'userDelay2': 300000}

但是實際上,原本舊的getStockInfo.jsp提供的原始資料如下

{u'msgArray': [{'a': u'292.50_293.00_293.50_294.50_295.00_',
'b': u'291.00_290.50_290.00_289.50_289.00_',
u'c': u'5269',
u'ch': u'5269.tw',
u'd': u'20170110',
u'ex': u'tse',
'f': u'2_1_1_3_5_',
u'fv': u'7',
'g': u'3_14_21_16_9_',
'h': u'304.50',
u'i': u'24',
u'ip': u'0',
u'it': u'12',
'l': u'290.00',
u'mt': u'000000',
u'n': u'u7965u78a9',
u'nf': u'u7965u78a9u79d1u6280u80a1u4efdu6709u9650u516cu53f8',
'o': u'296.00',
'oa': u'293.50',
'ob': u'292.00',
u'ot': u'14:30:00',
'ov': u'459',
'oz': u'293.50',
u'p': u'0',
u'ps': u'67',
'pz': u'291.00',
's': u'67',
u't': u'13:30:00',
u'tk0': u'5269.tw_tse_20170110_B_9999288746',
u'tk1': u'5269.tw_tse_20170110_B_9999267733',
u'tlong': u'1484029800000',
u'ts': u'0',
u'tv': u'67',
'u': u'325.00',
'v': u'918',
'w': u'266.00',
'y': u'295.50',
'z': u'291.00'}],
u'queryTime': {u'sessionFromTime': -1,
u'sessionKey': u'tse_5269.tw_20170110|',
u'sessionLatestTime': -1,
u'sessionStr': u'UserSession',
u'showChart': False,
u'stockInfo': 42144,
u'stockInfoItem': 222,
u'sysDate': u'20170110',
u'sysTime': u'17:23:37'},
u'referer': u'http://mis.twse.com.tw/stock/fibest.jsp?stock=5269',
u'rtcode': u'0000',
u'rtmessage': u'OK',
u'userDelay': 5000,
u'userDelay2': 300000}

這表示我們必須經過一些轉換才能得到正確的資料,而這些轉換所需的資料就在fibest.jsp的response中,我們觀察fibest.jsp的原始檔可以看到將資料還原的javascript function,rA3、rA2、rA1

<script>function rA3(item){
rA=new RegExp('CN0q','g');item.s=item.cH0;if(item.s!=undefined)item.s=item.s.replace(rA,'');rA=new RegExp('QL1z','g');item.a=item.nB1;if(item.a!=undefined)item.a=item.a.replace(rA,'');rA=new RegExp('ZM2nn','g');item.f=item.qP2;if(item.f!=undefined)item.f=item.f.replace(rA,'');rA=new RegExp('NN3ql','g');item.oa=item.lG3;if(item.oa!=undefined)item.oa=item.oa.replace(rA,'');}</script>


<script type="text/javascript" src="js/highstock.js"></script>
<script>function rA2(item){
rA=new RegExp('QL4wn','g');item.ov=item.zL4;if(item.ov!=undefined)item.ov=item.ov.replace(rA,'');rA=new RegExp('WN5gp','g');item.ob=item.mZ5;if(item.ob!=undefined)item.ob=item.ob.replace(rA,'');rA=new RegExp('GP6ff','g');item.g=item.nW6;if(item.g!=undefined)item.g=item.g.replace(rA,'');rA=new RegExp('FF7t','g');item.w=item.nV7;if(item.w!=undefined)item.w=item.w.replace(rA,'');rA=new RegExp('TJ8','g');item.z=item.qH8;if(item.z!=undefined)item.z=item.z.replace(rA,'');rA3(item);}</script>
<script type="text/javascript" src="ctrl/ctrl.lang_zh_tw.js?070102"></script>
<script id='init' type="text/javascript" loadJson=1 src="ctrl/ctrl.init.js?070102"></script>

<script type="text/javascript" src='ctrl/ctrl.fibest.js?070102'></script>
<meta name="Author" content="Galaxy Shen, eCloudMobile Corp." />



<script>function rA1(item){
rA=new RegExp('LC9pr','g');item.oz=item.lP9;if(item.oz!=undefined)item.oz=item.oz.replace(rA,'');rA=new RegExp('PR10j','g');item.h=item.wZ10;if(item.h!=undefined)item.h=item.h.replace(rA,'');rA=new RegExp('JT11v','g');item.b=item.nH11;if(item.b!=undefined)item.b=item.b.replace(rA,'');rA=new RegExp('VP12','g');item.v=item.gQ12;if(item.v!=undefined)item.v=item.v.replace(rA,'');rA=new RegExp('MC13tq','g');item.u=item.pT13;if(item.u!=undefined)item.u=item.u.replace(rA,'');rA=new RegExp('TQ14','g');item.pz=item.fC14;if(item.pz!=undefined)item.pz=item.pz.replace(rA,'');rA=new RegExp('HZ15ph','g');item.y=item.fM15;if(item.y!=undefined)item.y=item.y.replace(rA,'');rA=new RegExp('PH16','g');item.o=item.tP16;if(item.o!=undefined)item.o=item.o.replace(rA,'');rA=new RegExp('VW17zl','g');item.l=item.jV17;if(item.l!=undefined)item.l=item.l.replace(rA,'');rA2(item);}</script>

從這些javascript的function來看,就是將抓回來的原始資料,將錯誤的key轉換成正確的key,將插入的亂數字串從資料中移除。

所以我們必須先將fibest.jsp的reponse這些javascript用到的轉換資料先parse好,等到抓到json資料之後在如法炮製,取得正確的資料。

我想大費周章的將原始資料先插入一些亂數,並且再用javascript來還原,目的應該就是避免所謂的網路爬蟲程式來抓取資料,但是我以為開放資料的目的不就是鼓勵大家可以來存取公開的資料嗎?

1 則留言

發佈留言