
本文详细阐述了如何通过发布-订阅模式,结合消息队列(如Kafka或RabbitMQ)和Selenium WebDriver,实现多个独立浏览器实例的并行自动化,并模拟各自独立的鼠标操作。教程涵盖了系统架构、核心组件(领导者、追随者、消息队列)的职责,并提供了实现思路和关键注意事项,旨在帮助开发者构建高效、可扩展的多浏览器自动化解决方案。
在现代Web自动化测试或数据抓取场景中,经常需要同时在多个独立的浏览器实例中执行任务,并且每个实例都需要模拟独立的鼠标移动和点击操作。传统的自动化库,如pyautogui,通常只能控制一个全局的鼠标光标,无法满足多浏览器独立操作的需求。直接的虚拟化方案虽然能隔离环境,但通常开销较大,且在模拟独立鼠标操作方面仍需额外机制。本文将介绍一种基于发布-订阅(Pub-Sub)模式的解决方案,它能有效解决这一复杂挑战。
核心挑战在于操作系统层面的鼠标光标通常是唯一的。要在多个独立的浏览器中模拟各自的鼠标操作,意味着这些操作必须在每个浏览器进程的“内部”进行,而不是通过模拟物理鼠标。Selenium WebDriver提供了这样的能力,它允许我们通过编程方式控制浏览器内部的DOM元素,包括模拟点击、输入以及将鼠标移动到特定元素上。然而,如何协调和分发这些独立的指令到多个并行运行的浏览器实例,是实现的关键。
发布-订阅模式是一种消息传递模式,它将消息的发送者(发布者)与接收者(订阅者)解耦。在这种模式下,发布者发送消息到特定的“主题”或“通道”,而订阅者则监听这些主题并接收消息。这非常适合我们多浏览器并行的场景:
整个系统将由以下核心组件构成:
Notion Sites
Notion 推出的AI网站构建工具,允许用户将 Notion 页面直接发布为完整网站。
246
查看详情
每个追随者程序需要启动自己的浏览器实例。
# follower_program.py (simplified)
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
class BrowserFollower:
def __init__(self, browser_id):
self.browser_id = browser_id
self.driver = self._initialize_driver()
print(f"Follower {self.browser_id}: Browser initialized.")
def _initialize_driver(self):
# 可以配置不同的端口、用户数据目录等,以确保完全独立
options = webdriver.ChromeOptions()
# options.add_argument(f"--user-data-dir=/tmp/chrome_profile_{self.browser_id}")
# options.add_argument("--headless") # 根据需要选择是否无头模式
driver = webdriver.Chrome(options=options)
return driver
def execute_command(self, command):
action = command.get("action")
target = command.get("target")
value = command.get("value")
selector = command.get("selector")
try:
if action == "n*igate":
self.driver.get(value)
print(f"Follower {self.browser_id}: N*igated to {value}")
elif action == "click":
element = self.driver.find_element_by_css_selector(selector)
element.click()
print(f"Follower {self.bro
wser_id}: Clicked {selector}")
elif action == "mouse_move_to_element":
element = self.driver.find_element_by_css_selector(selector)
ActionChains(self.driver).move_to_element(element).perform()
print(f"Follower {self.browser_id}: Mouse moved to {selector}")
elif action == "mouse_move_by_offset":
x_offset = command.get("x_offset", 0)
y_offset = command.get("y_offset", 0)
ActionChains(self.driver).move_by_offset(x_offset, y_offset).perform()
print(f"Follower {self.browser_id}: Mouse moved by ({x_offset}, {y_offset})")
# ... 其他自动化操作
else:
print(f"Follower {self.browser_id}: Unknown action {action}")
except Exception as e:
print(f"Follower {self.browser_id}: Error executing {action} on {selector}: {e}")
def close(self):
self.driver.quit()
print(f"Follower {self.browser_id}: Browser closed.")
# 实际运行时,每个 follower 进程会实例化一个 BrowserFollower
# follower = BrowserFollower("instance_1")
# follower.execute_command({"action": "n*igate", "value": "https://www.google.com"})
# follower.close()领导者程序将任务分解成具体指令,并通过MQ发送。
# leader_program.py (simplified with a hypothetical MQ client)
import json
import time
# from some_mq_client import MQProducer # 替换为实际的Kafka/RabbitMQ客户端
class LeaderProgram:
def __init__(self, mq_producer_client):
self.producer = mq_producer_client
self.command_topic = "browser_commands"
self.feedback_topic = "browser_feedback"
def send_command(self, browser_id, action, **kwargs):
command = {
"browser_id": browser_id,
"action": action,
**kwargs
}
message = json.dumps(command).encode('utf-8')
# self.producer.publish(self.command_topic, message, key=browser_id) # Kafka example with key for partitioning
print(f"Leader: Sent command to {browser_id}: {command}")
# In a real scenario, you'd send via your MQ client
# For demonstration, we'll just print
def run_automation_scenario(self):
# 场景1: 浏览器1导航并点击
self.send_command("browser_instance_1", "n*igate", value="https://www.bing.com")
time.sleep(2)
self.send_command("browser_instance_1", "click", selector="#id_h") # 假设是搜索框
# 场景2: 浏览器2导航并移动鼠标
self.send_command("browser_instance_2", "n*igate", value="https://www.baidu.com")
time.sleep(3)
self.send_command("browser_instance_2", "mouse_move_to_element", selector="#s_lg_img") # 假设是百度logo
# 可以发送更多指令...
# Example usage (without actual MQ client for simplicity)
# producer = MQProducer(...) # Initialize your MQ producer
# leader = LeaderProgram(producer)
# leader.run_automation_scenario()每个追随者进程将连接到MQ并消费消息。
# follower_process_n.py (simplified with a hypothetical MQ client)
import json
# from some_mq_client import MQConsumer # 替换为实际的Kafka/RabbitMQ客户端
# Assuming BrowserFollower class is defined as above
def run_follower(browser_id):
follower = BrowserFollower(browser_id)
# consumer = MQConsumer(topic="browser_commands", group_id="browser_followers") # Kafka example
print(f"Follower {browser_id}: Listening for commands...")
try:
# In a real scenario, this would be a loop consuming from MQ
# For demonstration, we'll simulate receiving a few commands
# For actual MQ, you'd use consumer.poll() or similar
simulated_commands = [
{"browser_id": browser_id, "action": "n*igate", "value": "https://www.google.com"} if browser_id == "browser_instance_1" else None,
{"browser_id": browser_id, "action": "click", "selector": "input[name='q']"} if browser_id == "browser_instance_1" else None,
{"browser_id": browser_id, "action": "n*igate", "value": "https://www.example.com"} if browser_id == "browser_instance_2" else None,
{"browser_id": browser_id, "action": "mouse_move_by_offset", "x_offset": 50, "y_offset": 50} if browser_id == "browser_instance_2" else None,
]
for cmd in simulated_commands:
if cmd and cmd["browser_id"] == browser_id:
print(f"Follower {browser_id}: Received command: {cmd}")
follower.execute_command(cmd)
time.sleep(1) # Simulate processing time
except KeyboardInterrupt:
print(f"Follower {browser_id}: Shutting down...")
finally:
follower.close()
# consumer.close() # Close MQ consumer
if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
run_follower(sys.argv[1])
else:
print("Usage: python follower_process_n.py <browser_id>")
# To run:
# python follower_process_n.py browser_instance_1
# python follower_process_n.py browser_instance_2通过采用发布-订阅模式,结合消息队列和Selenium WebDriver,我们可以构建一个强大且可扩展的系统,以并行方式控制多个独立的浏览器实例,并精确模拟各自的鼠标操作。这种架构不仅解决了单一鼠标光标的限制,还通过解耦提高了系统的鲁棒性和可维护性,为复杂的Web自动化任务提供了高效的解决方案。
以上就是并行控制多个独立浏览器实例并模拟独立鼠标操作的教程的详细内容,更多请关注其它相关文章!
# python
# css
# 渝中区seo优化咨询
# 苏州网络营销推广公司
# 武汉seo新站优化
# 临清律师网站推广
# 新区域网站排行榜优化
# 放心营销推广有哪些
# 医院市场营销推广书籍
# 企业网站推广优化技巧
# 国际贸易网站推广系统
# 绍兴网站建设的地方
# 是一种
# 这一
# 都是
# 无头
# 如何使用
# 中分
# 客户端
# 自己的
# 多个
# 鼠标
# cookie
# apache
# docker
# go
# node
# json
# node.js
# js
# java
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
个人所得税办理入口 个人所得税综合所得年度汇算入口
ExcelSCAN与LAMBDA如何创建自定义移动平均函数_SCAN实现任意窗口期移动平均计算
iPhone12是否要更新ios16
iSpring三分屏制作教程
抖音手机分身两个账号怎么切换?分身两个系统是一样的吗?
如何在 WordPress 前端实现内容提交:古腾堡编辑器的替代方案与实践
cad怎么隐藏指定的图层_cad隐藏或冻结图层方法
b站怎么设置动态仅粉丝可见_b站动态粉丝可见设置方法
TikTok搜索结果不显示怎么办 TikTok搜索刷新与优化方法
被称为海蜈蚣的海洋动物是
PHP utf8_encode 字符编码转换陷阱与解决方案
sublime text 4如何安装_最新版sublime下载与汉化教程
圆通快递官网入口查询单号 手机版官方查询入口
小米手机截图后如何查看历史_小米手机截图历史记录查看方法
解决jQuery多计算器输入字段冲突的教程
Go语言反射机制下访问嵌入结构体中的被遮蔽方法
TikTok网页版实时观看入口 TikTok网页版短视频在线浏览
Word如何将文字快速转成表格 Word文本转换成表格功能使用技巧【效率】
《海底捞》点外卖方法
MacBook Pro词典使用指南
哈尔滨城市通昵称修改方法
mysql中如何配置字符集和排序规则_mysql字符集排序配置
search中maxlength属性用法解析
电脑开不了机怎么办 电脑无法开机的解决方法
《procreate》绘制渐变效果教程
Go Goroutine调度与并发执行深度解析
电脑“无法访问指定设备、路径或文件”怎么办?五种权限设置方法
苹果手机怎么合并照片_苹果手机合并多张照片的操作方法
Magento 2 产品保存事件中安全更新属性的最佳实践
c++如何掌握指针的核心用法_c++指针入门到精通指南
AO3永久镜像入口开放_AO3最新网址兼容所有浏览器
苹果如何下载nanobanana
win11怎么设置默认终端为Windows Terminal Win11替代CMD和PowerShell【技巧】
Yandex浏览器官方入口_Yandex搜索引擎中文版
J*a中为什么强调组合优于继承_组合模式带来的灵活性与可维护性解析
构建可配置的J*aScript加权点击计数器与共享总计功能
steam缓存文件在哪儿_steam缓存文件的路径查找方法与结构说明
腾讯QQ邮箱官方入口 QQ邮箱网页版登录平台
创建您的便携版VS Code:让配置随身携带
《波斯王子:失落的王冠》剑术大师打法攻略
Sublime怎么格式化HTML代码_Sublime前端代码美化插件使用指南
抖音评论无法发送如何修复 抖音评论功能操作指南
C++中std::thread和std::async的区别_C++并发编程与线程与异步任务比较
《知到》打卡课程方法
J*aScript 数值去小数位处理:多种方法与实践
广州地铁app准妈咪徽章领取方法
《撕歌》会员开通方法
高效调试PHP大型嵌套数组:JSON序列化与可视化工具实践
以下哪一个是适应长期护理制度发展而设立的新职业
Dash应用多值文本输入处理与类型转换教程
2025-12-12
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。