如何使用Python的BeautifulSoup爬取带加载更多按钮的单页站点全部数据
爬取Carmax全量车辆列表解决方案
你当前的代码只能获取到页面初始加载的第一页数据,原因是该站点的车辆列表为动态加载内容:首次打开页面仅渲染前20条左右数据,后续数据需要点击「加载更多」按钮触发JS请求后端接口才能加载,静态requests请求无法直接拿到后续内容。
下面给出两种可行实现方案:
方案1:Selenium模拟人工点击加载(上手简单)
该方案通过浏览器自动化工具模拟用户点击操作,直到没有更多数据可加载后再统一解析内容,不需要分析站点接口逻辑。
依赖安装
执行以下命令安装所需工具:pip install selenium webdriver-manager
示例代码
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import time # 初始化Chrome浏览器 driver = webdriver.Chrome(ChromeDriverManager().install()) driver.get("https://www.carmax.com/cars/all") # 等待页面初始加载完成 time.sleep(3) # 循环点击加载更多按钮,直到按钮消失 while True: try: # 找到加载更多按钮 load_more_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'See More Matches')]")) ) # 滚动到按钮位置再点击,避免被遮挡 driver.execute_script("arguments[0].scrollIntoView();", load_more_btn) load_more_btn.click() # 等待新内容加载完成 time.sleep(2) except: # 没有找到加载更多按钮,说明已经加载完全部内容 break # 解析全量页面内容 soup = BeautifulSoup(driver.page_source, 'html.parser') tiles = soup.find_all('div', class_='car-tile') n = 0 for tile in tiles: yearmake = tile.find('span', class_='year-make').text.strip() modeltrim = tile.find('span', class_='model-trim').text.strip() print('TILE ' + str(n) + ': ym=' + yearmake + ', mt=' + modeltrim) n = n + 1 driver.quit()
方案2:直接调用数据接口(性能更高)
如果不想启动浏览器,可以直接抓包拿到站点的车辆数据接口,循环请求接口拿到全量数据,请求速度更快也更稳定。
你可以通过浏览器F12控制台的「网络」面板筛选XHR请求,找到返回车辆列表数据的POST接口,自定义请求参数中的页码、每页数量,循环请求直到返回结果为空即可。
示例代码框架
import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36', 'Content-Type': 'application/json' } url = "你抓包拿到的车辆数据接口地址" page = 1 all_cars = [] while True: # 请求参数根据抓包结果调整 payload = { "page": page, "perPage": 24, "sort": "year:desc" # 其他必填参数按照抓包内容补充 } resp = requests.post(url, json=payload, headers=headers) data = resp.json() # 判断是否还有数据 if not data.get('cars'): break all_cars.extend(data['cars']) page += 1 # 后续处理车辆数据即可 for n, car in enumerate(all_cars): print(f'TILE {n}: ym={car["yearMake"]}, mt={car["modelTrim"]}')
内容的提问来源于stack exchange,提问作者Bradley
相关产品推荐
相关产品推荐

