籌碼面 - 台灣證券交易所買賣日報表查詢系統

更新於 發佈於 閱讀時間約 25 分鐘

自從筆者開始研究量化交易之後,就聽說股價跟籌碼面脫不了關係,其中的重點就是要分析分點交易狀況。台灣證券交易所與證券櫃檯買賣中心都有提供買賣日報表查詢,但是為了避免太多機器人爬蟲造成主機負擔,一個需要輸入圖形驗證碼,一個需要勾選reCaptcha我不是機器人的欄位。


這一篇就先以程式自動輸入圖形驗證碼,並取得證券交易所每一檔股票的買賣日報表當作範例。

台灣證券交易所的買賣日報表查詢網路連結為https://bsr.twse.com.tw/bshtm/bsMenu.aspx。主要的邏輯架構也不難,先把台灣證券交易所的網頁抓下來,找到辨識驗證碼的欄位,透過OpenCV與OCR把圖型轉成數字,填回數字以及想要抓取的股票代碼,按下網頁確定的按鈕,網站就會吐出該股票代碼的買賣日報表,我們把這些資料做個欄位處理之後,存成一個文字檔案,再由其他程式做籌碼計算。

這邊要注意的是OCR套件不一定每次都可以辨識出正確的數字,因為台灣證券交易所的數字長度永遠都是5,所以我們可以在辨識的結尾判斷長度,如果不正確,就重新判斷一次。

另外就是台灣證券交易所如果偵測到大量的索取要求,將會直接把IP鎖住一陣子,所以在每次索取要求之間,我們都先暫停一段時間,這邊我們是設定一分鐘。主要程式碼就如下所示:

        private async Task<bool> GetTWSEBroker(string code, string path)
{
// https://bsr.twse.com.tw/bshtm/bsMenu.aspx
// https://bsr.twse.com.tw/bshtm/bsContent.aspx

int dlretry = 0;
int ocrretry = 0;
begin:
string reqtwse = "https://bsr.twse.com.tw/bshtm/bsMenu.aspx";
CookieContainer _cookies = new CookieContainer();
string csvtwse = await GetAsync(reqtwse, _cookies, 65001);
again:
string Captcha = FindImg(csvtwse);
//Debug.WriteLine(code + " 辨識驗證碼 " + Captcha);
if (Captcha.Length != 5)
{
if (ocrretry++ < 5)
{
goto again;
}
else
{
Debug.WriteLine(code + " 辨識驗證碼錯誤 " + Captcha);
}
}

NameValueCollection postParams = System.Web.HttpUtility.ParseQueryString(string.Empty);
postParams.Add("__EVENTTARGET", "");
postParams.Add("__EVENTARGUMNET", "");
postParams.Add("__LASTFOCUS", "");
postParams.Add("__VIEWSTATE", FindToken(csvtwse, "__VIEWSTATE"));
postParams.Add("__VIEWSTATEGENERATOR", FindToken(csvtwse, "__VIEWSTATEGENERATOR"));
postParams.Add("__EVENTVALIDATION", FindToken(csvtwse, "__EVENTVALIDATION"));
postParams.Add("RadioButton_Normal", "RadioButton_Normal");
postParams.Add("TextBox_Stkno", code);
postParams.Add("CaptchaControl1", Captcha);
postParams.Add("btnOK", "%E6%9F%A5%E8%A9%A2");

string responseInString = SetAsync(reqtwse, _cookies, postParams);
//Debug.WriteLine(responseInString);
if (FindContent(responseInString))
{
string csvurl = "https://bsr.twse.com.tw/bshtm/bsContent.aspx";
string csvline = await GetAsync(csvurl, _cookies, 950);

if (csvline.Count() > 0)
{
File.WriteAllText(path, "證券代碼 " + code + " 序號,券商,價格,買進股數,賣出股數\r\n");
int skipline = 0;
foreach (var line in csvline.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Replace(" ", "")).Select(s => s.Replace(" ", "")))
{
if (skipline++ < 3) continue;

try
{
string[] csv = line.Split(",");
string strData = string.Empty;
if (csv.Count() == 11)
{
if (csv[6] != "")
{
strData = string.Format("{0},{1},{2},{3},{4}\r\n{5},{6},{7},{8},{9}\r\n",
csv[0], csv[1], csv[2], csv[3], csv[4], csv[6], csv[7], csv[8], csv[9], csv[10]
);
}
else
{
strData = string.Format("{0},{1},{2},{3},{4}\r\n",
csv[0], csv[1], csv[2], csv[3], csv[4]
);
}

File.AppendAllText(path, strData);
}
else
{
File.Delete(path);
Debug.WriteLine("TWSE Err inline " + code);
}
}
catch
{
File.Delete(path);
Debug.WriteLine("TWSE Err File " + code);
}
}
}

return true;
}
else if (dlretry++ < 5)
{
//Debug.WriteLine("驗證碼錯誤");
Thread.Sleep(60000);
goto begin;
}

Debug.WriteLine("TWSE Err download " + code);
return false;
}

為了可以取得網頁上面的資料,在這邊我們採用HtmlAgilityPack的HtmlDocument套件,幫助我們把網頁內容抓下來,並提取指定的欄位,其中辦識圖片中的數字,可以透過OpenCV先做圖片的切割,再透過Tesseract OCR的幫助,把每個圖片數字轉成實際數值,所以使用上要在C#先安裝HtmlAgilityPack、OpenCvSharp4以及Tesseract的套件。

我把相關的程式碼都放在下方,提供大家做參考。

        private string FindImg(string webdata)
{
try
{
if (webdata.Length == 0)
{
Debug.WriteLine("CaptchaImage has no challenge. Sleeping for a while now.");
Thread.Sleep(1800000);
return string.Empty;
}

string imgname = string.Empty;

HtmlDocument document = new HtmlDocument();
document.LoadHtml(webdata);

foreach (HtmlNode tag in document.DocumentNode.SelectNodes("//img"))
{
if (tag.Attributes["src"].Value.Contains("CaptchaImage"))
{
imgname = tag.Attributes["src"].Value;
}
}

string fname = @s_temppath + "CaptchaImage.JFIF";
if (File.Exists(fname))
{
File.Delete(fname);
}

using (WebClient webClient = new WebClient())
{
webClient.DownloadFile(new Uri("https://bsr.twse.com.tw/bshtm/" + imgname), fname);
//webClient.DownloadData
}

return DecodeCaptcha(@s_temppath + "CaptchaImage.JFIF");
}
catch (NullReferenceException)
{
// web return no page
Debug.WriteLine("CaptchaImage has no challenge. Sleeping for a while now.");
Thread.Sleep(1800000);
}
catch
{
//Debug.WriteLine("Exception in CaptchaImage");
Thread.Sleep(5000);
}
return string.Empty;
}
private string FindToken(string webdata, string item)
{
try
{
HtmlDocument document = new HtmlDocument();
document.LoadHtml(webdata);
string description = string.Empty;
foreach (HtmlNode tag in document.DocumentNode.SelectNodes("//input"))
{
if (tag.Attributes["name"] != null && tag.Attributes["id"] != null && tag.Attributes["name"].Value == item)
{
description = tag.Attributes["value"].Value;
}
}
return description;
//return System.Web.HttpUtility.UrlEncode(description);
}
catch (NullReferenceException)
{
// web return no page
Debug.WriteLine("CaptchaImage has no challenge. Sleeping for a while now.");
Thread.Sleep(1800000);
}
catch
{
;
}
return string.Empty;
}
private string DecodeCaptcha(string img)
{
var ocrtext = string.Empty;
// OpenCV#
using Mat captcha = new Mat(img, ImreadModes.Grayscale);
if (captcha.Empty())
{
return ocrtext;
}

// Convert the captcha to black and white.
using Mat captcha_bw = new Mat();
Cv2.Threshold(captcha, captcha_bw, 128, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);

// Erode the image to remove dot noise and that wierd line. I use a 3x3 rectengal as the kernal.
using Mat captcha_erode = new Mat();
using Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
Cv2.Erode(captcha_bw, captcha_erode, element);

// Some cosmetic
using Mat captcha_denoise = new Mat();
Cv2.FastNlMeansDenoising(captcha_erode, captcha_denoise, 50);

byte[] buffer = captcha_denoise.ToMemoryStream().ToArray();

// OCR
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
path = Path.Combine(path, "tessdata");
path = path.Replace("file:\\", "");

using (var engine = new TesseractEngine(path, "eng", EngineMode.Default))
{
engine.SetVariable("tessedit_char_whitelist", "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ");
engine.SetVariable("tessedit_unrej_any_wd", true);
using (var ocr = Pix.LoadFromMemory(buffer))
{
using (var page = engine.Process(ocr))
{
ocrtext = page.GetText();
}
}
}

return ocrtext.Trim('\n');
}

一開始,我對於網頁互動爬取資料也不是很熟悉,所以土炮煉製了這一大段的程式去抓資料,中間走過不少冤枉路,雖然我實在找不到籌碼面怎麼樣可以幫助程式交易,但是還是把這些結果記錄下來,留個紀念。

留言
avatar-img
留言分享你的想法!
avatar-img
Gary Hu的沙龍
4會員
11內容數
Gary Hu的沙龍的其他內容
2025/04/14
從2023年之前,美股會直接預扣30% 股息預扣稅率,但是在2023年通過台美稅務協定後,你想在美國券商(例如 TD Ameritrade、Firstrade、Charles Schwab 等)享有台美稅務協定下的21% 股息預扣稅率,關鍵就在於正確填寫並提交一份W-8BEN 表格。 以下是步
Thumbnail
2025/04/14
從2023年之前,美股會直接預扣30% 股息預扣稅率,但是在2023年通過台美稅務協定後,你想在美國券商(例如 TD Ameritrade、Firstrade、Charles Schwab 等)享有台美稅務協定下的21% 股息預扣稅率,關鍵就在於正確填寫並提交一份W-8BEN 表格。 以下是步
Thumbnail
2024/12/21
小弟走跳江湖多年,也累績了一些職場心得,在年底轉職熱門時刻,希望能夠幫助到一些有緣人。
2024/12/21
小弟走跳江湖多年,也累績了一些職場心得,在年底轉職熱門時刻,希望能夠幫助到一些有緣人。
2024/10/13
本地端生成式AI工具LM Studio安裝介紹,包含如何手動載入AI模型的技巧。
Thumbnail
2024/10/13
本地端生成式AI工具LM Studio安裝介紹,包含如何手動載入AI模型的技巧。
Thumbnail
看更多
你可能也想看
Thumbnail
大家好,我是一名眼科醫師,也是一位孩子的媽 身為眼科醫師的我,我知道視力發展對孩子來說有多關鍵。 每到開學季時,診間便充斥著許多憂心忡忡的家屬。近年來看診中,兒童提早近視、眼睛疲勞的案例明顯增加,除了3C使用過度,最常被忽略的,就是照明品質。 然而作為一位媽媽,孩子能在安全、舒適的環境
Thumbnail
大家好,我是一名眼科醫師,也是一位孩子的媽 身為眼科醫師的我,我知道視力發展對孩子來說有多關鍵。 每到開學季時,診間便充斥著許多憂心忡忡的家屬。近年來看診中,兒童提早近視、眼睛疲勞的案例明顯增加,除了3C使用過度,最常被忽略的,就是照明品質。 然而作為一位媽媽,孩子能在安全、舒適的環境
Thumbnail
我的「媽」呀! 母親節即將到來,vocus 邀請你寫下屬於你的「媽」故事——不管是紀錄爆笑的日常,或是一直想對她表達的感謝,又或者,是你這輩子最想聽她說出的一句話。 也歡迎你曬出合照,分享照片背後的點點滴滴 ♥️ 透過創作,將這份情感表達出來吧!🥹
Thumbnail
我的「媽」呀! 母親節即將到來,vocus 邀請你寫下屬於你的「媽」故事——不管是紀錄爆笑的日常,或是一直想對她表達的感謝,又或者,是你這輩子最想聽她說出的一句話。 也歡迎你曬出合照,分享照片背後的點點滴滴 ♥️ 透過創作,將這份情感表達出來吧!🥹
Thumbnail
大家應該都有印象,當你是新手時,貼出你的進出單時,都會有人提醒你把帳號碼掉,而且很多大咖或者進出金額大的人不但會碼掉帳戶,還會碼掉張數,因為怕別人找到他進出的分點。 那真的找的到嗎?可以的,因為台灣證交所跟櫃買中心都有提供查詢的網站,照片如下,上市以2330為例,上櫃以5309為例你會有下列的查詢結
Thumbnail
大家應該都有印象,當你是新手時,貼出你的進出單時,都會有人提醒你把帳號碼掉,而且很多大咖或者進出金額大的人不但會碼掉帳戶,還會碼掉張數,因為怕別人找到他進出的分點。 那真的找的到嗎?可以的,因為台灣證交所跟櫃買中心都有提供查詢的網站,照片如下,上市以2330為例,上櫃以5309為例你會有下列的查詢結
Thumbnail
每個人都有自己檢視個股好壞的方式,但總是希望每次在查詢時,如果能一鍵就檢視完成那該有多好。今天我們就來學習如何製作一份地雷股檢視圖,學會後就能夠如法炮製,製作自己的一鍵檢視清單,不用再上網依靠其他網站手動檢查,可以省下一大段時間,又能及時了解要投資的個股好壞,以便能適時做出買賣決策
Thumbnail
每個人都有自己檢視個股好壞的方式,但總是希望每次在查詢時,如果能一鍵就檢視完成那該有多好。今天我們就來學習如何製作一份地雷股檢視圖,學會後就能夠如法炮製,製作自己的一鍵檢視清單,不用再上網依靠其他網站手動檢查,可以省下一大段時間,又能及時了解要投資的個股好壞,以便能適時做出買賣決策
Thumbnail
如何觀察一家個股的好壞,最直觀的方式就是查詢其財務報表,像是資產負債表或是現金流量表等等,但這些報表中存在著密密麻麻的眾多指標,真的是會讓人看了頭昏眼花,而且也真的是極少數人才會每個指標都關注,大多的人一定都是觀察幾個自認為比較重要的指標而已吧,因為我就是如此,因此今天我們就來學習如何一鍵輕鬆查詢報
Thumbnail
如何觀察一家個股的好壞,最直觀的方式就是查詢其財務報表,像是資產負債表或是現金流量表等等,但這些報表中存在著密密麻麻的眾多指標,真的是會讓人看了頭昏眼花,而且也真的是極少數人才會每個指標都關注,大多的人一定都是觀察幾個自認為比較重要的指標而已吧,因為我就是如此,因此今天我們就來學習如何一鍵輕鬆查詢報
Thumbnail
選股一直是投資人最重要也最需要了解的一個步驟,選出好的股票就代表你已經成功一半了,但你是否每次選股都要開啟選股軟體,然後開始點選那超多樣的篩選條件,最終才能成功跑出今日的最新選股條件,這真的是太過麻煩了,導致很多人最終都放棄那本應該讓你投資成功的選股條件,所以今天我們就來教學如何用LINE BOT一
Thumbnail
選股一直是投資人最重要也最需要了解的一個步驟,選出好的股票就代表你已經成功一半了,但你是否每次選股都要開啟選股軟體,然後開始點選那超多樣的篩選條件,最終才能成功跑出今日的最新選股條件,這真的是太過麻煩了,導致很多人最終都放棄那本應該讓你投資成功的選股條件,所以今天我們就來教學如何用LINE BOT一
Thumbnail
在上一篇文章中我們教了如何爬取同業比較的相關排名資訊,而這次我們要爬取的資料是三大法人的資訊,並且以圖表的方式呈現出來,可以輕鬆的了解個股近期籌法的變動。我們將分成兩個部分來介紹,上半部先製作最新法人,而下半部再爬取歷史法人的資訊,並將其畫成圖表呈現
Thumbnail
在上一篇文章中我們教了如何爬取同業比較的相關排名資訊,而這次我們要爬取的資料是三大法人的資訊,並且以圖表的方式呈現出來,可以輕鬆的了解個股近期籌法的變動。我們將分成兩個部分來介紹,上半部先製作最新法人,而下半部再爬取歷史法人的資訊,並將其畫成圖表呈現
Thumbnail
今天繼續我們股市LINE BOT的訊息顯示教學,繼上次我們查詢了平均股利的資訊後,這次我們來製作如何查詢歷年股利的部份,其實大同小異,就差在爬取的網站資料差異而已,那我們就開始今天的教學吧!!
Thumbnail
今天繼續我們股市LINE BOT的訊息顯示教學,繼上次我們查詢了平均股利的資訊後,這次我們來製作如何查詢歷年股利的部份,其實大同小異,就差在爬取的網站資料差異而已,那我們就開始今天的教學吧!!
Thumbnail
前陣子因為Heroku被駭客入侵原因,導致Github串聯被封阻,一度無法進行教學,不過近日Heroku已重新全面開放串聯,因此我們將持續恢復教學文章,今天我們要教的是如何爬取個股的平均股利資訊,讓我們輕鬆一鍵了解個股股利的發放狀況
Thumbnail
前陣子因為Heroku被駭客入侵原因,導致Github串聯被封阻,一度無法進行教學,不過近日Heroku已重新全面開放串聯,因此我們將持續恢復教學文章,今天我們要教的是如何爬取個股的平均股利資訊,讓我們輕鬆一鍵了解個股股利的發放狀況
Thumbnail
在上一篇教學中,我們學會了如何將鉅亨網上的新聞爬取下來,並且顯示在LINE BOT中,而我們今天則來教一下如何查詢個股的一些基本資訊,以及最新的開盤價、成交價等資訊吧!!
Thumbnail
在上一篇教學中,我們學會了如何將鉅亨網上的新聞爬取下來,並且顯示在LINE BOT中,而我們今天則來教一下如何查詢個股的一些基本資訊,以及最新的開盤價、成交價等資訊吧!!
Thumbnail
Excel VBA 簡單的網頁爬蟲
Thumbnail
Excel VBA 簡單的網頁爬蟲
Thumbnail
是不是在投資股票的人,會有一種煩惱當你在找新的標的物或新的投資名單,總會覺的找股票代號或股票名稱很不方便,這邊提供一個小方法可以讓你找到全部股票名稱及代碼了!!!! 台灣證券交易所>>產品與服務>>證券編碼公告>>本國上市證券國際證券辨識號碼一覽表 STEP 1 台灣證券交易所 ·
Thumbnail
是不是在投資股票的人,會有一種煩惱當你在找新的標的物或新的投資名單,總會覺的找股票代號或股票名稱很不方便,這邊提供一個小方法可以讓你找到全部股票名稱及代碼了!!!! 台灣證券交易所>>產品與服務>>證券編碼公告>>本國上市證券國際證券辨識號碼一覽表 STEP 1 台灣證券交易所 ·
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News