Golang爬蟲(台灣股票代碼)

一開始要先說爬蟲是什麼呢?
跟據維基的定義其中一段:
網路爬蟲可以將自己所存取的頁面儲存下來,以便搜尋引擎事後生成索引供用戶搜尋。
可以理解成有個機器人,自動的幫你查看網頁,並且處理好資料
這些資料還會自己去更新
在後續有需要用到相關資料時,就不用自己再去查詢跟整理了
目前搜尋引擎也都是靠自動網路爬蟲去尋找關鍵字結果

很多人爬蟲都會想到用python
但其實Golang本身對於網路的支持性本來就高
所以也是可以試試用Golang喔

以下是以原生的庫達到爬股票代碼的範例
本國上市證券國際證券辨識號碼一覽表的網頁
自動處理成csv檔案以供之後作使用:

package main

import (
	"log"
	"strings"

	"bytes"
	"encoding/csv"
	"io/ioutil"
	"net/http"
	"os"

	"golang.org/x/text/transform"

	"github.com/PuerkitoBio/goquery"
	"golang.org/x/text/encoding/traditionalchinese"
)

func init() {
	log.SetFlags(log.Ldate | log.Lshortfile)
}
func main() {
	//	FindStockNumber()
	FindStockNumberBySTDLib()
}

// 'dtype', '國際證券辨識號碼', '上市日', '市場別', '產業別', 'CFI', '備註'
type Stock struct {
	Dtype            string
	IdetifyNumber    string
	Date             string
	MarketCategory   string
	IndustryCategory string
	CFI              string
	Note             string
}

func FindStockNumberBySTDLib() {
	log.Print("Visiting http://isin.twse.com.tw/isin/C_public.jsp?strMode=2")
	resp, err := http.Get("http://isin.twse.com.tw/isin/C_public.jsp?strMode=2")
	if err != nil {
		log.Println("Get url error.")
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		log.Printf("get content failed status code is %d. \n", resp.StatusCode)
		return
	}

	BodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("HTML body read error.")
		return
	}
	log.Println("Get HTML.")
	// 將抓到的html網頁資訊交給goquery解析
	htmlDoc, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(BodyBytes)))
	if err != nil {
		log.Println("Goquery parse fail.")
		return
	}

	var StockList []Stock
	htmlDoc.Find(".h4").Each(func(j int, contentSelection *goquery.Selection) {
		var stock Stock
		contentSelection.Find("tr[align!='center']").Each(func(_ int, tr *goquery.Selection) {
			tr.Find("td[colspan!='7']").Each(func(i int, s *goquery.Selection) {
				// 轉換編碼
				decodeStr, _ := DecodeBig5([]byte(s.Text()))

				data := string(decodeStr)
				number := i % 8
				switch number {
				case 0:
					stock.Dtype = data
				case 1:
					stock.IdetifyNumber = data
				case 2:
					stock.Date = data
				case 3:
					stock.MarketCategory = data
				case 4:
					stock.IndustryCategory = data
				case 5:
					stock.CFI = data
				case 6:
					stock.Note = data
				}
			})
			StockList = append(StockList, stock)
		})

	})
	f, err := os.Create("./StockList.csv")
	if err != nil {
		return
	}

	f.WriteString("\xEF\xBB\xBF")
	defer f.Close()
	fw := csv.NewWriter(f)
	// 'dtype', '國際證券辨識號碼', '上市日', '市場別', '產業別', 'CFI'
	fw.Write([]string{"有價證券代號", "名稱", "國際證券辨識號碼(ISIN Code)", "上市日", "市場別", "產業別", "CFI", "備註"})
	sep := string([]byte{227, 128, 128})
	for _, i := range StockList {
		SplitStr := strings.Split(i.Dtype, sep)
		if len(SplitStr) > 1 {
			fw.Write([]string{
				SplitStr[0],
				SplitStr[1],
				i.IdetifyNumber,
				i.Date,
				i.MarketCategory,
				i.IndustryCategory,
				i.CFI,
				i.Note,
			})
		} else {
			fw.Write([]string{
				i.Dtype,
				" ",
				i.IdetifyNumber,
				i.Date,
				i.MarketCategory,
				i.IndustryCategory,
				i.CFI,
				i.Note,
			})
		}

	}
	fw.Flush()
	log.Println("Write to .csv success.")
}

//convert BIG5 to UTF-8
func DecodeBig5(s []byte) ([]byte, error) {
	I := bytes.NewReader(s)
	O := transform.NewReader(I, traditionalchinese.Big5.NewDecoder())
	d, e := ioutil.ReadAll(O)
	if e != nil {
		return nil, e
	}
	return d, nil
}

//convert UTF-8 to BIG5
func EncodeBig5(s []byte) ([]byte, error) {
	I := bytes.NewReader(s)
	O := transform.NewReader(I, traditionalchinese.Big5.NewEncoder())
	d, e := ioutil.ReadAll(O)
	if e != nil {
		return nil, e
	}
	return d, nil
}

處理過程中
要記得編碼的部分
不然後面整理成CSV的時候
會變成亂碼

在我的github上也可以找到這個範例喔

佶曰:網路爬蟲比蝸牛爬得快

發佈留言