BeautifulSoup结合Selenium爬取Kayak时find_all返回0的问题
问题原因
- Kayak自带反爬风控,旧版Chrome无头模式的浏览器特征非常明显,会被直接识别为爬虫请求,返回的页面不包含航班动态渲染内容,自然找不到目标span元素,和BeautifulSoup的查找逻辑无关。
- 你使用的
implicitly_wait仅会等待页面初始DOM加载完成,不会等待航班列表的异步接口请求、前端渲染流程结束,就算绕过反爬,抓取时机不对也拿不到目标内容。 - 你拼接的目标URL末尾多了一个多余空格,可能触发异常请求逻辑。
可直接运行的修复代码
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from bs4 import BeautifulSoup from webdriver_manager.chrome import ChromeDriverManager import time # 基础参数配置 origin = "PIT" destination = "ARN" startdate = "2022-12-18" # 去掉URL末尾多余空格 url = f"https://www.kayak.com/flights/{origin}-{destination}/{startdate}?sort=price_a" # 配置Chrome选项,绕过基础反爬检测 chrome_options = Options() # 用新版无头模式,浏览器特征和正常用户端一致 chrome_options.add_argument("--headless=new") chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_argument("user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option("useAutomationExtension", False) # 启动驱动 driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options) # 移除webdriver暴露的自动化标识 driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") driver.get(url) # 显式等待:直到航班出发时间元素渲染完成,最长等待40秒 WebDriverWait(driver, 40).until( EC.presence_of_element_located((By.CSS_SELECTOR, "span.depart-time.base-time")) ) # 模拟用户滚动,触发所有航班项的懒加载 for scroll_pos in range(0, 2000, 500): driver.execute_script(f"window.scrollTo(0, {scroll_pos})") time.sleep(0.8) # 此时再解析页面即可拿到目标元素 soup = BeautifulSoup(driver.page_source, "lxml") deptimes = soup.find_all("span", attrs={'class': 'depart-time base-time'}) arrtimes = soup.find_all('span', attrs={'class': 'arrival-time base-time'}) meridies = soup.find_all('span', attrs={'class': 'time-meridiem meridiem'}) print(f"抓到出发时间数量:{len(deptimes)}") driver.quit()
排查提示
- 如果运行后返回的元素长度还是0,先打印
driver.page_source搜索关键字depart-time,如果搜不到说明还是被风控拦截,可以尝试更换真实浏览器的user-agent、增加访问间隔、搭配代理使用。 - 不要在页面刚加载完成就立刻取源码,Kayak的航班数据是分批异步加载的,必须等目标节点出现后再解析。
内容的提问来源于stack exchange,提问作者kzzz
相关产品推荐
相关产品推荐

