【Selenium】提高测试爬虫效率:Selenium与多线程的完美结合

news2024/11/25 0:50:40

插入图片

前言

使用Selenium 创建多个浏览器,这在自动化操作中非常常见。

而在Python中,使用 Selenium + threading Selenium + ThreadPoolExecutor 都是很好的实现方法。

应用场景:

  • 创建多个浏览器用于测试或者数据采集;
  • 使用Selenium 控制本地安装的 chrome浏览器 去做一些操作

文章提供了 Selenium + threading Selenium + ThreadPoolExecutor 结合的代码模板,拿来即用。



知识点📖📖

作用链接
threading用于实现多线程https://docs.python.org/zh-cn/3/library/threading.html
concurrent.futures.ThreadPoolExecutor 使用线程池来异步执行调用https://docs.python.org/zh-cn/3/library/concurrent.futures.html

上面两个都是 Python 内置模块,无需手动安装~


导入模块

import threading
from concurrent.futures import ThreadPoolExecutor, as_completed



多线程还是线程池?

Selenium中,使用 多线程 或者是 线程池,差别并不大。主要都是网络I/O的操作。

在使用 ThreadPoolExecutor 的情况下,任务将被分配到不同的线程中执行,从而提高并发处理能力。与使用 threading 模块相比,使用 ThreadPoolExecutor 有以下优势:

  1. 更高的并发处理能力:线程池 可以动态地调整线程数量,以适应任务的数量和处理要求,从而提高并发处理能力。
  2. 更好的性能:线程池 可以根据任务的类型和大小动态地调整线程数量,从而提高性能和效率。

总之,使用 线程池 可以提高并发处理能力,更易于管理,并且可以提供更好的性能和效率。

但是选择多线程,效果也不差。

所以使用哪个都不必纠结,哪个代码量更少就选哪个自然是最好的。


多个浏览器✨

Selenium自动化中需要多个浏览器,属于是非常常见的操作了。
不管是用于自动化测试、还是爬虫数据采集,这都是个可行的方法。

这里示例的代码中,线程池的运行时候只有 多线程 的一半!!!

多线程与 多 浏览器🧨

这份代码的应用场景会广一些,后续复用修改一下 browser_thread 函数的逻辑就可以了。

这里模拟相对复杂的操作,在创建的浏览器中新打开一个标签页,用于访问指定的网站。
然后切换到新打开的标签页,进行截图。



代码释义:

  • 定义一个名为 start_browser 的函数,用于创建 webdriver.Chrome 对象。
  • 定义一个名为 browser_thread 的函数,接受一个 webdriver.Chrome 对象和一个整数作为参数,用于打开指定网页并截图。 切换到最后一个窗口,然后截图。
  • main函数创建了5个浏览器,5个线程,执行上面的操作,然后等待所有线程执行完毕。
# -*- coding: utf-8 -*-
# Name:         multi_thread.py
# Author:       小菜
# Date:         2023/6/1 20:00
# Description:


import threading
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService

from webdriver_manager.chrome import ChromeDriverManager


def start_browser():
    service = ChromeService(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)
    return driver


def browser_thread(driver: webdriver.Chrome, idx: int):
    url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
                'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']

    try:
        driver.execute_script(f"window.open('{url_list[idx]}')")
        driver.switch_to.window(driver.window_handles[-1])
        driver.save_screenshot(f'{idx}.png')
        return True
    except Exception:
        return False


def main():
    for idx in range(5):
        driver = start_browser()
        threading.Thread(target=browser_thread, args=(driver, idx)).start()

    # 等待所有线程执行完毕
    for thread in threading.enumerate():
        if thread is not threading.current_thread():
            thread.join()


if __name__ == "__main__":
    main()

运行结果

  • 运行时长在9.28秒(速度与网络环境有很大关系,木桶效应,取决于最后运行完成的浏览器
  • 看到程序运行完成后,多出了5张截图。

在这里插入图片描述

线程池与 多 浏览器🎍

这份代码与 多线程与 多浏览器 的操作基本一致。速度上却比多线程节省了一半。

# -*- coding: utf-8 -*-
# Name:         demo2.py
# Author:       小菜
# Date:         2023/6/1 20:00
# Description:


from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from concurrent.futures import ThreadPoolExecutor, as_completed

MAX_WORKERS = 5
service = ChromeService(ChromeDriverManager().install())


def start_browser():
    driver = webdriver.Chrome(service=service)
    return driver


def browser_task(driver: webdriver.Chrome, idx: int):
    url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
                'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']

    try:
        driver.execute_script(f"window.open('{url_list[idx]}')")
        driver.switch_to.window(driver.window_handles[-1])
        driver.save_screenshot(f'{idx}.png')
        return True
    except Exception:
        return False


def main():
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
    ths = list()
    for idx in range(5):
        driver = start_browser()
        th = executor.submit(browser_task, driver, idx=idx)
        ths.append(th)

    # 获取结果
    for future in as_completed(ths):
        print(future.result())


if __name__ == "__main__":
    main()

运行结果

  • 运行时长在4.5秒(运行效果图不是很匹配,但确实是比多线程快很多。
  • 看到程序运行完成后,多出了5张截图。在这里插入图片描述

多个标签页

这个的应用场景有点意思。

这里的操作与上面的 多个浏览器其实是差不多的。
区别在于:上面打开多个浏览器,这里打开多个标签页。

所以这个需要考量一个问题:资源争夺。与是这里用上了 threading.Lock 锁,用以保护资源线程安全。

多线程与 多 标签页🎃

代码释义:

  • 与上面差不多,不解释了。
# -*- coding: utf-8 -*-
# Name:         demo2.py
# Author:       小菜
# Date:         2023/6/1 20:00
# Description:

import threading
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService

from webdriver_manager.chrome import ChromeDriverManager

service = ChromeService(ChromeDriverManager().install())
lock = threading.Lock()


def start_browser():
    driver = webdriver.Chrome(service=service)
    return driver


def browser_thread(driver: webdriver.Chrome, idx: int):
    url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
                'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']
    try:
        lock.acquire()
        driver.execute_script(f"window.open('{url_list[idx]}')")
        driver.switch_to.window(driver.window_handles[idx + 1])
        driver.save_screenshot(f'{idx}.png')
        return True
    except Exception:
        return False
    finally:
        lock.release()


def main():
    driver = start_browser()
    for idx in range(5):
        threading.Thread(target=browser_thread, args=(driver, idx)).start()

    # 等待所有线程执行完毕
    for thread in threading.enumerate():
        if thread is not threading.current_thread():
            thread.join()


if __name__ == "__main__":
    main()

运行结果

在这里插入图片描述

线程池与 多 标签页👀

这里不展示运行结果了,因为效果与 多线程与 多 标签页 一致。

# -*- coding: utf-8 -*-
# Name:         thread_pool.py
# Author:       小菜
# Date:         2023/6/1 20:00
# Description:

import time
import threading

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from concurrent.futures import ThreadPoolExecutor, as_completed

MAX_WORKERS = 5
service = ChromeService(ChromeDriverManager().install())
lock = threading.Lock()


def start_browser():
    driver = webdriver.Chrome(service=service)
    return driver


def browser_task(driver: webdriver.Chrome, idx: int):
    url_list = ['https://www.csdn.net/', 'https://www.baidu.com',
                'https://music.163.com/', 'https://y.qq.com/', 'https://cn.vuejs.org/']

    try:
        lock.acquire()
        driver.execute_script(f"window.open('{url_list[idx]}')")
        driver.switch_to.window(driver.window_handles[idx + 1])
        driver.save_screenshot(f'{idx}.png')
        return True
    except Exception:
        return False
    finally:
        lock.release()


def main():
    driver = start_browser()
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
    ths = list()
    for idx in range(5):
        th = executor.submit(browser_task, driver, idx=idx)
        ths.append(th)

    # 获取结果
    for future in as_completed(ths):
        print(future.result())


if __name__ == "__main__":
    st = time.time()
    main()
    et = time.time()
    print(et - st)

总结⚡⚡

本文章介绍了 Selenium + threading Selenium + ThreadPoolExecutor 来创建多个浏览器或多个标签页的操作。

文中示例的代码比较简单,所以 线程池多线程 运行的更加快。
但在实际的使用过程中,可以根据自己的喜好去选择 线程池 还是 多线程

后话

本次分享到此结束,

see you~🐱‍🏍🐱‍🏍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/599385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Region Proposal Network (RPN) 架构详解

动动发财的小手,点个赞吧! 简介 如果您正在阅读这篇文章[1],那么我假设您一定听说过用于目标检测的 RCNN 系列,如果是的话,那么您一定遇到过 RPN,即区域提议网络。如果您不了解 RCNN 系列,那么我…

Github copilot的详细介绍,竞品比对分析,效率使用方法总结。

Copilot介绍,与竞品对比 Copilot是GitHub和OpenAI合作开发的一款人工智能代码助手,它可以根据用户输入的注释和代码片段,自动生成高质量的代码。Copilot使用了OpenAI的GPT模型,可以学习和理解大量的代码库和文档,从而…

javascript基础十三:说说 typeof 与 instanceof 区别?

一、typeof typeof 操作符返回一个字符串,表示未经计算的操作数的类型 举个粟子: typeof 1 number typeof 2 string typeof undefined undefined typeof false boolean typeof Symbol() symbol typeof null object typeof [] object typeof {} object…

TCP传输性能的关键因素除了流量控制,还有这些!

TCP网络通信基本原理 文章目录 TCP网络通信基本原理TCP效率(滑动窗口)流量控制拥塞控制延时应答捎带应答 面向字节流异常情况分析总结UDP/TCP特性与不同应用场景 TCP效率(滑动窗口) 滑动窗口:在TCP通信协议下&#xf…

【UnityShader入门精要】【总结记录】【第二章-2】

☀️博客主页:CSDN博客主页 💨本文由 萌萌的小木屋 原创,首发于 CSDN💢 🔥学习专栏推荐:面试汇总 ❗️游戏框架专栏推荐:游戏实用框架专栏 ⛅️点赞 👍 收藏 ⭐留言 📝&a…

1901-2021年1km分辨率逐月最高气温栅格数据(全国/分省)

气温数据是我们最常用的气象指标之一,之前我们给大家分享过来源于国家青藏高原科学数据中心提供的1901-2021年1km分辨率逐月平均气温栅格数据(可查看之前的文章获悉详情)! 本次我们分享的同样是来自国家青藏高原科学数据中心的高…

【探索】在 JavaScript 中使用 C 程序

JavaScript 是个灵活的脚本语言,能方便的处理业务逻辑。当需要传输通信时,我们大多选择 JSON 或 XML 格式。 但在数据长度非常苛刻的情况下,文本协议的效率就非常低了,这时不得不使用二进制格式。 去年的今天,在折腾…

Redis中的整数集合(IntSet)

Redis节省内存的两个优秀设计思想:一个是使用连续的内存空间,避免内存碎片开销;二个是针对不同长度的数据,采用不同大小的元数据,以避免使用统一大小的元数据,造成内存空间的浪费。IntSet便具备以上两个设计…

160套小程序源码

源码列表如下: AppleMusic (知乎日报) 微信小程序 d artand 今日更新求职招聘类 医药网 口碑外卖点餐 城市天气 外卖小程序 定位天气 家居在线 微信小程序-大好商城,wechat-weapp 微信小程序的掘金信息流 微信跳一跳小游戏源码 微票源码-demo 急救应急处…

MyBatis- plus

实战总结 1.批量插入性能 1.批量插入性能差的原因 使用saveBatch()方法时, MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入&a…

2023企业真实性能测试常见面试题分析

简述性能测试流程? 1.分析性能需求。挑选用户使用最频繁的场景来测试,比如:登陆,搜索,下单等等。确定性能指标,比如:事务通过率为100%,TOP99%是5秒,最大并发用户为1000人…

Three.js——八、坐标、更改模型原点、移除、显示隐藏模型对象

世界坐标.getWorldPosition() 基础坐标也就是模型的.position属性 世界坐标:就是模型资深.position和所有父对象.position累加的坐标 用.getWorldPosition()属性需要用三维向量表示摸个坐标后方可读取 例如: const geometry new THREE.BoxGeometry(10…

【Qt】createEditor进不去【2023.05.07】

摘要 妈卖批,因为这个函数进不去,emo了一下午。实际上就是因为函数声明和定义的地方漏了个const关键字。 1.正确✔: QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) cons…

Rocketmq面试(三)消息积压,增加消费者有用么?

目录 一.广播模式和集群模式的不同 二.延迟拉取 三.消费者延迟拉取消息的原因 四.增加消费者后是如何分配MessageQueue(引出负载策略) 一.广播模式和集群模式的不同 首先我们要强调一下。在广播模式(每条消息需要被消费者组中的每个消费者处理,也就是…

QT/PyQT/PySide 通过富文本形式实现关键词高亮

因为本质上都是QT,所以我标题带了QT,这个思路是没问题的,就是用C得换个语言。 最开始想根据之前一篇博客的思路进行高亮 PyQT/PySide 文本浏览器跳转到指定行,并高亮指定行_qt 指定行高亮_Toblerone_Wind的博客-CSDN博客https:/…

Linux 设备树文件手动编译的 Makefile

前言 通过了解 Linux 设备树的编译方法,手动写了一个可以把 dts、dtsi、设备树依赖头文件等编译为设备树 dtb 的 Makefile Makefile 如下 mkfile_path : $(abspath $(lastword $(MAKEFILE_LIST))) cur_makefile_path : $(dir $(mkfile_path))DIR_ROOT : $(cur_ma…

十三届蓝桥杯国赛2022

会得噶 A 2022B 钟表C 卡牌D 最大数字dfsF 费用报销&#xff08;不是根据收据个数&#xff0c;而是根据日期dp)H 机房&#xff08;最近公共祖先lca&#xff09;I 齿轮J 搬砖&#xff08;贪心01背包&#xff09; A 2022 #include <bits/stdc.h> using namespace std; int …

Openlayers如何设置米作为作为圆形的真实半径,解决圆形半径跟随地图缩放同时缩放的失真问题

专栏目录: OpenLayers入门教程汇总目录 前言 相信找到这篇文章的同学肯定遇到了Openlayers直接设置圆形半径( radius)单位不准确的问题,而且失真严重。这是因为默认圆形半径设置的是浏览器像素大小,而不是真实地理信息中的半径长度。那么怎么进行转换成我们现实中的“米…

python+vue校园快递代取系统的设计与实现3i0v9

开发语言&#xff1a;Python 框架&#xff1a;django/flask Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 本系统名为“基于vue快递代取系统”&#xff0c;系统主要适用于毕业设计&#xff0c;不…

【数据分享】1929-2022年全球站点的逐日最高气温(Shp\Excel\12000个站点)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01; 之前我们分享过1929-2022年全球气象站…