7-多線程爬蟲糗事百科

7-多線程爬蟲糗事百科

簡介

多線程 thread 在 Python 裏面被稱作雞肋的存在!不建議使用,多是使用多進程,雖然不建議使用,還是做個筆記吧。

實現線程的兩種方式

直接利用函數創建多線程
import _thread
import time


# 爲線程定義函數
def print_time(thread_name, delay):
    count = 0
    while count < 5:
        time.sleep(delay)
        count += 1
        print("%s : %s" % (thread_name, time.ctime(time.time())))


# 創建兩個線程
try:
    _thread.start_new_thread(print_time, ("thread-1", 2))
    _thread.start_new_thread(print_time, ("thread-2", 3))
except:
    print("Error: unalbe to start thread")


# 這是讓主線程一直在等待
# 如果去掉,線程中數據不會打印
while 1:
    pass
利用threading創建多線程

使用Threading模塊創建線程,直接從threading.Thread繼承,然後重寫init方法和run方法:

利用threading多線程糗事百科

from threading import Thread
from queue import Queue
from fake_useragent import UserAgent
import requests
from lxml import etree
import time


# 爬蟲類
class CrawlInfo(Thread):
    def __init__(self, url_queue, html_queue):
        Thread.__init__(self)
        self.url_queue = url_queue
        self.html_queue = html_queue

    def run(self):
        headers = {
            'User-Agent': UserAgent().random
        }
        while not self.url_queue.empty():
            response = requests.get(self.url_queue.get(), headers=headers)
            if response.status_code == 200:
                self.html_queue.put(response.text)


class ParseInfo(Thread):
    def __init__(self, html_queue):
        Thread.__init__(self)
        self.html_queue = html_queue

    def run(self) -> None:
        while not self.html_queue.empty():
            e = etree.HTML(self.html_queue.get())
            contents = e.xpath('//div[@class="content"]/span[1]')
            with open("duanzi.txt", "a", encoding="utf-8") as f:
                for content in contents:
                    info = content.xpath('string(.)')
                    f.write(info + "\n")


if __name__ == '__main__':
    time.time()
    # 存儲url的容器
    # FIFO(first-in-first-out先入先出)隊列
    url_queue = Queue()
    # 存儲內容容器
    html_queue = Queue()
    base_url = 'https://www.qiushibaike.com/text/page/{}/'
    for i in range(1, 13):
        new_url = base_url.format(i)
        url_queue.put(new_url)

    # 創建一個爬蟲
    crawl_list = []
    for i in range(0, 3):
        crawl1 = CrawlInfo(url_queue, html_queue)
        crawl_list.append(crawl1)
        crawl1.start()

    for crawl_detail in crawl_list:
        crawl_detail.join()

    # 處理數據
    crawl2 = ParseInfo(html_queue)
    crawl2.start()

線程同步

如果多個線程共同對某個數據修改,則可能出現不可預料的結果,爲了保證數據的正確性,需要對多個線程進行同步。

使用Thread對象的Lock和Rlock可以實現簡單的線程同步,這兩個對象都有acquire方法和release方法,對於那些需要每次只允許一個線程操作的數據,可以將其操作放到acquire和release方法之間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章