使用requests+bs4/json爬取Bovada MLB数据遇内容不一致问题
解决Bovada MLB赛事数据爬取的问题
我来帮你拆解一下你遇到的问题,然后一步步解决它:
为什么requests返回的HTML和浏览器显示不一致?
这是因为Bovada这类网站用了JavaScript动态渲染内容。当你用requests.get()请求页面时,它只会获取服务器返回的静态HTML,不会执行页面里的JavaScript代码——而浏览器会自动执行JS,动态加载赛事数据、赔率这些内容,所以你在浏览器开发者工具里看到的完整内容,requests根本拿不到。
另外,你尝试用view-source:https://...作为请求URL是完全错误的,view-source:是浏览器的内置功能协议,不是一个可通过HTTP请求的地址,requests自然无法获取到数据。
正确的爬取步骤
1. 找到数据的实际来源
你提到页面底部有iframe和包含目标数据的JSON,那我们先从iframe入手:首先请求主页面,找到iframe的真实URL,然后直接请求这个iframe页面,因为里面才是承载数据的地方。
2. 代码实现(分步解析)
第一步:请求主页面,提取iframe链接
import requests from bs4 import BeautifulSoup import json # 模拟浏览器的请求头,避免被网站识别为爬虫 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' } main_url = 'https://sports.bovada.lv/baseball/mlb/game-lines-market-group' response = requests.get(main_url, headers=headers) soup = BeautifulSoup(response.text, 'lxml') # 找到页面中的iframe(你可以根据实际页面的iframe属性调整,比如id、class) iframe = soup.find('iframe') if not iframe: print("没找到包含数据的iframe,可能网站结构变了") else: # 拼接完整的iframe URL(如果src是相对路径的话) iframe_src = iframe['src'] if not iframe_src.startswith('http'): iframe_src = 'https://sports.bovada.lv' + iframe_src
第二步:请求iframe页面,提取JSON数据
请求iframe页面后,数据通常会藏在某个<script>标签里的JSON结构中,我们需要定位并提取:
# 请求iframe页面 iframe_response = requests.get(iframe_src, headers=headers) iframe_soup = BeautifulSoup(iframe_response.text, 'lxml') # 遍历所有script标签,寻找包含目标数据的内容 for script in iframe_soup.find_all('script'): script_content = script.text.strip() # 用你提到的'itemList'作为关键词定位 if 'itemList' in script_content: # 清理JSON字符串(去掉前面的变量赋值和后面的多余符号) json_start = script_content.find('{') json_end = script_content.rfind('}') + 1 json_str = script_content[json_start:json_end] # 解析JSON try: data = json.loads(json_str) item_list = data.get('itemList', []) # 提取你需要的字段(这里的键名需要根据实际JSON结构调整) for game in item_list: # 球队信息 team_home = game.get('homeTeam', {}).get('name') team_away = game.get('awayTeam', {}).get('name') # 投手信息 pitcher_home = game.get('homePitcher', {}).get('name') pitcher_away = game.get('awayPitcher', {}).get('name') # 赔率 odds_home = game.get('homeOdds') odds_away = game.get('awayOdds') # 总得分 total_score = game.get('total', {}).get('overUnder') # 打印结果(或者保存到文件/数据库) print(f"赛事:{team_away} vs {team_home}") print(f"投手:{pitcher_away} | {pitcher_home}") print(f"赔率:客队 {odds_away} | 主队 {odds_home}") print(f"总得分:{total_score}\n") except json.JSONDecodeError as e: print(f"解析JSON出错:{e}") break
3. 备选方案:直接找API接口
如果iframe的方法不好用,你可以用浏览器的开发者工具(F12打开),切换到Network标签,刷新页面后,筛选XHR或Fetch请求,找包含mlb、game-lines这类关键词的请求——这些就是网站直接获取数据的API接口。
找到API URL后,直接用requests.get()请求这个URL(带上同样的headers),就能直接拿到结构化的JSON数据,比解析HTML更高效。
注意事项
- 反爬机制:博彩网站通常有反爬措施,不要频繁请求,建议加
time.sleep()控制间隔;如果遇到403/503错误,可能需要添加Cookie到headers里(从浏览器复制当前会话的Cookie)。 - 网站结构变化:这类网站的页面结构和API可能会随时更新,代码需要根据实际情况调整字段名或定位逻辑。
内容的提问来源于stack exchange,提问作者Michael T Johnson
相关产品推荐
相关产品推荐

