
本文详细阐述了如何通过发布-订阅模式,结合消息队列(如Kafka或RabbitMQ)和Selenium WebDriver,实现多个独立浏览器实例的并行自动化,并模拟各自独立的鼠标操作。教程涵盖了系统架构、核心组件(领导者、追随者、消息队列)的职责,并提供了实现思路和关键注意事项,旨在帮助开发者构建高效、可扩展的多浏览器自动化解决方案。
在现代Web自动化测试或数据抓取场景中,经常需要同时在多个独立的浏览器实例中执行任务,并且每个实例都需要模拟独立的鼠标移动和点击操作。传统的自动化库,如pyautogui,通常只能控制一个全局的鼠标光标,无法满足多浏览器独立操作的需求。直接的虚拟化方案虽然能隔离环境,但通常开销较大,且在模拟独立鼠标操作方面仍需额外机制。本文将介绍一种基于发布-订阅(Pub-Sub)模式的解决方案,它能有效解决这一复杂挑战。
核心挑战在于操作系统层面的鼠标光标通常是唯一的。要在多个独立的浏览器中模拟各自的鼠标操作,意味着这些操作必须在每个浏览器进程的“内部”进行,而不是通过模拟物理鼠标。Selenium WebDriver提供了这样的能力,它允许我们通过编程方式控制浏览器内部的DOM元素,包括模拟点击、输入以及将鼠标移动到特定元素上。然而,如何协调和分发这些独立的指令到多个并行运行的浏览器实例,是实现的关键。
发布-订阅模式是一种消息传递模式,它将消息的发送者(发布者)与接收者(订阅者)解耦。在这种模式下,发布者发送消息到特定的“主题”或“通道”,而订阅者则监听这些主题并接收消息。这非常适合我们多浏览器并行的场景:
整个系统将由以下核心组件构成:
每个追随者程序需要启动自己的浏览器实例。
# 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 == "navigate":
self.driver.get(value)
print(f"Follower {self.browser_id}: Navigated to {value}")
elif action == "click":
element = self.driver.find_element_by_css_selector(selector)
element.click()
print(f"Follower {self.browser_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": "navigate", "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", "navigate", 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", "navigate", 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": "navigate", "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": "navigate", "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自动化任务提供了高效的解决方案。
以上就是并行控制多个独立浏览器实例并模拟独立鼠标操作的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号