iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Software Development

Python 爬蟲這樣學,一定是大拇指拉!系列 第 28

[Python 爬蟲這樣學,一定是大拇指拉!] DAY28 - 實戰演練:集大成 - 自動更新每日個股日成交資訊

自動更新每日個股日成交資訊

結合前幾篇所學,我們來做一個可以自動更新日成交資訊的程式吧!

程式部分:

import json
import time
import requests
from pathlib import Path
from threading import Thread
from datetime import datetime
from fake_useragent import UserAgent


class DailyPriceSpider:

    def __init__(self):
    
        # 重複使用 TCP 連線
        self.req = requests.Session()
        self.url = "https://www.twse.com.tw/exchangeReport/STOCK_DAY"
        self.headers = self.req.headers
        
        # 偽裝 User-Agent
        ua = UserAgent()
        self.headers["User-Agent"] = ua.random
 
    # 供內部使用
    def __get(self, date, stock_no):
        res = self.req.get(self.url,
                           headers = self.headers,
                           params={
                               "response": "csv",  # 這次抓的是 csv 格式
                               "date": date,
                               "stockNo": stock_no
                           })
        return res
    
    # 供內部使用
    def __save_file(self, res_text, path):
        # 去掉 res_text 裡多餘的空白行
        res_text = '\n'.join(
            filter(None,
                   res_text.splitlines()
                   )
        )

        path = Path(path)
        # parents=True,如果父資料夾不存在則會一併創建
        # exist_ok=True,創建資料夾時,該資料夾已存在則不會 throw exception
        path.parent.mkdir(parents=True, exist_ok=True)
        
        # 這邊我比較懶一點,是直接覆蓋整個檔案,可以依照個人喜好去修改
        with open(path, 'w', encoding="utf-8") as file:
            file.write(res_text)
        return
 
    # 把上面的兩個 function 整合成一個 function,供外部使用
    def scrape(self, date, stock_no, save_path=""):
        res = self.__get(date, stock_no)
        if save_path:
            res_text = res.text
            self.__save_file(res_text, save_path)
        # 雖然這邊沒用到但還是可以先 return response 保留日後擴充彈性
        return res

if __name__ == '__main__':
    SAVE_PATH_ROOT = "./daily_stock_price/"
    SLEEP_TIME = 3
    
    # 之前有實作過抓取股票清單的程式了,我們直接讀取清單裡的內容來使用
    # 程式實作篇章傳送門請至本篇文章最上面
    stock_info_list_file = {}
    with open("./stock_info_list.json", "r", encoding="utf-8") as f:
        stock_info_list_file = json.load(f)

    # 不管日期是幾號,他回傳都是給我們一整個月的,所以就固定設成1號就好
    # strftime(),把 datetime 輸出成我們要的格式
    today_date = "{}01".format(datetime.now().strftime("%Y%m"))

    stock_info_list = stock_info_list_file.get("stock", [])
    dps = DailyPriceSpider()
    req_thread_list = []

    for stock_info in stock_info_list:

        stock_no = stock_info.get("stockNo")
        stock_name = stock_info.get("stockName")
        stock_industry = stock_info.get("stockIndustry")
        file_name = "{}_{}_daily_price.csv".format(
            today_date[:-2],  # 字串只需要用到年跟月
            stock_no+stock_name)

        save_path = "{}/{}/{}/{}".format(SAVE_PATH_ROOT,
                                         stock_industry,
                                         stock_no+stock_name,
                                         file_name)

        if stock_no and stock_name and stock_industry:
            # daemon=True,就是 main 結束時,daemon=True 的執行緒也會跟著結束
            req_thread = Thread(target=dps.scrape,
                                args=(today_date, stock_no, save_path),
                                daemon=True)
            req_thread.start()
            req_thread_list.append(req_thread)
            time.sleep(SLEEP_TIME)

    for req_thread in req_thread_list:
        req_thread.join()

    print("Finished")

輸出的資料會長這樣:
https://ithelp.ithome.com.tw/upload/images/20211012/20139358EsAQqV8tjZ.png

以上是程式的部分,那我們要怎麼讓程式每天自動去更新呢!?

Win10 本身有內建工作排程器的工具,設定完之後,電腦就會照著 Schedule 去跑這支程式囉!
設定參考傳送門

以上就是把我們從第一天所學的所有東西,應用在爬蟲的部分!
之後可以再加上 logger 或 error handler 之類的,讓程式更完整。


上一篇
[Python 爬蟲這樣學,一定是大拇指拉!] DAY27 - 實戰演練:重複使用 TCP 連線
下一篇
[Python 爬蟲這樣學,一定是大拇指拉!] DAY29 - 實戰演練:自製進度條 Progress Bar
系列文
Python 爬蟲這樣學,一定是大拇指拉!30

尚未有邦友留言

立即登入留言