You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用nodriver实现多页面跳转时获取新页面元素报错:AttributeError及Event Loop已关闭问题

nodriver实现多页面跳转时获取新页面元素报错:AttributeError及Event Loop已关闭问题

我来帮你分析和解决这两个问题,看起来都是对nodriver的异步页面跳转逻辑理解不到位导致的:

首先看AttributeError: 'NoneType' object has no attribute 'find'的原因

你这里的page2 = await improve.click()是错误的——nodriver里元素的click()方法只是执行点击动作,不会返回新页面的实例,所以page2其实是None,这就导致后面调用page2.find()直接报错。

要获取跳转后的新页面,应该从driver的pages列表里取,因为新打开的页面会自动添加到这个列表中。

然后是RuntimeError: Event loop is closed的问题

这个问题主要是两个原因:

  1. 你混用了同步的time.sleep()和异步代码,同步sleep会阻塞asyncio的事件循环,导致nodriver无法正常处理页面事件,后续资源清理时出问题;
  2. 程序报错退出时,driver没有被正确关闭,导致子进程的资源没有被释放,当事件循环已经关闭后,子进程的transport还尝试操作,就会抛出这个错误。

修正后的完整代码

import asyncio
import nodriver as uc
import pyautogui

async def b_start_chrome_and_log_in():
    driver = None
    try:
        print("start chrome")
        # 启动Chrome实例
        driver = await uc.start(maximize=True)
        # 窗口最大化(如果nodriver的maximize=True生效,这步可以去掉)
        pyautogui.click(x=1181, y=38)
        # 访问目标网站
        page = await driver.get('https://www.mytpi.com/')
        # 用asyncio.sleep替代time.sleep,避免阻塞事件循环
        await asyncio.sleep(2)
        
        # 定位下拉菜单元素
        improve = await page.find('/html/body/nav/div/ul/li[4]/a')
        await asyncio.sleep(2)
        
        # 记录当前页面数量,用于判断新页面是否加载
        original_page_count = len(driver.pages)
        # 执行点击动作
        await improve.click()
        
        # 等待新页面出现
        while len(driver.pages) == original_page_count:
            await asyncio.sleep(0.3)
        
        # 获取最新打开的页面(列表最后一个元素)
        page2 = driver.pages[-1]
        await asyncio.sleep(2)
        
        # 定位目标元素
        swing = await page2.find('/html/body/div[2]/div/div/ul/li[1]/div/a/span')
        print("成功找到目标元素!")
    finally:
        # 确保无论是否报错,driver都能被正确关闭
        if driver is not None:
            await driver.close()

asyncio.run(b_start_chrome_and_log_in())

额外的几个建议

  • 尽量避免使用绝对xpath,页面结构稍微变动就会定位失败,优先用元素的id、class或者文本内容来定位,比如await page.find('.improve-menu', by='css')或者await page.find('Improve my Game', by='text');
  • 如果nodriver版本支持,可以用await driver.wait_for_new_page()来替代手动轮询页面数量,这个方法更优雅;
  • 不要依赖固定的sleep时长,可以用await page.wait_for_selector()来等待元素加载,比固定sleep更可靠,比如await page2.wait_for_selector('/html/body/div[2]/div/div/ul/li[1]/div/a/span')之后再去find元素。

备注:内容来源于stack exchange,提问作者steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 14:45:29