Pyppeteer脚本点击下一页时报错,如何实现全页面机构信息采集?
解决Pyppeteer翻页爬取时的TimeoutError和NetworkError问题
我看了你爬取印度所得税局豁免机构列表时遇到的问题——翻到5-10页左右就报超时或者Target closed错误,这在爬取加载较慢的政府网站时很常见,主要是页面加载不稳定、等待逻辑不够严谨导致的,咱们来一步步修复:
错误原因分析
- TimeoutError:点击下一页后,目标网站加载速度慢,默认30秒的等待时间不足以让元素完全显示;或者页面跳转后元素选择器的等待逻辑没有适配新页面的加载节奏。
- NetworkError (Target closed):大多是因为页面跳转时,还没等浏览器完成上下文切换就执行了后续操作,导致连接中断;也可能是浏览器沙箱模式的稳定性问题。
修改后的稳定版代码
import asyncio from pyppeteer import launch from pyppeteer.errors import TimeoutError, NetworkError url = "https://www.incometaxindia.gov.in/Pages/utilities/exempted-institutions.aspx" async def fetch_table(link): # 初始化浏览器时添加稳定性配置,模拟真实浏览器环境 browser = await launch( headless=False, args=[ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--window-size=1920,1080' ], defaultViewport=None ) page = await browser.newPage() # 延长页面导航超时到60秒,适配慢加载网站 await page.setDefaultNavigationTimeout(60000) # 等待网络空闲后再开始操作,确保页面完全加载 await page.goto(link, waitUntil='networkidle2') page_number = 1 while True: print(f"正在爬取第 {page_number} 页...") try: # 延长元素等待超时到60秒,确保元素加载完成 await page.waitForSelector("h1.faqsno-heading", {'visible': True, 'timeout': 60000}) # 用evaluate批量获取文本,比逐个查询更高效稳定 institutions = await page.evaluate(''' () => Array.from(document.querySelectorAll("h1.faqsno-heading div[id^='arrowex']")) .map(elem => elem.innerText.trim()) ''') for name in institutions: print(name) # 先等待下一页按钮可见且可点击,避免无效点击 next_btn = await page.waitForSelector("[title='Next Page']", {'visible': True, 'timeout': 30000}) # 检查按钮是否被禁用(最后一页的下一页按钮通常会禁用) is_disabled = await page.evaluate('btn => btn.disabled', next_btn) if is_disabled: print("已到达最后一页,停止爬取") break # 同时等待点击和页面跳转完成,确保页面完全切换后再继续 await asyncio.gather( page.waitForNavigation(waitUntil='networkidle2'), next_btn.click() ) page_number += 1 except TimeoutError: print(f"第 {page_number} 页加载超时,尝试跳过") page_number += 1 # 尝试刷新页面后继续,或者直接跳过 try: await page.reload(waitUntil='networkidle2') except: pass continue except NetworkError: print(f"网络连接异常,重新加载当前页") await page.reload(waitUntil='networkidle2') continue except Exception as e: print(f"遇到未知错误: {str(e)}") break await browser.close() if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(fetch_table(url))
关键改动说明
- 浏览器稳定性配置:添加
--no-sandbox等参数避免沙箱模式的兼容性问题,设置完整窗口尺寸模拟真实用户访问 - 更合理的超时设置:把页面导航和元素等待超时延长到60秒,适配政府网站较慢的加载速度
- 严谨的等待逻辑:
- 使用
waitUntil='networkidle2'等待网络空闲,确保页面资源完全加载 - 点击下一页时,用
asyncio.gather同时等待点击和页面跳转,避免页面未切换就执行后续操作 - 检查下一页按钮是否禁用,提前判断是否到达最后一页
- 使用
- 高效的数据采集:用
page.evaluate在浏览器端批量处理元素,减少Python和浏览器的通信次数,提升稳定性 - 针对性错误处理:对超时、网络错误分别处理,允许脚本自动恢复或跳过异常页面,保证整体爬取流程不中断
额外建议
目标网站可能有反爬机制,建议在翻页后添加短暂等待(比如await asyncio.sleep(2)),避免爬取速度过快被限制;如果还是出现问题,可以尝试切换为无头模式(headless=True),有时无头模式的稳定性更好。
内容的提问来源于stack exchange,提问作者robots.txt
相关产品推荐
相关产品推荐

