登录后使用Python Selenium ActionChains触发JavascriptException: Cyclic object value错误
登录后使用Python Selenium ActionChains触发JavascriptException: Cyclic object value错误
你遇到的这个问题确实挺让人头疼的——明明上周还正常,现在只要在自定义的登录函数之后调用ActionChains执行Ctrl+Click打开新标签,就会抛出JavascriptException: Message: Cyclic object value,但登录前完全正常。
先还原下你的场景:
- 环境:Python 3 + Jupyter Notebook + Selenium Firefox驱动
- 登录前测试ActionChains完全成功:
import time from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys driver = webdriver.Firefox() driver.get('http://google.com') element = driver.find_element(By.LINK_TEXT, 'Terms') for x in range(1,5): ActionChains(driver) \ .key_down(Keys.CONTROL) \ .click(element) \ .key_up(Keys.CONTROL) \ .perform() print("Upstream of login ActionChains successful")
- 调用login函数后,同样的操作就报错:
login(driver) element2 = driver.find_element(By.LINK_TEXT, 'About') ActionChains(driver) \ .key_down(Keys.CONTROL) \ .click(element2) \ .key_up(Keys.CONTROL) \ .perform() print("Downstream of login ActionChains successful")
- 报错栈指向Selenium的W3C Actions序列化环节,是Firefox Marionette驱动在处理JS对象时碰到了循环引用。
可能的原因和解决办法
原因分析
这个错误本质是Selenium的W3C Actions API在序列化动作指令时,遇到了页面中存在循环引用的JS对象(比如页面全局变量、第三方脚本创建的循环引用结构)。登录后的页面跳转改变了浏览器的JS上下文,刚好触发了这个问题。
具体解决方案
1. 用原生JS替代ActionChains实现开新标签
最稳妥的办法是绕开ActionChains,直接调用浏览器的JS API打开新标签,完全避免动作序列化的问题:
# 替换原来的ActionChains代码 element2 = driver.find_element(By.LINK_TEXT, 'About') driver.execute_script("window.open(arguments[0].href, '_blank');", element2)
这种方式兼容性更好,也不会受页面JS上下文的影响。
2. 重置ActionChains的动作上下文
在登录后显式重置ActionChains的状态,清空之前的动作缓存:
login(driver) # 重置ActionChains的动作队列 actions = ActionChains(driver) actions.reset_actions() element2 = driver.find_element(By.LINK_TEXT, 'About') actions.key_down(Keys.CONTROL)\ .click(element2)\ .key_up(Keys.CONTROL)\ .perform()
同时可以在登录后加上页面焦点重置,确保浏览器上下文正常:
driver.execute_script("window.focus();")
3. 优化登录函数的页面跳转方式
你的login函数最后用link.send_keys(Keys.RETURN)跳转页面,换成link.click()可能会避免一些上下文异常:
def login(driver, username, password): driver.implicitly_wait(5) driver.get("http://mywebsite.com") elem = driver.find_element(By.ID, "Username") elem.clear() elem.send_keys(username) elem = driver.find_element(By.ID, "Password") elem.clear() elem.send_keys(password) elem.send_keys(Keys.RETURN) # 替换成click()跳转 link = driver.find_element(By.ID, "NextSection") link.click() return
4. 确保页面完全加载后再执行操作
登录后等待页面完全加载完成,避免在页面JS未初始化完成时执行ActionChains:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC login(driver) # 显式等待目标元素加载完成 WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, 'About'))) # 再执行操作 element2 = driver.find_element(By.LINK_TEXT, 'About') ActionChains(driver)\ .key_down(Keys.CONTROL)\ .click(element2)\ .key_up(Keys.CONTROL)\ .perform()
尝试上面的方法,应该能解决你遇到的循环对象值报错问题。
备注:内容来源于stack exchange,提问作者jackal555
相关产品推荐
相关产品推荐

