如何记录Selenium/WebDriver启动浏览器中的手动用户操作?
问题描述
我希望记录由Selenium/WebDriver启动的浏览器中的手动用户操作。目前我的脚本可以正常记录自动化操作,但无法记录/打印我在浏览器中执行的手动操作,请问我哪里出错了?
我的脚本
from selenium import webdriver import logging from selenium.webdriver.common.by import By from selenium.webdriver.support.events import EventFiringWebDriver from selenium.webdriver.support.events import AbstractEventListener logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s') class MyListener(AbstractEventListener): def __init__(self, logger): super().__init__() self.logger = logger def before_navigate_to(self, url, driver): self.logger.info(f"Laden der Seite: {url}") def before_find(self, by, value, driver): self.logger.info(f"Suche nach {by} mit dem Wert {value}.") def after_find(self, by, value, driver): self.logger.info(f"Element gefunden: {by} mit dem Wert {value}.") def before_click(self, element, driver): print(f"Klick auf {element}.") self.logger.info(f"Klick auf {element}.") def after_click(self, element, driver): print(f"Klick auf {element} beendet.") self.logger.info(f"Klick auf {element} beendet.") def before_change_value_of(self, element, driver): print(f"Eingabe in {element}.") self.logger.info(f"Eingabe in {element}.") def after_change_value_of(self, element, driver): print(f"Eingabe in {element} beendet.") self.logger.info(f"Eingabe in {element} beendet.") chrome_options = webdriver.ChromeOptions() chrome_options.add_experimental_option('excludeSwitches', ['enable-logging']) chrome_options.add_experimental_option("detach", True) driver = webdriver.Chrome(options=chrome_options) driver = EventFiringWebDriver(driver, MyListener(logging)) driver.get("https://www.google.com/") nutzungsb = driver.find_element(By.ID,"W0wltc") nutzungsb.click() search_box = driver.find_element(By.NAME,"q") search_box.send_keys("user_input") search_box.submit()
日志输出(app.log)
2023-03-10 10:39:32,961:INFO:Laden der Seite: https://www.google.com/ 2023-03-10 10:39:34,720:INFO:Suche nach id mit dem Wert W0wltc. 2023-03-10 10:39:34,753:INFO:Element gefunden: id mit dem Wert W0wltc. 2023-03-10 10:39:34,753:INFO:Klick auf <selenium.webdriver.remote.webelement.WebElement (session="ba492d8265b7d98601d6c58daafd1d81", element="4e348086-9653-461c-bf8e-6dfc8129c608")>. 2023-03-10 10:39:34,843:INFO:Klick auf <selenium.webdriver.remote.webelement.WebElement (session="ba492d8265b7d98601d6c58daafd1d81", element="4e348086-9653-461c-bf8e-6dfc8129c608")> beendet. 2023-03-10 10:39:34,843:INFO:Suche nach name mit dem Wert q. 2023-03-10 10:39:34,862:INFO:Element gefunden: name mit dem Wert q. 2023-03-10 10:39:34,862:INFO:Eingabe in <selenium.webdriver.remote.webelement.WebElement (session="ba492d8265b7d98601d6c58daafd1d81", element="9174f201-0095-4c9b-9344-ee2fa54bb56b")>. 2023-03-10 10:39:34,937:INFO:Eingabe in <selenium.webdriver.remote.webelement.WebElement (session="ba492d8265b7d98601d6c58daafd1d81", element="9174f201-0095-4c9b-9344-ee2fa54bb56b")> beendet.
问题原因与解决方案
原因
你使用的AbstractEventListener只负责监听WebDriver自身发起的命令,只有当通过Selenium API调用点击、输入等操作时,这些事件才会被触发。而手动操作是直接在浏览器中发起的,WebDriver默认不会捕获这类用户交互事件,所以你的监听器无法记录手动操作。
解决方案
要记录手动操作,需要通过页面注入JavaScript监听事件,或者利用浏览器DevTools协议捕获用户交互。
方案1:注入JavaScript监听页面事件
通过Selenium向页面注入JS代码,监听click、input等用户事件,将事件信息存储在页面全局变量中,再定期通过WebDriver读取这些信息并记录。
修改后的示例脚本:
from selenium import webdriver import logging import time from selenium.webdriver.common.by import By from selenium.webdriver.support.events import EventFiringWebDriver from selenium.webdriver.support.events import AbstractEventListener logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s') class MyListener(AbstractEventListener): def __init__(self, logger): super().__init__() self.logger = logger def before_navigate_to(self, url, driver): self.logger.info(f"Laden der Seite: {url}") def before_find(self, by, value, driver): self.logger.info(f"Suche nach {by} mit dem Wert {value}.") def after_find(self, by, value, driver): self.logger.info(f"Element gefunden: {by} mit dem Wert {value}.") def before_click(self, element, driver): print(f"Klick auf {element}.") self.logger.info(f"Klick auf {element}.") def after_click(self, element, driver): print(f"Klick auf {element} beendet.") self.logger.info(f"Klick auf {element} beendet.") def before_change_value_of(self, element, driver): print(f"Eingabe in {element}.") self.logger.info(f"Eingabe in {element}.") def after_change_value_of(self, element, driver): print(f"Eingabe in {element} beendet.") self.logger.info(f"Eingabe in {element} beendet.") def inject_manual_event_listener(driver): # 注入JS,监听点击和输入事件,存储到window.manualEvents数组 js_script = """ window.manualEvents = []; document.addEventListener('click', function(e) { let elemInfo = { type: 'click', tagName: e.target.tagName, id: e.target.id || '无ID', className: e.target.className || '无类名', timestamp: new Date().toISOString() }; window.manualEvents.push(elemInfo); }); document.addEventListener('input', function(e) { let elemInfo = { type: 'input', tagName: e.target.tagName, id: e.target.id || '无ID', className: e.target.className || '无类名', value: e.target.value, timestamp: new Date().toISOString() }; window.manualEvents.push(elemInfo); }); """ driver.execute_script(js_script) def log_manual_events(driver, logger): # 读取页面中存储的手动事件并记录 events = driver.execute_script("return window.manualEvents || [];") for event in events: if event['type'] == 'click': msg = f"手动点击元素: 标签={event['tagName']}, ID={event['id']}, 类名={event['className']}, 时间={event['timestamp']}" elif event['type'] == 'input': msg = f"手动输入内容: 标签={event['tagName']}, ID={event['id']}, 类名={event['className']}, 内容={event['value']}, 时间={event['timestamp']}" logger.info(msg) print(msg) # 清空已记录的事件,避免重复记录 driver.execute_script("window.manualEvents = [];") chrome_options = webdriver.ChromeOptions() chrome_options.add_experimental_option('excludeSwitches', ['enable-logging']) chrome_options.add_experimental_option("detach", True) driver = webdriver.Chrome(options=chrome_options) driver = EventFiringWebDriver(driver, MyListener(logging)) driver.get("https://www.google.com/") # 注入手动事件监听器 inject_manual_event_listener(driver) nutzungsb = driver.find_element(By.ID,"W0wltc") nutzungsb.click() search_box = driver.find_element(By.NAME,"q") search_box.send_keys("user_input") search_box.submit() # 等待用户执行手动操作,实际场景可放在循环中定期检查 print("等待用户执行手动操作...") time.sleep(10) log_manual_events(driver, logging)
方案2:使用Chrome DevTools协议监听事件
如果需要更全面的交互记录,可以利用Selenium的DevTools接口,直接通过浏览器协议捕获鼠标、键盘等操作,无需注入JS。
示例代码片段:
# 启用DevTools的Input模块 driver.execute_cdp_cmd('Input.enable', {}) # 监听鼠标点击事件 def on_mouse_event(event): if event['params']['type'] == 'mousePressed': logging.info(f"手动鼠标点击: x={event['params']['x']}, y={event['params']['y']}, 按钮={event['params']['button']}") driver.add_cdp_listener('Input.dispatchMouseEvent', on_mouse_event) # 监听键盘输入事件 def on_key_event(event): if event['params']['type'] == 'keyDown' and 'text' in event['params']: logging.info(f"手动键盘输入: 字符={event['params']['text']}") driver.add_cdp_listener('Input.dispatchKeyEvent', on_key_event)
注意事项
- 注入JS的方式受页面内容安全策略(CSP)限制,若页面有严格的CSP配置,脚本可能无法执行。
- DevTools协议仅支持Chromium内核浏览器(Chrome、Edge等),不同浏览器的事件名称可能略有差异。
内容的提问来源于stack exchange,提问作者Malta
相关产品推荐
相关产品推荐

