当前位置: 首页 > news >正文

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

前言

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

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

应用场景:

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

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

知识点📖📖

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

导入模块

import threading
from concurrent.futures import ThreadPoolExecutor, as_completed

多线程还是线程池?

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

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

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

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

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

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

多个浏览器✨

Selenium自动化中需要多个浏览器,属于是非常常见的操作了。

不管是用于自动化测试、还是爬虫数据采集,这都是个可行的方法。

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

多线程与 多 浏览器🧨

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

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

然后切换到新打开的标签页,进行截图。

代码释义:

  • 定义一个名为 start_browser 的函数,用于创建 webdriver.Chrome 对象。
  • 定义一个名为 browser_thread 的函数,接受一个 webdriver.Chrome 对象和一个整数作为参数,用于打开指定网页并截图。 切换到最后一个窗口,然后截图。
  • main函数创建了5个浏览器,5个线程,执行上面的操作,然后等待所有线程执行完毕。
# -*- coding: utf-8 -*-
# Name: multi_thread.py
# Author: 小月
# Date: 2023/10/26 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/10/26 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/10/26 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/10/26 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~🐱‍🏍🐱‍🏍

相关文章:

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

前言 使用Selenium 创建多个浏览器,这在自动化操作中非常常见。 而在Python中,使用 Selenium threading 或 Selenium ThreadPoolExecutor 都是很好的实现方法。 应用场景: 创建多个浏览器用于测试或者数据采集;使用Selenium 控…...

ElCLib类解析

OpenCascade 中的 ElCLib 类提供了对基本曲线(例如 2D 和 3D 空间中的二次曲线和直线)进行基本几何计算的函数。它提供与参数化、点评估和曲线参数范围内的定位相关的各种操作和计算。以下是一些需要注意的要点: 点和矢量计算:ElC…...

栈、队列、矩阵的总结

栈的应用 括号匹配 表达式求值(中缀,后缀) 中缀转后缀(机算) 中缀机算 后缀机算 总结 特殊矩阵 对称矩阵的压缩存储 三角矩阵 三对角矩阵 稀疏矩阵的压缩存储...

PCL 半径滤波剔除噪点

目录 一、算法原理二、注意事项三、代码实现一、算法原理 PCL半径滤波是删除在输入的点云一定范围内没有达到足够多领域的所有数据点。通俗的讲:就是以一个点p给定一个范围r,领域点要求的个数为m,r若在这个点的r范围内部的个数大于m则保留,小于m则删除。因此,使用该算法时…...

Android SurfaceFlinger做Layer合成时,如何与HAL层进行交互

目录 零、本文讨论问题的范围一、问题:SurfaceFlinger图层合成选择实现方式的两难1.1 从OpenGL ES、HWC本身来讲1.2 以HWC为主导的判断逻辑 二、SurfaceFlinger与HAL层进行交互的具体实现框架2.1 SurfaceFlinger 调用 OpenGL ES 流程2.2 FrameBuffer2.3 SurfaceFlin…...

华为eNSP配置专题-策略路由的配置

文章目录 华为eNSP配置专题-策略路由的配置0、概要介绍1、前置环境1.1、宿主机1.2、eNSP模拟器 2、基本环境搭建2.1、终端构成和连接2.2、终端的基本配置 3、配置接入交换机上的VLAN4、配置核心交换机为网关和DHCP服务器5、配置核心交换机和出口路由器互通6、配置PC和出口路由器…...

JAVA实现智能停车场管理系统 开源

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容A. 车主端功能B. 停车工作人员功能C. 系统管理员功能1. 停车位模块2. 车辆模块3. 停车记录模块4. IC卡模块5. IC卡挂失模块 三、界面展示3.1 登录注册3.2 车辆模块3.3 停车位模块3.4 停车数据模块3.5 IC卡档案模块3.6 IC卡挂…...

深入理解Docker之:存储卷相关概念详解和分析

深入理解Docker之:存储卷相关概念详解和分析 1. 为什么要使用存储卷 Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层,并在镜像栈顶部添加一个读写层如果运行中的容器修改了现有的一个已经存在的文件&#x…...

Node.js的基本概念node -v 和npm -v 这两个命令的作用

Node.js 是一个开源且跨平台的 JavaScript 运行时环境,它可以让你在服务器端运行 JavaScript 代码。Node.js 使用了 Chrome 的 V8 JavaScript 引擎来执行代码,非常高效。 在 Node.js 出现之前,JavaScript 通常只在浏览器中运行,用…...

mysql bin_log日志恢复数据

1、开启bin_log日志 开启方式1 my.ini 下配置开启或者vi /etc/my.cnf log_binmysql-bin server_id1 2、参考文章 https://blog.csdn.net/DreamEhome/article/details/130010601 (重点) 【mysql】binlog日志_mysql binlog日志-CSDN博客 MySQL 开启binlog日志和windows服务…...

C++系列之list的模拟实现

💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 list的节点类 template struct list_Node { public: list_Node* _prev; list_…...

什么情况下你会使用AI工具(chatgpt、bard)?

在当今数字化和智能化的时代,AI工具已成为许多领域的常见工具。在本文中,我将探讨什么情况下会使用AI工具。前言 – 人工智能教程 ChatGPT是一款由OpenAI开发的大型语言模型,可以生成文本、翻译语言、编写不同类型的创意内容,并以…...

【go】两数求和

文章目录 题目代码解法2 代码仓库 题目 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案…...

软考高项-成本管理

工具和技术 三点估算 通过考虑估算中的不确定性与风险,使用3种估算值来界定活动成本的近似区间,可以提高活动成本估算的准确性; 储备分析 为应对成本的不确定性,成本估算中可以包括应急储备。应急储备的管理方法: 将…...

24年FRM备考知识点以及一级公式表

FRM一级公示表以及备考知识点 链接:https://pan.baidu.com/s/17RpFF9OyfRk7FGtEQrxf3A?pwd1234 提取码:1234 FRM二级公示表以及备考知识点 链接:https://pan.baidu.com/s/175D05wV1p94dIfBZThutCQ?pwd1234 提取码:1234...

Spring Cloud学习:二【详细】

目录 Nacos的配置 Nacos的单机启动 服务注册 Nacos服务分级存储模型 优先访问同集群的服务 根据权重负载均衡 环境隔离Namespace Nacos调用流程 Nacos与Eureka注册对比 Nacos与Eureka的共同点 Nacos与Eureka的区别 Nacos配置管理 统一配置 配置自动刷新 多环境配…...

Unity的live2dgalgame多语言可配置剧情框架

这段代码用于读取表格 using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using OfficeOpenXml; using System.IO; using UnityEngine.Networking; using UnityEngine.UI; using Random UnityEngine.Random;public class Plots…...

再畅通工程(最小生成树)

题目描述:还是畅通工程 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)&…...

前后端分离不可忽视的陷阱,深入剖析挑战,分享解决方案,助你顺利实施分离开发。

不管你设计的系统架构是怎么样,最后都是你的组织内的沟通结构胜出。这个观点一直在组织内不断地被证明,但也不断地被忽略。 前后端分离的利与弊 近几年,随着微服务架构风格的引入、前后端生态的快速发展、多端产品化的出现,前后…...

(四)库存超卖案例实战——优化redis分布式锁

前言 在上一节内容中,我们已经实现了使用redis分布式锁解决商品“超卖”的问题,本节内容是对redis分布式锁的优化。在上一节的redis分布式锁中,我们的锁有俩个可以优化的问题。第一,锁需要实现可重入,同一个线程不用重…...

别被忽悠了!2026亲测靠谱的AI论文网站|避坑精选版

2026 年学术写作工具已高度分化,千笔AI与ThouPen为全流程首选,豆包、DeepSeek 为专项强手;避坑关键:拒绝假文献、严控 AIGC 率、优先国内适配、免费试用先行。 一、TOP3 全流程首选(亲测不踩雷) 1. 千笔AI&…...

3大实战秘籍:揭秘raylib如何让游戏开发像搭积木一样简单

3大实战秘籍:揭秘raylib如何让游戏开发像搭积木一样简单 【免费下载链接】raylib A simple and easy-to-use library to enjoy videogames programming 项目地址: https://gitcode.com/GitHub_Trending/ra/raylib 你是否曾经被复杂的游戏引擎配置搞得焦头烂额…...

基于随机森林的低成本传感器机器学习校准实践指南

1. 项目概述:当低成本传感器遇上机器学习校准在物联网和智能感知系统铺天盖地的今天,低成本传感器几乎无处不在。从监测办公室的空气质量,到追踪城市街道的噪音污染,再到农业大棚里的温湿度控制,这些价格亲民的“小眼睛…...

探索Windows 10上的Android世界:揭秘WSA-Windows-10项目的3个技术突破

探索Windows 10上的Android世界:揭秘WSA-Windows-10项目的3个技术突破 【免费下载链接】WSA-Windows-10 This is a backport of Windows Subsystem for Android to Windows 10. 项目地址: https://gitcode.com/gh_mirrors/ws/WSA-Windows-10 想象一下&#…...

基于C#实现(WinForm)P2P聊天程序

♻️ 资源 大小: 29.8MB ➡️ 资源下载:https://download.csdn.net/download/s1t16/87430269 p2p聊天程序 一、功能介绍 1.1 登录 用户凭用户名和密码登录系统,可以更换服务器 IP 和端口,以防网络不畅通,连接服务…...

如何快速定制Office界面:终极开源工具使用指南

如何快速定制Office界面:终极开源工具使用指南 【免费下载链接】office-ribbonx-editor An overhauled fork of the original Custom UI Editor for Microsoft Office, built with WPF 项目地址: https://gitcode.com/gh_mirrors/of/office-ribbonx-editor O…...

抖音批量下载助手:一键构建你的专属视频素材库

抖音批量下载助手:一键构建你的专属视频素材库 【免费下载链接】douyinhelper 抖音批量下载助手 项目地址: https://gitcode.com/gh_mirrors/do/douyinhelper 还在为手动保存抖音视频而烦恼吗?想要批量获取心仪创作者的精彩内容却无从下手&#x…...

独立开发者如何利用Taotoken的TokenPlan在项目初期有效控制AI实验成本

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 独立开发者如何利用Taotoken的TokenPlan在项目初期有效控制AI实验成本 对于独立开发者或学生而言,在构建AI应用原型时&…...

麒麟桌面CVE-2024-1086漏洞深度修复指南

1. 这个漏洞不是“修个补丁就完事”:麒麟桌面系统CVE-2024-1086的真实威胁图谱你可能刚在安全通告里看到“麒麟桌面系统修复CVE-2024-1086”,顺手点了个更新,心里想着“又一个内核提权漏洞,打上补丁不就完了?”——我去…...

eqMac终极指南:macOS系统级音频均衡器免费使用教程

eqMac终极指南:macOS系统级音频均衡器免费使用教程 【免费下载链接】eqMac macOS System-wide Audio Equalizer & Volume Mixer 🎧 项目地址: https://gitcode.com/gh_mirrors/eq/eqMac 你是否曾经觉得Mac电脑的音质不够理想?想要…...