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

如何修复Vanguard共同基金web scraping代码运行数据不一致问题

问题定位

你遇到的偶发数据丢失问题核心有三个原因:

  • 等待逻辑不合理:使用绝对路径XPATH等待固定行号加载,不同基金表格行数不一致,且绝对路径极易受页面结构微调影响,经常出现表格内容未完全渲染就触发了抓取逻辑,导致键名文本缺失,只剩下值。
  • 元素选择容错性差:直接用索引取第三个role="presentation"的表格,页面加载顺序或者结构稍有变动,就会取错表格,自然拿不到对应字段。
  • 无校验重试机制:抓取完成后没有校验核心字段是否存在,哪怕数据不全也直接往下执行。
修复方案

1. 替换等待逻辑

不要用绝对路径的结构等待,改用业务字段等待,确保你需要的核心字段已经渲染完成再执行抓取:

# 替换原有WebDriverWait行,等待两个核心字段都出现在页面中
WebDriverWait(browser, 20).until(EC.text_to_be_present_in_element((By.TAG_NAME, 'body'), 'Average effective maturity'))
WebDriverWait(browser, 20).until(EC.text_to_be_present_in_element((By.TAG_NAME, 'body'), 'Average duration'))

2. 优化表格定位逻辑

不要通过索引取表格,改为通过表格内的特征字段匹配,确保取到的是目标概览表:

# 原有htmlData = mySoup.findAll(...) 及之后行替换为如下逻辑
htmlData = mySoup.findAll('table',{'role':'presentation'})
overview_table = None
for table in htmlData:
    table_content = table.get_text()
    if 'Fund total net assets' in table_content and 'Average duration' in table_content:
        overview_table = table
        break
if not overview_table:
    print(f"{symbol} 未找到目标概览表,跳过")
    continue
overviewDataList = extractOverviewTable(overview_table)

3. 增加重试与校验机制

给每个基金增加最多3次重试逻辑,抓取完成后校验核心字段是否存在,不存在就重试:

for symbol in symbols:
    max_retry = 3
    retry_count = 0
    overviewDataList = None
    while retry_count < max_retry:
        browser.get(url_vanguard.format(symbol))
        print(symbol)
        try:
            # 等待核心字段加载
            WebDriverWait(browser, 20).until(EC.text_to_be_present_in_element((By.TAG_NAME, 'body'), 'Average duration'))
            html = browser.page_source
            mySoup = BeautifulSoup(html, 'html.parser')
            # 定位概览表
            htmlData = mySoup.findAll('table',{'role':'presentation'})
            overview_table = None
            for table in htmlData:
                table_content = table.get_text()
                if 'Fund total net assets' in table_content and 'Average duration' in table_content:
                    overview_table = table
                    break
            if not overview_table:
                retry_count +=1
                continue
            # 提取数据
            overviewDataList = extractOverviewTable(overview_table)
            # 校验核心字段是否存在
            if 'Average effective maturity' in overviewDataList and 'Average duration' in overviewDataList:
                break
        except TimeoutException:
            print(f"{symbol} 加载超时,第{retry_count+1}次重试")
        retry_count +=1
    if not overviewDataList or 'Average duration' not in overviewDataList:
        print(f"{symbol} 多次重试后仍无法获取完整数据")
        continue
    # 后续业务逻辑

4. 优化提取函数容错性

避免空行、无span元素的情况导致提取失败:

def extractOverviewTable(htmlTable):
    table = htmlTable.find('tbody')
    rows = table.findAll('tr')
    returnDict = {}
    for row in rows:
        cols = row.findAll('td')
        if len(cols) < 2:
            continue
        # 兼容没有span的场景
        key_span = cols[0].find('span')
        if key_span:
            key = key_span.text.replace('\n', '').strip()
        else:
            key = cols[0].text.replace('\n', '').strip()
        value = cols[1].text.replace('\n', '').strip()
        if 'Layer' in key:
            key = key[:key.index('Layer')].strip()
        if not key:
            continue
        returnDict[key] = value
    return returnDict

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:36:01