Drissionpage多线程控制多标签页爬虫

751 阅读1分钟
# -*- coding: utf-8 -*-
# @Author  : XiYuan
# @Time    : 2023/12/4 21:40
import concurrent.futures
import queue
from time import sleep

# 创建配置对象(默认从 ini 文件中读取配置)
from DrissionPage._configs.chromium_options import ChromiumOptions
from DrissionPage._pages.chromium_tab import WebPageTab
from DrissionPage._pages.web_page import WebPage


class TabPool:

    def __init__(self, size=3, mode='d', timeout=None, chromium_options=None, session_or_options=None):
        self._thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=size)
        self._tab_pool = queue.Queue()
        self._tab_dic = {}
        # 创建配置对象(默认从 ini 文件中读取配置)
        co = ChromiumOptions()
        # 设置不加载图片、静音
        co.mute().set_load_mode('eager')
        self._webpage = WebPage(mode, timeout, chromium_options, session_or_options)
        self._create_web_tab_pool(size)

    def _create_web_tab_pool(self, size=5):
        for i in range(0, size + 1):
            self._create_tab()

    def _create_tab(self):
        tab = self._webpage.new_tab()
        tab = self._webpage.get_tab(tab)
        self._tab_pool.put(tab)
        self._tab_dic[tab] = 0

    def get_active_web_tab(self) -> WebPageTab:
        tab = self._tab_pool.get()  # 随机获取其中一个tab
        count = self._tab_dic.get(tab)
        self._tab_dic[tab] = count + 1
        # self._time_to_return_tab(tab)
        return tab

    def close_web_page_pool(self):
        """
        确保任务都已经完成才能调用这个方法
        """
        self._thread_pool.shutdown(wait=True)
        while not self._tab_pool.empty():
            self._tab_pool.get().close()

    def return_active_web_tab(self, tab):
        """
        使用完进行归还到tab池中
        """
        if tab.states.is_loading:
            sleep(1)  # 休息一秒在归还
            self.return_active_web_tab(tab)
        else:
            tab.run_cdp("Page.stopLoading")
            # 使用次数上限为100次,超过就关闭掉,这是为了解决tab请求过多后,会阻塞请求的bug
            if self._tab_dic.get(tab) > 100:
                tab.close()  # 关闭标签页
                self._create_tab()
            else:
                self._tab_pool.put(tab)

    def operate(self, func, **kwargs):
        """
        :param func: 要执行的方法
                kwargs:额外的参数
        :return:
        """

        def carry_out_func():
            tab = self.get_active_web_tab()
            func(tab, kwargs)
            self.return_active_web_tab(tab)

        self._thread_pool.submit(carry_out_func)


def test1(tab, kwargs):
    print(kwargs)
    tab.get("https://www.baidu.com")
    tab.ele('#kw').input('hello world')
    tab.ele('#su').click()


if __name__ == '__main__':
    pool = TabPool(size=8)
    for i in range(1, 10000):
        pool.operate(test1, kwargs=123)
    pool.close_web_page_pool()

上面的类tab_pool,可以用于管理多个tab(标签页)进行不同的操作

用此来实现多线程爬虫

该类会管理线程的创建和销毁

管理tab资源的调度和释放

只需要传入要执行的操作进行即可,如test1就是要执行的操作

实现多标签页的多线程爬虫

代码仓库 dp_pligin: drisseionPage增强插件 (gitee.com)