[Python 爬虫这样学,一定是大拇指拉!] DAY26 - 实战演练:多执行绪 - 抓取多个个股日成交资讯

多执行绪(multithreading)

所以我们的多执行绪在程序是怎麽运作呢?

  • 一般情况:

    • 假设 req1、req2 都是送 request 到 server 的 function。
    • 送出收到资料皆须花费三秒
    import time
    
    def req1():
        print("req1: 开始送 request") 
        time.sleep(3)
        print("req1: 接收到 response") 
    
    def req2():
        print("req2: 开始送 request") 
        time.sleep(3)
        print("req2: 接收到 response")
    
    if __name__ == '__main__':
        req1()
        req2()
    

    输出:

    https://ithelp.ithome.com.tw/upload/images/20211011/20139358R4d6JdinWW.png

    • 根据输出结果我们可以知道:
      req2 执行前,必须得等 req1 整个流程(function 里的那些动作)跑完。所以 CPU 这种一秒钟几千万上下的核心也陪 req2 乾等了 3 秒钟。但这样子的使用是非常浪费 CPU 资源的。那该怎麽解决呢?
  • 我们可以运用多执行绪:

    import time
    # import python 的多执行绪套件
    from threading import Thread
    
    def req1():
        print("req1: 开始送 request") 
        time.sleep(3)
        print("req1: 接收到 response") 
    
    def req2():
        print("req2: 开始送 request") 
        time.sleep(3)
        print("req2: 接收到 response")
    
    if __name__ == '__main__':
        # 先将 funtion 包装成 thread 的物件,再执行
        Thread(target=req1).start()
        Thread(target=req2).start()
    

    输出:

    https://ithelp.ithome.com.tw/upload/images/20211011/201393589xCmv9MVBK.png

    • 根据输出结果我们发现到:
      req1 还没执行完就马上接着做 req2 了!终於不用再等 req1 整个流程(function 里的那些动作)跑完才做下一个动作了。简单来说,程序(main)的运行就不会阻塞在那边,会继续往下做。根据下面的比较图,花费时间真的变少了!

      • 一般情况花费时间:
        https://ithelp.ithome.com.tw/upload/images/20211011/20139358edrIMaLtxa.png

      • 使用多执行绪花费时间:
        https://ithelp.ithome.com.tw/upload/images/20211011/20139358f0yScMI8db.png

    • 而当要送出多个 request 时,会建议使用多执行绪来做,是因为 request 送出到收到 response 这中间多多少少都是要等的,而且根据现实的网路状况,也不能保证每次都很快,可能0.3秒、5秒、10秒。所以与其等,我不如先送其他 request 来节省时间。

多执行绪搭配爬虫

那我们拿之前教的个股日成交资讯结合多执行绪,来抓取多个个股日成交资讯吧!

  • 示范:

    import time
    import requests
    from threading import Thread
    
    # 将流程先用 function 封装起来,接下来才能带入 thread 中
    def daily_price_req(date, stock_no):
        res = requests.get("https://www.twse.com.tw/exchangeReport/STOCK_DAY",
                           params={
                               "response": "json",
                               "date": date,
                               "stockNo": stock_no
                           })
    
        # 把 JSON 转成 Python 可存取之型态
        res_json = res.json()
    
        # 我们要的每日成交资讯在 data 这个栏位
        daily_price_list = res_json['data']
    
        # 印出资料
        print("{} 每日成交资讯: {}".format(stock_no, daily_price_list))
    
    
    if __name__ == '__main__':
        # 日期什麽的,可以依照需求设定
        req_info_list = [
            {
                "date": "20211011",
                "stockNo": "2330"
            },
            {
                "date": "20211011",
                "stockNo": "2603"
            },
            {
                "date": "20211011",
                "stockNo": "2609"
            }
        ]
    
        for req_info in req_info_list:
            req_date = req_info.get("date")
            req_stock_no = req_info.get("stockNo")
            if req_date and req_stock_no:
                # args 为 function 会用到的参数
                req_thread = Thread(target=daily_price_req,
                                    args=(req_date, req_stock_no))
                req_thread.start()
    
                # 每个 req 间隔最好 3 秒以上,不然会被证交所锁 IP 一段时间
                time.sleep(3)
    

    输出(图片横幅太宽,我截图只截一半请见谅):
    https://ithelp.ithome.com.tw/upload/images/20211011/20139358hbl2iZmRR7.png

  • 多执行绪的另外一个用法:

    req_thread_list = []
    for req_info in req_info_list:
            req_date = req_info.get("date")
            req_stock_no = req_info.get("stockNo")
            if req_date and req_stock_no:
                req_thread = Thread(target=daily_price_req,
                                    args=(req_date, req_stock_no))
                req_thread.start()
                req_thread_list.append(req_thread)
    
                # 每个 req 间隔最好 3 秒以上,不然会被证交所锁 IP 一段时间
                time.sleep(3)
    
    for req_thread in req_thread_list:
        # join() 就是让程序等着,确定该 thread 已经执行完毕之後再继续往下
        # 所以这边的用法是说:
        # 我的程序会在这边等所有 req thread(daily_price_req 里的那些动作)都执行完毕後再往下做
        req_thread.join()
    
    # do something...
    print("do something...")
    

    输出(图片横幅太宽,我截图只截一半请见谅):
    https://ithelp.ithome.com.tw/upload/images/20211011/201393580TNK5WDf7c.png

以上就是多执行绪搭配爬虫的应用!可以依照不同需求再自行修改~


<<:  Day 29 - "TAT台湾敏捷部落"的讲座资源超丰富

>>:  Day26 - 收放工具按钮

Day11 - this&Object Prototypes Ch3 Objects - Contents - Existence

作者说明了两种确认 object 特定 property 是否存在的方式 in operator:p...

Day26 参加职训(机器学习与资料分析工程师培训班),Tensorflow.keras & Pytorch

上午: Python机器学习套件与资料分析 挑几个不错的片段分享 # 储存每个epoch的weigh...

Day12-你好 安安 对不起我要去洗澡了 如何跟pod互动

前一章介绍如何建立,删除pod之後,就要来谈谈如何对pod本身进行互动了。 当我们建立完有应用程序的...

[day-27] U-net Experiments (3) - performance 2

前言 除了 EM segmentatation challenge 比赛之外,还有参加了另外一个比赛...

用 Python 畅玩 Line bot - 06:Image Message

现在我们可以来尝试能对收到的 Image message 做怎样的操作,我们可以使用line_bot...