使用BeautifulSoup爬取Oddsportal西甲赔率时遇选择器语法错误求助
解决Oddsportal西甲赔率抓取的错误问题
嘿,我来帮你搞定这个抓取赔率时遇到的错误!
先说说你遇到的核心问题
你看到的soupsieve.util.SelectorSyntaxError是因为你的CSS选择器里混进了不可见的控制字符(\x1b,也就是ESC转义字符),导致选择器解析器直接罢工了。从错误提示的标记位置能看出来,这个隐藏字符藏在选择器里,让#tournamentTable td[xodd]变成了非法语法。
另外还有个隐性坑:Oddsportal的赔率数据大多是JavaScript动态加载的,就算你修复了选择器,用requests只能拿到静态HTML,大概率还是拿不到你想要的10行3列赔率数据。
一步步修复方案
1. 先把选择器的脏字符清掉
先重新写个干净的选择器,避免隐藏字符的干扰,你可以用两种方式来筛选带xodd属性的td:
第一种,修复后的CSS选择器写法:
import requests from bs4 import BeautifulSoup as bs url = 'https://www.oddsportal.com/soccer/spain/laliga' r = requests.get(url, 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'}) soup = bs(r.content, 'lxml') # 用干净的选择器筛选,同时清理文本空格 odds = [b.text.strip() for b in soup.select('#tournamentTable td[xodd]')] print(odds)
第二种,用find_all加属性筛选,比CSS选择器更不容易出语法问题:
table = soup.find('table', id='tournamentTable') if table: odds = [td.text.strip() for td in table.find_all('td', attrs={'xodd': True})] print(odds) else: print("没找到目标赛事表格哦")
2. 解决动态加载的核心问题
上面的代码能解决语法错误,但大概率拿不到完整赔率,因为静态HTML里没有这些动态渲染的数据。这时候得用selenium模拟浏览器加载页面,才能拿到渲染后的完整内容:
首先安装selenium:
pip install selenium
然后下载对应你Chrome浏览器版本的ChromeDriver(注意版本要匹配),然后用下面的代码:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from bs4 import BeautifulSoup as bs import time # 配置无头浏览器(不弹出窗口) chrome_options = Options() chrome_options.add_argument('--headless=new') chrome_options.add_argument('--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') # 启动浏览器 driver = webdriver.Chrome(options=chrome_options) url = 'https://www.oddsportal.com/soccer/spain/laliga' driver.get(url) # 给页面一点加载时间,避免数据还没渲染完 time.sleep(3) # 获取完整的渲染后页面源码 soup = bs(driver.page_source, 'lxml') # 提取并整理成10行3列的格式 table = soup.find('table', id='tournamentTable') if table: odds_cells = table.find_all('td', attrs={'xodd': True}) # 每3个td为一组(胜、平、负赔率) odds_groups = [odds_cells[i:i+3] for i in range(0, len(odds_cells), 3)] # 取前10组数据 for idx, group in enumerate(odds_groups[:10]): print(f"赛事{idx+1}:{' | '.join([cell.text.strip() for cell in group])}") else: print("未找到赛事表格,可能页面结构变了或者被反爬拦截了") # 记得关闭浏览器 driver.quit()
3. 一些避坑提示
- ChromeDriver的版本必须和你的Chrome浏览器版本完全匹配,不然会启动失败。
- Oddsportal有反爬机制,别太频繁请求页面,加个
time.sleep()很有必要。 - 网站的HTML结构可能会不定期更新,如果之后又拿不到数据,记得重新检查页面元素的属性和结构。
内容的提问来源于stack exchange,提问作者Lander
相关产品推荐
相关产品推荐

