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

为何未修改的网页爬虫代码每次运行输出结果不一致?

问题分析与解决方案

你的爬虫结果不稳定,核心原因是页面交互后未等待数据完全渲染就抓取内容,加上一些不稳定的选择器和资源复用问题,导致每次运行结果不一致。以下是针对性的修复方案:

核心问题拆解

  • 点击"Show All"后立即获取HTML,此时表格数据可能还在异步加载,导致抓取到不完整的内容
  • popup.wait_for_load_state("domcontentloaded")仅等待弹窗DOM加载完成,但动态渲染的表格数据并未加载完毕
  • 依赖tables[7]这种固定索引定位表格,页面结构稍有变动就会出错,且加载不完全时索引对应的表格也会异常
  • 每次循环重新启动浏览器,不仅效率低,还可能因浏览器启动/关闭的状态问题导致交互异常

修复方案与代码修改

1. 复用浏览器实例,避免重复启动关闭

把浏览器启动移到循环外,每次循环只打开新页面,减少资源开销和状态异常。

2. 精准等待数据加载完成

点击"Show All"后,等待表格的具体元素出现(比如表格的tbody行),确保数据完全渲染后再抓取HTML。

3. 替换不稳定的选择器

不用text="%s"匹配赛马名称,改用更精准的文本定位方式,避免文本匹配的歧义。

4. 移除全局变量,改用参数传递

全局变量容易导致循环中的状态混乱,改成函数参数传递状态变量,避免意外的状态覆盖。

5. 动态定位目标表格

不再依赖固定索引定位表格,通过表格内容关键词匹配,提升鲁棒性。

修改后的完整代码

import pandas as pd
import xlwings as xw
from playwright.sync_api import sync_playwright

# 初始化Excel连接
wb = xw.Book("jockeyclub.xlsx")
rc1 = wb.sheets['Race Card 1']

def scrape_ranking(page, horse_name, sheet_name, tablerow):
    print(f"处理马匹: {horse_name}")
    
    # 点击赛马名称(精准文本定位)
    with page.expect_popup() as popup_info:
        page.click(f"text='{horse_name}'")
    
    popup = popup_info.value
    # 等待弹窗内网络请求完全结束
    popup.wait_for_load_state("networkidle")
    
    # 点击Show All按钮
    show_all_btn = popup.get_by_alt_text("Show All")
    show_all_btn.click()
    
    # 等待表格数据加载:等待表格行元素出现,超时10秒
    popup.wait_for_selector("table tbody tr", timeout=10000)
    # 再次等待网络空闲,确保所有数据渲染完成
    popup.wait_for_load_state("networkidle")
    
    html = popup.content()
    popup.close()  # 仅关闭弹窗,保留浏览器实例
    
    # 动态定位目标表格:通过表格内容关键词匹配
    tables = pd.read_html(html)
    target_df = None
    for table in tables:
        # 假设目标表格包含Race Date这类标识性字段
        if "Race Date" in str(table.columns) or "Race Date" in str(table.values):
            target_df = table
            break
    
    if target_df is not None:
        print(target_df)
        # 写入Excel
        rc1.range(f'A{tablerow-1}').value = horse_name
        with pd.ExcelWriter("jockeyclub.xlsx", engine="openpyxl", mode='a', if_sheet_exists='overlay') as writer:
            target_df.to_excel(writer, sheet_name=sheet_name, index=False, startrow=tablerow)
        # 根据表格实际行数调整下一个表格的起始位置
        return tablerow + len(target_df) + 5
    else:
        print(f"未找到{horse_name}的有效表格")
        return tablerow + 10

def main():
    rownum = 6
    tablerow = 20
    url = "https://racing.hkjc.com/racing/information/English/raCing/RaceCard.aspx?RaceDate=2023/04/15&Racecourse=ST&RaceNo=1"
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(url)
        # 等待主页面加载完成
        page.wait_for_load_state("networkidle")
        
        while rownum <= 13:
            horse_name = rc1.range(f'E{rownum}').value
            if not horse_name:
                print(f"第{rownum}行无马匹名称,跳过")
                rownum += 1
                continue
            # 调用抓取函数,更新下一个表格的起始行
            tablerow = scrape_ranking(page, horse_name, "Race Card 1", tablerow)
            rownum += 1
        
        browser.close()

if __name__ == "__main__":
    main()

关键修改说明

  • 浏览器复用:全程只启动一次浏览器,循环内复用页面,减少资源开销和状态异常
  • 等待策略优化:使用networkidle等待网络请求完成,同时等待表格元素出现,确保数据完全渲染
  • 动态表格定位:不再依赖固定索引,通过表格内容关键词匹配目标表格,避免页面结构变动导致的错误
  • 状态管理优化:移除全局变量,改用参数传递状态,避免循环中的状态混乱
  • 异常防护:增加对空马匹名称的判断,避免无效点击操作

内容的提问来源于stack exchange,提问作者NNBananas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 10:35:13