使用BeautifulSoup4爬取Veri.bet投注数据返回空列表求助
问题分析与解决方案
为什么返回空列表?
- 静态HTML不含目标数据:你用
requests.get获取的是页面初始静态HTML,而点击"Access Betting Simulator"按钮后的数据是通过JavaScript动态从后端API加载的,静态页面里根本没有betting-line这类元素,所以soup.find_all找不到任何内容。 - 无法模拟按钮点击:
requests库只能发送HTTP请求,不能模拟浏览器的JavaScript交互(比如点击按钮),直接爬取初始页面拿不到动态加载的数据。
解决方法
1. 找到真实的数据源API
打开浏览器开发者工具(F12),切换到「网络」面板,点击页面上的"Access Betting Simulator"按钮,观察XHR/fetch请求,就能发现页面会向某个API地址发送请求获取投注数据(具体地址以实际请求为准)。
2. 直接请求API获取数据
不需要解析HTML,直接请求这个API接口就能拿到结构化的JSON数据,再把数据映射到你的Item类中。
修改后的代码示例
import requests import dataclasses import json @dataclasses.dataclass class Item: sport_league: str = '' # 运动类型,如棒球、篮球、足球 event_date_utc: str = '' # 赛事UTC时间,ISO格式 team1: str = '' # 主队名称 team2: str = '' # 客队名称 pitcher: str = '' # 棒球投手(可选) period: str = '' # 赛事阶段,如全场、上半场、第一节等 line_type: str = '' # 投注类型,如moneyline、让分、大小分 price: str = '' # 投注赔率,如'-133'或'+105' side: str = '' # 大小分方向,如'over'(大)、'under'(小) team: str = '' # 对应队伍,大小分投注时为'total' spread: float = 0.0 # 让分/大小分值,如-1.5、+2.5 def parse_api_data(api_data): betting_lines = [] # 需根据API实际返回的字段结构调整映射关系 for data in api_data: item = Item() item.sport_league = data.get('sportLeague', '') item.event_date_utc = data.get('eventDateUtc', '') item.team1 = data.get('team1', '') item.team2 = data.get('team2', '') item.pitcher = data.get('pitcher', '') item.period = data.get('period', '') item.line_type = data.get('lineType', '') item.price = data.get('price', '') item.side = data.get('side', '') item.team = data.get('team', '') if item.line_type in ['spread', 'over/under']: item.spread = float(data.get('spread', 0.0)) betting_lines.append(item) return betting_lines def main(): # 替换为你找到的真实API地址 api_url = "https://veri.bet/api/simulator/data" # 模拟浏览器请求头,避免被拦截 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" } response = requests.get(api_url, headers=headers) if response.status_code == 200: api_data = response.json() betting_lines = parse_api_data(api_data) # 将dataclass对象转为字典后再序列化 print(json.dumps([dataclasses.asdict(item) for item in betting_lines], indent=2, ensure_ascii=False)) else: print(f"请求API失败,状态码:{response.status_code}") if __name__ == '__main__': main()
注意事项
- 字段映射调整:实际API返回的字段名可能和你定义的
Item类属性不一致,需要对照开发者工具里的响应数据修改parse_api_data中的字段映射。 - 请求头模拟:部分网站会校验请求头,添加
User-Agent等字段可以降低被拦截的概率。 - 反爬限制:频繁请求可能触发网站反爬机制,必要时可添加请求延迟或使用代理。
内容的提问来源于stack exchange,提问作者Thales Souza
相关产品推荐
相关产品推荐

