如何用Python的BeautifulSoup4爬取相邻兄弟节点数据(AAPL Basic EPS)
问题:爬取雅虎财经AAPL的Basic EPS数值失败
尝试用Python脚本从https://finance.yahoo.com/quote/AAPL/financials爬取AAPL的Basic EPS行数据时,原代码多次打印“Basic EPS”但无法获取相邻的数值字段。
原代码
#!/usr/bin/env python3 import os, pandas as pd from os import chdir #Web scraping from bs4 import BeautifulSoup import urllib.request as ul chdir(os.getcwd()+"/Data") colist="AAPL" header = {'User-Agent': 'Mozilla/5.0'} #prevents a 403 error req=ul.Request("https://finance.yahoo.com/quote/"+colist+"/financials", headers=header) page = ul.urlopen(req) soup=BeautifulSoup(page, "lxml") for div_parent in soup.find("div",class_="rowTitle svelte-1xjz32c",title="Basic EPS"): print(div_parent.text) for div_child in div_parent.find_next_siblings("div",class_="column svelte-1xjz32c"): print(div_child.text)
页面相关HTML结构
<div class="row lv-0 svelte-1xjz32c"><div class="column sticky svelte-1xjz32c"> <div class="rowTitle svelte-1xjz32c" title="Basic EPS">Basic EPS</div></div> <div class="column svelte-1xjz32c alt">6.46 </div><div class="column svelte-1xjz32c">6.16 </div><div class="column svelte-1xjz32c alt">6.15 </div><div class="column svelte-1xjz32c">5.67 </div><div class="column svelte-1xjz32c alt">3.31 </div></div> <div class="row lv-0 svelte-1xjz32c"><div class="column sticky svelte-1xjz32c"> <div class="rowTitle svelte-1xjz32c" title="Diluted EPS">Diluted EPS</div></div> <div class="column svelte-1xjz32c alt">6.43 </div><div class="column svelte-1xjz32c">6.13 </div><div class="column svelte-1xjz32c alt">6.11 </div><div class="column svelte-1xjz32c">5.61 </div><div class="column svelte-1xjz32c alt">3.28 </div></div>
解决思路与代码调整方案
问题分析
原代码的核心错误:
soup.find(...)获取的是"Basic EPS"文本所在的rowTitle元素,直接遍历该元素会遍历其内部的文本节点,导致重复打印"Basic EPS"- 数值字段并不在
rowTitle的兄弟节点中,而是在rowTitle的父级容器(column sticky)的同级节点里,所有数值和标题都属于同一个row容器。
正确思路
- 定位到包含"Basic EPS"的
rowTitle元素 - 向上遍历DOM树,找到该元素所在的最外层
row容器(class为row lv-0 svelte-1xjz32c) - 在这个
row容器内,筛选所有非sticky类型的column元素,提取它们的文本内容,即为目标EPS数值
调整后的代码
#!/usr/bin/env python3 import os import pandas as pd from os import chdir from bs4 import BeautifulSoup import urllib.request as ul # 切换到Data目录(目录不存在则创建) try: chdir(os.path.join(os.getcwd(), "Data")) except FileNotFoundError: os.mkdir("Data") chdir("Data") colist = "AAPL" header = {'User-Agent': 'Mozilla/5.0'} req = ul.Request(f"https://finance.yahoo.com/quote/{colist}/financials", headers=header) page = ul.urlopen(req) soup = BeautifulSoup(page, "lxml") # 1. 找到Basic EPS对应的rowTitle元素 basic_eps_title = soup.find("div", class_="rowTitle svelte-1xjz32c", title="Basic EPS") if basic_eps_title: # 2. 向上找到所在的row容器(rowTitle -> column sticky -> row) row_container = basic_eps_title.parent.parent # 3. 提取所有非sticky的column元素的文本,去除空格 eps_values = [col.get_text(strip=True) for col in row_container.find_all("div", class_="column svelte-1xjz32c") if "sticky" not in col.get("class", [])] print("Basic EPS数值:") for val in eps_values: print(val) else: print("未找到Basic EPS对应的行")
代码说明
- 增加目录异常处理,避免因Data目录不存在导致报错
- 通过
parent.parent直接定位到row容器,匹配HTML结构层级 - 用列表推导式筛选非sticky的column元素,同时清理数值前后的空格
- 增加元素存在性判断,避免空指针异常
内容的提问来源于stack exchange,提问作者murkywaters
相关产品推荐
相关产品推荐

