使用BeautifulSoup爬取Yahoo Finance股票时Offset失效问题排查
问题描述
我想获取Yahoo Finance「被低估的成长型股票」页面表格里的所有股票列表,程序里尝试打印所有表格行的<a>标签,但每次只能输出前25条。我试着用while循环每次递增offset参数来获取后续25条数据,虽然offset确实在递增,但输出始终都是前25条表格行的<a>标签。
原代码
from bs4 import BeautifulSoup import requests import re offset = 0 TableUrl = f"https://finance.yahoo.com/screener/predefined/undervalued_growth_stocks/?count=100&offset={offset}" TablePage = requests.get(TableUrl).text TableDoc = BeautifulSoup(TablePage, "html.parser") # 统计股票总数 numOfStocksParent = TableDoc.find(class_="Mstart(15px) Fw(500) Fz(s)") numOfStocks = int(numOfStocksParent.string.split("of ")[-1].split(" results")[0]) while offset < numOfStocks: LoopTableUrl = f"https://finance.yahoo.com/screener/predefined/undervalued_growth_stocks/?count=100&offset={offset}" LoopTablePage = requests.get(LoopTableUrl).text LoopTableDoc = BeautifulSoup(LoopTablePage, "html.parser") LoopTable = LoopTableDoc.find("table") LoopTableRows = LoopTable.find_all("tr") for row in LoopTableRows: print(row.find("a")) offset += 25
问题原因及解决办法
核心问题
Yahoo Finance的筛选页面依赖会话Cookie验证请求合法性,每次用requests.get()发起全新请求时,没有携带首次访问生成的Cookie,服务器会直接忽略offset参数,始终返回第一页数据。
修复方案
- 使用
requests.Session()维持会话,自动保存和复用Cookie; - 让
count参数和递增步长保持一致(比如每次取25条就设count=25),避免数据重复或遗漏; - 跳过表格表头行,避免输出空的
<a>标签。
修复后的代码
from bs4 import BeautifulSoup import requests import re # 初始化会话,自动维持Cookie session = requests.Session() offset = 0 # 首次请求获取股票总数,会话自动保存Cookie TableUrl = f"https://finance.yahoo.com/screener/predefined/undervalued_growth_stocks/?count=25&offset={offset}" TablePage = session.get(TableUrl).text TableDoc = BeautifulSoup(TablePage, "html.parser") # 提取股票总数 numOfStocksParent = TableDoc.find(class_="Mstart(15px) Fw(500) Fz(s)") numOfStocks = int(numOfStocksParent.string.split("of ")[-1].split(" results")[0]) while offset < numOfStocks: LoopTableUrl = f"https://finance.yahoo.com/screener/predefined/undervalued_growth_stocks/?count=25&offset={offset}" LoopTablePage = session.get(LoopTableUrl).text LoopTableDoc = BeautifulSoup(LoopTablePage, "html.parser") LoopTable = LoopTableDoc.find("table") LoopTableRows = LoopTable.find_all("tr") # 跳过表头行,只遍历数据行 for row in LoopTableRows[1:]: stock_link = row.find("a") if stock_link: # 打印股票代码和链接,替代原有的标签对象输出 print(f"{stock_link.text}: {stock_link['href']}") offset += 25
补充说明
- 会话
session会自动保存首次请求的Cookie,后续请求携带该Cookie后,服务器就能正确识别offset参数,返回对应分页的数据; - 调整
count与步长一致,确保每次请求刚好获取一页数据,避免重复抓取; - 跳过表头并判断链接是否存在,能避免输出空值,同时让输出内容更直观有用。
内容的提问来源于stack exchange,提问作者tdocog
相关产品推荐
相关产品推荐

