UNPKG

node-twstock

Version:

A client library for scraping Taiwan stock market data

83 lines (82 loc) 3.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TdccScraper = void 0; const _ = require("lodash"); const cheerio = require("cheerio"); const numeral = require("numeral"); const csvtojson = require("csvtojson"); const luxon_1 = require("luxon"); const scraper_1 = require("./scraper"); class TdccScraper extends scraper_1.Scraper { async fetchStocksShareholders(options) { const { date, symbol } = options; const url = 'https://www.tdcc.com.tw/portal/zh/smWeb/qryStock'; const request = await this.httpService.get(url); const $request = cheerio.load(request.data); const token = $request('#SYNCHRONIZER_TOKEN').attr('value'); const uri = $request('#SYNCHRONIZER_URI').attr('value'); const method = $request('#method').attr('value'); const firDate = $request('#firDate').attr('value'); const scaDate = $request('#scaDate').find('option').map((_, el) => { return $request(el).attr('value'); }).toArray(); const cookie = request.headers['set-cookie']; const form = new URLSearchParams({ SYNCHRONIZER_TOKEN: token, SYNCHRONIZER_URI: uri, method, firDate, scaDate: luxon_1.DateTime.fromISO(date).toFormat('yyyyMMdd'), sqlMethod: 'StockNo', stockNo: symbol, stockName: '', }); const response = await this.httpService.post(url, form, { headers: { 'Cookie': cookie } }); const $response = cheerio.load(response.data); const message = $response('.table tr').find('td').eq(0).text(); if (message === '查無此資料') return null; const data = {}; data.date = date; data.symbol = symbol; data.shareholders = $response('.table tr').slice(1).map((_, el) => { const td = $response(el).find('td'); return { level: numeral(td.eq(0).text()).value(), holders: numeral(td.eq(2).text()).value(), shares: numeral(td.eq(3).text()).value(), proportion: numeral(td.eq(4).text()).value(), }; }).toArray(); if (data.shareholders.length === 16) { data.shareholders = [ ...data.shareholders.slice(0, -1), { level: 16, holders: null, shares: 0, proportion: 0 }, Object.assign(Object.assign({}, data.shareholders[data.shareholders.length - 1]), { level: 17 }) ]; } return data; } async fetchStocksShareholdersRecentWeek(options) { const url = 'https://smart.tdcc.com.tw/opendata/getOD.ashx?id=1-5'; const response = await this.httpService.get(url); const json = await csvtojson({ noheader: true, output: 'csv' }).fromString(response.data); const [fields, ...rows] = json; const distributions = rows.map(row => ({ date: luxon_1.DateTime.fromFormat(row[0], 'yyyyMMdd').toISODate(), symbol: row[1], level: numeral(row[2]).value(), holders: row[2] === '16' ? null : numeral(row[3]).value(), shares: row[2] === '16' ? numeral(row[4]).multiply(-1).value() : numeral(row[4]).value(), proportion: row[2] === '16' ? numeral(row[5]).multiply(-1).value() : numeral(row[5]).value(), })); const data = _(distributions).groupBy('symbol') .map(rows => { const { date, symbol } = rows[0]; const shareholders = rows.map(row => _.omit(row, ['date', 'symbol'])); return { date, symbol, shareholders }; }).value(); return (options === null || options === void 0 ? void 0 : options.symbol) ? data.find(data => data.symbol === options.symbol) : data; } } exports.TdccScraper = TdccScraper;