顯示具有 股票 標籤的文章。 顯示所有文章
顯示具有 股票 標籤的文章。 顯示所有文章

2017年12月26日 星期二

[Node.js] 用 request + cheerio

用 request 抓取頁面 HTML

用 Chrome Developer Tool 觀察 HTML 結構以下為證交所網站資料
<table>
<thead>
<tr>
<th colspan='9'>
<div>105年02月 3008 大立光 各日成交資訊</div>
</th>
</tr>
<tr>
<td>日期</td>
<td>成交股數</td>
<td>成交金額</td>
<td>開盤價</td>
<td>最高價</td>
<td>最低價</td>
<td>收盤價</td>
<td>漲跌價差</td>
<td>成交筆數</td>
</tr>
</thead>
<tbody>
<tr>
<td>105/02/01</td>
<td>2,260,409</td>
<td>5,523,826,200</td>
<td>2,485.00</td>
<td>2,550.00</td>
<td>2,350.00</td>
<td>2,350.00</td>
<td>-150.00</td>
<td>2,164</td>
</tr> ......
把 request 這個 library require 進來之後,就可以用它來發 HTTP request 拿到網頁的 body,參考下面的 code,拿到的 body 是一個字串,就是整個網頁的 HTML
const request = require('request')
const url = 'http://www.twse.com.tw/exchangeReport/STOCK_DAY?response=html&date=20171001&stockNo=3008'
request(url, (err, res, body) => {
  console.log(body)
})

用 cheerio 擷取我們要的部份

拿到 body 之後接著要擷取出要的部份,cheerio 可以用 css selector的語法來選擇元素
const cheerio = require('cheerio')
// 把 body 放進 cheerio 準備分析
const $ = cheerio.load(body)
let stock = []
$('tbody td').each(function(i, elem) {
  sotck.push( $(this).text());
})
console.log(stock)

整理資料

因為拿到的資料滿亂的,稍微把它整理一下並輸出
//欄位0日期
if (i%5==0)
    stock.push( $(this).text()); 

//欄位2當日最高價
if (i%5==2)
   stock.push( parseFloat($(this).text().replace(/,/g,''))); 

輸出暫存

存好後放入txt,db隨便...之後開始賺錢?!技術分析

總結

  • 先找到要抓哪個網站的資料
  • 用 Chrome Developer Tool 觀察 HTML 結構
  • 寫 code 用 request 向網站要資料
  • 把要來的資料用 cheerio 取出要的部份
  • 把資料整理完之後輸出
參考:https://larrylu.blog/nodejs-request-cheerio-weather-414e33f45c7d

證交所最佳五檔的程式解析

證交所提供了股票即時最佳五檔的網頁,供一般民眾查詢(但我相信,會觀注的多半是碼農,從最佳五檔的網址,它主要的Host是 mis.twse.com.tw ,這是我們要注意的第一個點,透過 dig command,我們可以發現twse.com.tw網域用了4台DNS主機來應付輸詢,這也是我要提的第一個建議:
若不是用瀏覽器執行JavaScript程式
 URL直接採用網址IP連結,不要使用mis.twse.com.tw網域,輸詢太多次會卡住,且若每次輸詢結果不一致時,會導致Session遺失
再來針對它的程式設計加以說明:
先說一下,用網頁查詢的網址格式是
http://mis.twse.com.tw/stock/fibest.jsp?lang=zh_tw&stock={代號}
,在瀏覽器下通常lang=zh_tw參數會被省略,但是程式設計時,請不要忘了要加上去。這是最重要的一個關鍵,因為我們必須在這頁取得Session(並且要保留),否則後面的資料存取將無以為繼,所以若是以程式要取得Session的第一件事就是連到
http://mis.twse.com.tw/stock/fibest.jsp?lang=zh_tw
我們取得這個網頁只是為了取得Cookie
然後我們再檢閱最佳五檔的網頁源碼, 可以發現一個重要的JavaScript:ctrl.fibest.js,所有的故事從這裡開始:假設我們查詢的是6294智基,它會先到(參考 function initStock()) http://mis.twse.com.tw/stock/api/getStock.jsp?ch=6294.tw&json=1&_=時間亂數
取回6294的程式代號
{
   "msgArray":[
      {
         "ex":"otc",
         "d":"20170109",
         "it":"12",
         "n":"智基",
         "i":"20",
         "ip":"0",
         "w":"110.00",
         "u":"134.00",
         "t":"07:50:00",
         "p":"0",
         "ch":"6294.tw",
         "key":"otc_6294.tw",
         "y":"122.00"
      }
   ],
   "rtmessage":"OK",
   "queryTime":{
      "stockDetail":2315,
      "totalMicroTime":2315
   },
   "rtcode":"0000"
}
其實這裡不難看出上市代號前綴 tse_,而上櫃代號則前綴 otc_,作為碼農,您應該找個地方把所有代號的上市櫃狀態記錄在某個地方,並不時更新,若不知道請參考
http://isin.twse.com.tw/isin/C_public.jsp?strMode=2

http://isin.twse.com.tw/isin/C_public.jsp?strMode=4
另外,tse_t00.tw與otc_o00.tw分別為上市櫃指數代號
 2017/8/26 開始在取得最佳5檔前,必須先經過
http://mis.twse.com.tw/stock/api/getStockInfo.jsp?ex_ch=tse_t00.tw|otc_o00.tw|tse_FRMSA.tw&json=1&delay=0&_={時間亂數}
請注意,| 必須escape %7c(c必須為小寫)
然後再參考下面一點取得5檔資料
最後是取得五檔資訊(參考 function loadStockInfo()),它會載入
/stock/api/getStockInfo.jsp?ex_ch=otc_6294.tw&json=1&delay=0&_=時間亂數
實際上這個連結反履變過數次,若是資料出不來,就回報檢查看看是否這裡有所變動,其資料回傳範例如下(BJ4,自已對一下就知道欄位義意,該注意的是它的Json資料型態是Array,可見是為了可以回傳多筆查詢),註:回傳的json其值必須包含 "rtcode":"0000" 項問才可視為查詢成功,若不是,則請重新查詢
{
   "msgArray":[
      {
         "ts":"0",
         "tk0":"2330.tw_tse_20170116_B_9999925914",
         "tk1":"2330.tw_tse_20170116_B_9999925580",
         "tlong":"1484528728000", //目前時間
         "f":"217_1784_1144_1788_1190_",            //五檔賣量
         "ex":"tse",
         "g":"2165_1133_3126_1611_1962_",           //五檔買量
         "d":"20170116",
         "it":"12",
         "b":"179.00_178.50_178.00_177.50_177.00_", //五檔賣價
         "c":"2330",
         "mt":"549353",
         "a":"179.50_180.00_180.50_181.00_181.50_", //五檔賣價
         "n":"台積電",
         "o":"180.00",  //開盤價
         "l":"179.00",  //最低成交價
         "h":"180.50",  //最高成交價
         "ip":"0",      //1:趨跌,2:趨漲,4:暫緩收盤,5:暫緩開盤
         "i":"24",
         "w":"163.50",  //跌停價
         "v":"6359",    //累積成交量
         "u":"199.50",  //漲停價
         "t":"09:05:28",//揭示時間
         "s":"34",      //當盤成交量
         "pz":"180.00",
         "tv":"34",
         "p":"0",
         "nf":"台灣積體電路製造股份有限公司",
         "ch":"2330.tw",
         "z":"179.50",  //最近成交價
         "y":"181.50",  //昨日成交價
         "ps":"2459"    //試算參考成交量
      }
   ],
   "userDelay":...
   ...
   },
   "rtcode":"0000"
}
第3點是取得單一股票的方式,另外它也有方法可以同時取得多檔股票記錄,它取得的方式是:
http://mis.twse.com.tw/stock/api/getStockInfo.jsp?ex_ch=代號1|代號2|...|代號N&cp=0&json=1&delay=0&_=時間亂數
,範例如下(要注意HTTP Get 有長度限制):
http://mis.twse.com.tw/stock/api/getSTKInfo.jsp?ex_ch=tse_2377.tw%7cotc_6294.tw%7c&cp=0&json=1&delay=0&_=1483942971571
2017-8-12註:|(pipeline)  若要編碼請一定編為%7c(小寫),因為在前一天(8/11),證交所不再接受%7C了
取回的資料格式跟第3點類似,只不過取回的資料是一次多筆罷了,所以作為碼農,打開IDE,開始寫程式去吧!

上面的解析,寫成Java程式,可以從此處下載(程式碼在此),下載程式後只要在命令視窗下執行 

來源:http://kentyeh.blogspot.tw/2015/07/blog-post_16.html