首页 > 其他分享 >selenium单例模式下 docker-chrome 多线程并发代码

selenium单例模式下 docker-chrome 多线程并发代码

时间:2024-10-23 09:21:00浏览次数:8  
标签:chrome selenium self driver BrowserManager def 多线程 opts browser

最近需要写爬虫,在解决docker-standalone-chrome 发现只能有一个chrome被执行。所以写了这个多线程并发控制类来管理。当模板记录下。


#! /usr/bin/env python3
import threading
import traceback

from loguru import logger
from selenium import webdriver
from selenium.common import WebDriverException
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from selenium.webdriver.common.by import By
import json
from utils.configs import ScreenshotDir, ChromeUserDataDir, REMOTE_DRIVER


def options():
    """默认选项"""
    opts = webdriver.ChromeOptions()
    opts.add_argument(f"user-data-dir={ChromeUserDataDir}")
    opts.page_load_strategy = 'eager'
    opts.add_experimental_option('excludeSwitches', ['enable-automation'])  # 开发者模式
    opts.add_argument("--disable-popup-blocking")  # 关闭操作bar
    opts.add_argument("--blink-settings=imagesEnabled=false")  # 禁用图片
    opts.add_argument("--window-size=1920,1080")  # 窗口大小
    opts.add_argument("--no-sandbox")  # 无沙箱
    opts.add_argument("--disable-gpu")
    # opts.add_argument('--headless')  # 无头模式
    # opts.add_experimental_option('debuggerAddress', '127.0.0.1:9222')  # 指定server
    return opts


class Browser:
    """浏览器,线程不安全"""

    def __init__(self, opts=None):
        if not opts:
            opts = options()
        self.driver = webdriver.Remote(command_executor=REMOTE_DRIVER, options=opts)
        # self.driver = webdriver.Chrome(options=opts)

    def quit(self):
        try:
            if hasattr(self, 'driver') and hasattr(self.driver, 'quit'):
                self.driver.quit()
                self.driver = None
        except Exception as e:
            logger.error("browser quit err:{e}\ntraceback:{traceback}".format(e=e, traceback=traceback.format_exc()))

    def send(self, cmd, params):
        """发送命令"""
        resource = "/session/%s/chromium/send_command_and_get_result" % self.driver.session_id
        url = self.driver.command_executor._url + resource
        body = json.dumps({'cmd': cmd, 'params': params})
        response = self.driver.command_executor._request('POST', url, body)
        return response.get('value')

    def get(self, url) -> None:
        logger.info(f'browser starting open url={url}')
        self.driver.get(url)
        logger.info(f'browser open suc url={url}')

    def wait_by_xpath(self, path, timeout=10) -> None:
        try:
            WebDriverWait(self.driver, timeout, 1, ignored_exceptions=(WebDriverException,)).until(
                EC.element_to_be_clickable((By.XPATH, path)))
        except Exception:
            logger.error(f'browser wait xpath not find')

    def wait_by_id(self, tid, timeout=10) -> None:
        try:
            WebDriverWait(self.driver, timeout, 1, ignored_exceptions=(WebDriverException,)).until(
                EC.presence_of_element_located((By.ID, tid)))
        except Exception:
            logger.error(f'browser wait id not find')

    def save(self, path):
        with open(path, 'w', encoding='utf-8') as fw:
            fw.write(self.get_page_source())

    def get_page_source(self) -> str:
        return self.driver.page_source

    def click(self, path):
        try:
            button = self.driver.find_element(By.XPATH, path)
            if button:
                button.click()
                time.sleep(2)
                # 跳转到新标签
                windows = self.driver.window_handles
                self.driver.switch_to.window(windows[-1])

                return self.driver.current_url
            else:
                return ""
        except Exception as e:
            logger.error(f'browser click err={e}')

    def screenshot(self, name=None):
        full_name = 'full_page_screenshot.png'
        if name:
            full_name = name
        screenshot_path = f'{ScreenshotDir}/{full_name}'
        self.driver.save_screenshot(screenshot_path)


class BrowserManager:
    """浏览器管理类,线程安全
    usages:
        with BrowserManager() as browser:
            browser.get(url)
    """
    _browser = None
    _is_used = False
    _condition = threading.Condition()

    def __init__(self, opts=None):
        self.opts = opts

    def __enter__(self):
        with BrowserManager._condition:
            while BrowserManager._is_used:
                if not BrowserManager._condition.wait(timeout=10):
                    continue

            BrowserManager._is_used = True
            try:
                BrowserManager._browser = Browser(self.opts)
            except Exception as e:
                BrowserManager._is_used = False
                raise e

            return BrowserManager._browser

    def __exit__(self, exc_type, exc_value, traceback):
        with BrowserManager._condition:
            BrowserManager._browser.quit()
            BrowserManager._is_used = False
            BrowserManager._condition.notify()

用法就很简单了,例如


with BrowserManager() as browser:
    try:
        browser.get(url)
        return browser.get_page_source()
    except Exception as e:
        logger.error(e)

标签:chrome,selenium,self,driver,BrowserManager,def,多线程,opts,browser
From: https://www.cnblogs.com/haoabcd2010/p/18494433

相关文章

  • [Python] Selenium监控网络请求
      Selenium监控网络有两种方式,第一种使用代理,第二张是使用CDP(ChromeDevToolsProtocol)协议,下面直接进入主题分别介绍如何使用代理和CDP协议监控网络请求。  一、使用Selenium-Wire设置代理拦截处理请求。  Selenium-Wire是基于Selenium开发的抓包工具,基本使用方式如下:fr......
  • 新 Chrome 插件可检测 AI 伪造声音;Canary Speech 推出用于临床对话的语音分析技术丨 R
       开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(Real-TimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编......
  • 11-案例:多线程版用户聊天程序
    1.多线程版用户群聊程序的_多用户聊天运行结果2.多线程版用户群聊程序的_服务端代码3.多线程版用户群聊程序的_客户端代码4.多线程版用户群聊程序的_双用户聊天运行结果5.多线程版用户群聊程序的_双用户聊天运行服务端代码6.多线程版用户群聊程序的_双用户聊天运行客户端代码......
  • 【Linux线程】Linux多线程实践:深入生产者消费者模型
    ......
  • 【JavaEE】【多线程】单例模式
    目录一、设计模式1.1单例模式1.1.1饿汉模式1.1.2懒汉模式1.2线程安全问题1.3懒汉模式线程安全问题的解决方法1.3.1原子性问题解决1.3.2解决效率问题1.3.3解决内存可见性问题和指令重排序问题一、设计模式在讲解案例前,先介绍一个概念设计模式:就是大佬们......
  • 关于selenium 最近的更新记录
    1、导入元素操作方式有所变动,故导入的内容也要变更:fromselenium.webdriver.common.byimportBy2、获取元素的语句语句:driver.find_element(By.操作方式,"值")如获取ID:driver.find_element(By.ID,"值")获取类名:driver.find_element(By.CLASS_NAME,"值")获取CSS样式:driver......
  • 多线程(八):阻塞队列 & 生产者消费者模型
    目录1.阻塞队列 2.生产者消费者模型2.1场景举例2.2重要优势2.2.1解耦合 2.2.2削峰填谷2.3付出的代价3.BlockingQueue4.模拟实现阻塞队列4.1wait的注意事项4.2代码实现 1.阻塞队列在数据结构中,我们学习了简单的普通队列,也学习了较为复杂一些......
  • selenium执行页面滚动无效
    起因:​ 今天有个测试活动,需要记录一界面的状态,计划每10分钟截图记录。由于网页有失效时间,便考虑使用selenium定时登录,去目标页面,目标位置执行截图。问题:​ 在进入页面后,需滚动页面到最低部才能看到需要的数据图表。但是进入页面后,执行模拟滚动时,时常会无效。网上各种方法都尝......
  • 多线程模块threading
    1.简单例子importthreadingimporttimedefrun(n):print("task",n)time.sleep(2)t1=threading.Thread(target=run,args=("t1",))t2=threading.Thread(target=run,args=("t2",))t1.start()t2.start()2.真使用时需要用类importthreadingcl......
  • 一,多线程
    多线程详解:从基础到实践在现代编程中,多线程是一种常见的并发执行技术,它允许程序同时执行多个任务。本文将详细介绍多线程的基本概念、实现方式、线程控制、线程同步、死锁、线程间通信以及线程池等高级主题。多线程概述进程与线程进程:是系统进行资源分配和调用的独立单位,每一......