新闻中心
使用Python爬取Yahoo财经动态收益数据教程

本教程旨在解决使用python爬取yahoo财经动态加载收益数据时遇到的挑战。传统基于`beautifulsoup`的静态html解析方法在此类场景中无效。文章将详细指导如何通过模拟浏览器对yahoo财经后端api的post请求,获取包含公司名称、事件类型和发布时间等详细收益信息的结构化json数据,并提供了完整的python代码示例及注意事项。
动态网页数据抓取的挑战
在尝试从Yahoo财经等现代网站抓取数据时,开发者常会遇到一个问题:即使使用requests库成功获取了页面内容,BeautifulSoup也无法找到预期的元素。这通常是因为网站采用了J*aScript动态加载数据。用户在浏览器中看到的实时数据并非直接嵌入在初始HTML中,而是通过J*aScript在页面加载后向后端API发起请求,并将返回的数据渲染到页面上。
对于Yahoo财经的收益日历页面,直接解析其HTML (https://finance.yahoo.com/calendar/earnings?day={date}) 往往只能获取到页面的静态骨架,而实际的收益数据(如公司名称、收益发布时间等)则是由J*aScript异步加载的。因此,传统的requests + BeautifulSoup组合无法直接获取到这些动态数据。
解决方案:模拟API请求
要成功抓取动态加载的数据,我们需要模拟浏览器发起的实际API请求。这通常涉及以下步骤:
- 识别API端点: 使用浏览器的开发者工具(通常是F12),在“网络”或“Network”选项卡中监控页面加载过程。当页面显示出目标数据时,查找类型为XHR/Fetch的请求,这些请求通常会返回JSON或XML格式的数据。
- 分析请求参数: 检查识别出的API请求的URL、请求方法(GET/POST)、请求头(Headers)、查询参数(Query Parameters)以及请求体(Request Payload)。这些信息对于成功模拟请求至关重要。
- 构建Python请求: 使用requests库根据分析结果构建并发送请求。
通过对Yahoo财经收益日历页面的分析,可以发现其动态数据是通过向 https://query2.finance.yahoo.com/v1/finance/visualization 这个API端点发送 POST 请求获取的。
构建API请求详情
模拟Yahoo财经API请求需要以下几个关键组成部分:
1. 请求头 (Headers)
User-Agent 是一个重要的请求头,它告诉服务器发起请求的客户端类型。模拟一个常见的浏览器User-Agent可以有效避免某些网站的简单反爬机制。
headers = {
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0",
}2. 查询参数 (URL Parameters)
URL中包含一些查询参数,这些参数通常用于指定语言、地区等信息。crumb 参数是一个安全令牌,它可能会随时间变化。在实际生产环境中,可能需要先从页面动态获取此crumb值。
易标AI
告别低效手工,迎接AI标书新时代!3分钟智能生成,行业唯一具备查重功能,自动避雷废标项
135
查看详情
params = {
"crumb": "EwuCwsPbKM2", # 此值可能需要动态获取
"lang": "en-US",
"region": "US",
"corsDomain": "finance.yahoo.com",
}3. JSON请求体 (Request Payload)
这是最核心的部分,它定义了要查询的数据类型、字段、过滤条件(如日期范围、地区)和排序方式。
- entityIdType: 指定查询实体类型,此处为"earnings"。
- includeFields: 一个列表,包含我们希望从API响应中获取的字段,例如ticker (股票代码), companyshortname (公司简称), eventname (事件名称), startdatetime (开始日期时间), `epsestimate (EPS预估)等。
- offset, size: 用于分页,offset表示偏移量,size表示每页返回的记录数。
- query: 这是一个嵌套的字典,定义了数据过滤逻辑。
- operands: 一个列表,每个元素定义一个过滤条件。
- 例如,{"operands": ["startdatetime", "2025-12-15"], "operator": "gte"} 表示startdatetime大于或等于2025-12-15。
- {"operands": ["startdatetime", "2025-12-16"], "operator": "lt"} 表示startdatetime小于2025-12-16。
- {"operands": ["region", "us"], "operator": "eq"} 表示region等于us。
- operator: 将多个条件组合起来的逻辑操作符,此处为"and"。
- operands: 一个列表,每个元素定义一个过滤条件。
- sortField, sortType: 定义结果的排序字段和排序方式。
query = {
"entityIdType": "earnings",
"includeFields": [
"ticker",
"companyshortname",
"eventname",
"startdatetime",
"startdatetimetype",
"epsestimate",
"epsactual",
"epssurprisepct",
"timeZoneShortName",
"gmtOffsetMilliSeconds",
],
"offset": 0,
"query": {
"operands": [
{"operands": ["startdatetime", "2025-12-15"], "operator": "gte"}, # 查询开始日期
{"operands": ["startdatetime", "2025-12-16"], "operator": "lt"}, # 查询结束日期 (不包含)
{"operands": ["region", "us"], "operator": "eq"},
],
"operator": "and",
},
"size": 100,
"sortField": "companyshortname",
"sortType": "ASC",
}4. Cookie
A3 cookie是另一个重要的组成部分,它可能与用户会话或认证有关。与crumb类似,这个cookie的值也可能动态变化,需要特别注意。在提供的示例中,它被硬编码,但在实际应用中,更稳健的方法是在每次请求前获取最新的A3 cookie。
# 此cookie值可能随时间变化,需要定期更新或动态获取 cookie = "d=AQABBK8KXmQCEA8-VE0dBLqG5QEpQ7OglmEFEgABCAHCeWWpZfNtb2UB9qMAAAcIqgpeZJj7vK8&S=AQAAAqhyTAOrxcxONc4ktfzCOkg"
完整代码示例
结合以上分析,我们可以构建一个完整的Python脚本来抓取指定日期的Yahoo财经收益数据。
import requests
from datetime import date, timedelta
def get_yahoo_earnings(target_date: date):
"""
从Yahoo财经API获取指定日期的收益数据。
Args:
target_date (date): 要查询的日期对象。
Returns:
list: 包含收益数据字典的列表,如果请求失败则返回空列表。
"""
headers = {
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0",
}
url = "https://query2.finance.yahoo.com/v1/finance/visualization"
# crumb参数可能需要动态获取,此处为示例值
params = {
"crumb": "EwuCwsPbKM2", # 注意:此值可能失效,需要从Yahoo页面动态抓取
"lang": "en-US",
"region": "US",
"corsDomain": "finance.yahoo.com",
}
# 构建查询日期范围
start_date_str = target_date.strftime("%Y-%m-%d")
end_date_str = (target_date + timedelta(days=1)).strftime("%Y-%m-%d")
query = {
"entityIdType": "earnings",
"includeFields": [
"ticker",
"companyshortname",
"eventname",
"startdatetime",
"startdatetimetype",
"epsestimate",
"epsactual",
"epssurprisepct",
"timeZoneShortName",
"gmtOffsetMilliSeconds",
],
"offset&qu
ot;: 0,
"query": {
"operands": [
{"operands": ["startdatetime", start_date_str], "operator": "gte"},
{"operands": ["startdatetime", end_date_str], "operator": "lt"},
{"operands": ["region", "us"], "operator": "eq"},
],
"operator": "and",
},
"size": 100, # 可根据需要调整每页返回数量
"sortField": "companyshortname",
"sortType": "ASC",
}
# A3 cookie也可能失效,需要动态获取
cookie = "d=AQABBK8KXmQCEA8-VE0dBLqG5QEpQ7OglmEFEgABCAHCeWWpZfNtb2UB9qMAAAcIqgpeZJj7vK8&S=AQAAAqhyTAOrxcxONc4ktfzCOkg"
earnings_data = []
with requests.Session() as s:
s.headers.update(headers)
s.cookies["A3"] = cookie # 设置A3 cookie
try:
response = s.post(url, params=params, json=query)
response.raise_for_status() # 检查HTTP错误
data = response.json()
if data and "finance" in data and "result" in data["finance"] and \
data["finance"]["result"] and data["finance"]["result"][0]["documents"]:
for doc in data["finance"]["result"][0]["documents"]:
if "rows" in doc:
for r in doc["rows"]:
# 提取并格式化数据
company_name = r[1] if len(r) > 1 else ""
event_name = r[2] if len(r) > 2 and r[2] else ""
start_datetime = r[3] if len(r) > 3 else ""
earnings_data.append({
"company_name": company_name,
"event_name": event_name,
"start_datetime": start_datetime
})
else:
print(f"API响应中未找到预期数据结构: {data}")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
except ValueError as e:
print(f"JSON解析错误: {e}")
return earnings_data
if __name__ == "__main__":
# 获取昨天的日期 (假设今天是周日,昨天是周六,我们需要周五的收益)
# 实际应用中,可以直接指定日期
today = date.today()
# 调整为上一个工作日,例如,如果今天是周日,则获取上周五的日期
target_date = today - timedelta(days=2) # 示例:如果今天是周日,这将是周五
print(f"尝试获取 {target_date.strftime('%Y-%m-%d')} 的收益数据...")
earnings = get_yahoo_earnings(target_date)
if earnings:
print(f"\n{target_date.strftime('%Y-%m-%d')} 收益数据:")
for item in earnings:
print(f"{item['company_name']:<40} {item['event_name']:<40} {item['start_datetime']:<30}")
else:
print(f"未能获取 {target_date.strftime('%Y-%m-%d')} 的收益数据。")
# 示例:获取特定日期的收益
specific_date = date(2025, 12, 15)
print(f"\n尝试获取 {specific_date.strftime('%Y-%m-%d')} 的收益数据...")
earnings_specific = get_yahoo_earnings(specific_date)
if earnings_specific:
print(f"\n{specific_date.strftime('%Y-%m-%d')} 收益数据:")
for item in earnings_specific:
print(f"{item['company_name']:<40} {item['event_name']:<40} {item['start_datetime']:<30}")
else:
print(f"未能获取 {specific_date.strftime('%Y-%m-%d')} 的收益数据。")示例输出 (根据实际API响应可能有所不同):
尝试获取 2025-12-15 的收益数据... 2025-12-15 收益数据: Lewis and Clark Bank Q3 2025 Earnings Release 2025-12-15T13:10:00.000Z Alzamend Neuro, Inc. 2025-12-15T16:32:00.000Z ATIF Holdings Ltd Q1 2025 Earnings Release 2025-12-15T21:00:00.000Z Barnwell Industries Inc Q4 2025 Earnings Release 2025-12-15T23:05:13.000Z Quanex Building Products Corp Q4 2025 Earnings Call 2025-12-15T16:00:00.000Z PharmaCyte Biotech, Inc. 2025-12-15T17:27:00.000Z Edesa Biotech, Inc. 2025-12-15T16:10:00.000Z Butler National Corporation 2025-12-15T09:47:00.000Z Enzo Biochem, Inc. 2025-12-15T16:17:00:00.000Z Everything Blockchain Inc Q3 2025 Earnings Release 2025-12-15T21:05:00.000Z ... (更多数据)
注意事项与最佳实践
-
动态crumb和cookie的处理: 示例代码中的crumb和A3 cookie是硬编码的。这些值可能会随时间变化或因用户会话而异。在生产环境中,建议实现一个机制来动态获取这些值。这通常涉及:
- 首先对Yahoo财经日历页面进行一次GET请求。
- 使用BeautifulSoup或正则表达式从响应HTML中提取crumb值。
- 从requests响应对象中获取并设置A3 cookie。
- 或者,使用如Selenium等无头浏览器库来模拟完整的浏览器行为,让其自动处理cookie和J*aScript渲染。
- 日期处理: query参数中的startdatetime是UTC时间。在构建查询时,请确保日期字符串格式正确 (YYYY-MM-DD),并考虑时区转换,以获取目标区域的准确日期数据。
- 错误处理: 务必添加健壮的错误处理机制,包括网络请求失败、JSON解析失败以及API响应结构不符合预期的情况。
- 速率限制与IP封锁: 频繁或高速的请求可能会触发网站的速率限制,导致IP被暂时或永久封锁。建议在请求之间添加适当的延迟 (time.sleep()),并考虑使用代理IP池。
- 数据字段: includeFields列表可以根据需要进行调整,以获取更多或更少的数据字段。
- 分页处理: 如果某一天的收益数据量超过size参数(例如100条),你需要通过调整offset参数来多次请求,以获取所有数据。
总结
通过模拟Yahoo财经的后端API请求,我们可以有效地绕过前端J*aScript渲染的限制,直接获取结构化的动态数据。这种方法比传统的BeautifulSoup解析更稳定、更高效,并且能够获取更精确的数据。然而,动态参数(如crumb和cookie)的管理是实现健壮爬虫的关键挑战,需要开发者投入额外精力进行动态获取和维护。遵循上述最佳实践,可以帮助您构建一个稳定且高效的Yahoo财经收益数据爬虫。
以上就是使用Python爬取Yahoo财经动态收益数据教程的详细内容,更多请关注其它相关文章!
# 每页
# 莱西企业推广网络营销
# 什么网站可以做优化
# 炎陵房地产营销推广公司
# 烤鱼营销推广语句大全集
# 玉溪网站怎么优化
# 药品营销推广开场白
# 关岭网站推广公司
# 宁波网站建设推广专家组
# 威海营销网站优化推广
# 忻州远程指导seo优化
# 分页
# 公司名称
# 后端
# 我们可以
# linux
# 周日
# 发布时间
# 是一个
# 加载
# 编码
# cookie
# 正则表达式
# json
# 前端
# js
# html
# java
# python
# javascript
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
Python异步编程实践:使用Binance API构建实时交易数据流
mc.js免安装版 mc.js一键畅玩入口
Descript怎样用AI剪辑自动去噪_Descript用AI剪辑自动去噪【自动降噪】
在哪找SublimeJ远程工具_SFTP插件配置教程
Win10磁盘清理工具在哪 Win10打开并使用磁盘清理【教程】
html两个JS只运行一个怎么办_让双JS在html中都运行方法【技巧】
批改网学生版PC登录 批改网官网登录系统入口
如何设置Windows Defender的定时扫描_计划任务实现自动杀毒【安全】
京东单号查询入口_京东快递订单追踪入口
sublime怎么覆盖插件的默认快捷键_sublime快捷键优先级与设置
抓大鹅解压小游戏 抓大鹅摸鱼解压入口
JUnit5/Mockito:优雅测试内部依赖与异常处理的实践
Steam官网入口直达 Steam注册及登录步骤
知音漫客正版漫画平台_知音漫客官网账号登录
NRF24L01数据传输深度解析:解决大载荷接收异常与分包策略
J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析
css卡片内容溢出如何处理_使用overflow隐藏或scroll显示内容
没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享
C++如何实现一个智能指针_手动实现C++ shared_ptr的引用计数功能
Bing引擎入口最新2025 Bing搜索免费官方登录
J*aScript生成器_j*ascript异步迭代
sublime如何配置Go语言开发环境_sublime搭建Golang编译运行系统
在J*aScript中复现SciPy的B样条拟合与求值:关键考量
内存检查:在VS Code中调试C++时的内存视图
神庙逃亡小游戏在线玩 神庙逃亡小游戏入口
Windows7怎么硬盘安装 Windows7提取ISO镜像到非系统盘并运行setup.exe实现硬盘直装【教程】
Node.js CSV 数据处理:基于字段空值条件过滤整条记录的策略
c++如何使用折叠表达式(Fold Expressions)_c++17可变参数模板新技巧
晋江读书网页版在线登录 晋江读书电脑版官网
Pandas DataFrame 多条件优先级排序与排名
QQ邮箱官方登录入口_QQ邮箱网页版快捷使用平台
Win11怎么关闭快速启动_Win11彻底关机设置教程
汽水音乐在线版入口_汽水音乐网页播放手册
Mac终端命令大全_Mac常用Terminal指令速查
反效果?《战地6》免费试玩开启后玩家数不升反降
KFC套餐升级怎么获取优惠代码_KFC套餐升级活动与优惠代码获取方法
MAC如何将整个网页截长图_MAC使用Safari的导出为PDF或第三方工具
AngularJS $http POST请求数据传递与Go后端接收实践
Python中高效访问嵌套字典与列表中的键值对
网易大神怎么保存别人动态的图片_网易大神动态图片保存方法
地铁跑酷免费秒玩入口链接 地铁跑酷小游戏免费秒玩网站
Yandex浏览器官方网页版入口 Yandex浏览器最新版官网
Win11怎么查看电脑配置_Win11硬件配置检测工具使用
fishbowl官网免费版 fishbowl养鱼网站入口
poki网页游戏推荐_poki免费游戏平台入口
Django模型中自动计算可用余额的实现方法
Golang如何优化CPU绑定任务分配策略_Golang CPU任务分配优化实践
漫蛙2(台版)官方入口地址 漫蛙2(台版)正版漫画网页端
J*aScript 字符串标签转换:使用正则表达式高效替换
J*aScript map 迭代中检测空数组元素的有效方法


2025-11-08
浏览次数:次
返回列表
ot;: 0,
"query": {
"operands": [
{"operands": ["startdatetime", start_date_str], "operator": "gte"},
{"operands": ["startdatetime", end_date_str], "operator": "lt"},
{"operands": ["region", "us"], "operator": "eq"},
],
"operator": "and",
},
"size": 100, # 可根据需要调整每页返回数量
"sortField": "companyshortname",
"sortType": "ASC",
}
# A3 cookie也可能失效,需要动态获取
cookie = "d=AQABBK8KXmQCEA8-VE0dBLqG5QEpQ7OglmEFEgABCAHCeWWpZfNtb2UB9qMAAAcIqgpeZJj7vK8&S=AQAAAqhyTAOrxcxONc4ktfzCOkg"
earnings_data = []
with requests.Session() as s:
s.headers.update(headers)
s.cookies["A3"] = cookie # 设置A3 cookie
try:
response = s.post(url, params=params, json=query)
response.raise_for_status() # 检查HTTP错误
data = response.json()
if data and "finance" in data and "result" in data["finance"] and \
data["finance"]["result"] and data["finance"]["result"][0]["documents"]:
for doc in data["finance"]["result"][0]["documents"]:
if "rows" in doc:
for r in doc["rows"]:
# 提取并格式化数据
company_name = r[1] if len(r) > 1 else ""
event_name = r[2] if len(r) > 2 and r[2] else ""
start_datetime = r[3] if len(r) > 3 else ""
earnings_data.append({
"company_name": company_name,
"event_name": event_name,
"start_datetime": start_datetime
})
else:
print(f"API响应中未找到预期数据结构: {data}")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
except ValueError as e:
print(f"JSON解析错误: {e}")
return earnings_data
if __name__ == "__main__":
# 获取昨天的日期 (假设今天是周日,昨天是周六,我们需要周五的收益)
# 实际应用中,可以直接指定日期
today = date.today()
# 调整为上一个工作日,例如,如果今天是周日,则获取上周五的日期
target_date = today - timedelta(days=2) # 示例:如果今天是周日,这将是周五
print(f"尝试获取 {target_date.strftime('%Y-%m-%d')} 的收益数据...")
earnings = get_yahoo_earnings(target_date)
if earnings:
print(f"\n{target_date.strftime('%Y-%m-%d')} 收益数据:")
for item in earnings:
print(f"{item['company_name']:<40} {item['event_name']:<40} {item['start_datetime']:<30}")
else:
print(f"未能获取 {target_date.strftime('%Y-%m-%d')} 的收益数据。")
# 示例:获取特定日期的收益
specific_date = date(2025, 12, 15)
print(f"\n尝试获取 {specific_date.strftime('%Y-%m-%d')} 的收益数据...")
earnings_specific = get_yahoo_earnings(specific_date)
if earnings_specific:
print(f"\n{specific_date.strftime('%Y-%m-%d')} 收益数据:")
for item in earnings_specific:
print(f"{item['company_name']:<40} {item['event_name']:<40} {item['start_datetime']:<30}")
else:
print(f"未能获取 {specific_date.strftime('%Y-%m-%d')} 的收益数据。")