使用Beautiful Soup爬取丝芙兰香水仅获前12条数据问题求助
解决丝芙兰香水页面爬取仅获取前12条数据的问题
嘿,我碰到过一模一样的问题!丝芙兰这个香水列表页用了懒加载机制——页面初始只会渲染前12条商品,剩下的48条得等用户滚动到对应位置时,才会通过JavaScript动态加载出来。你用requests.get()拿到的只是页面的静态初始源码,后面的商品元素要么是占位结构,要么内容还没填充,所以就算perfume_containers长度显示60,也提取不到后面的品牌信息。
给你两个靠谱的解决方案:
方案一:用Selenium模拟浏览器动态加载页面
Selenium可以模拟真实浏览器的行为,帮你滚动页面加载所有商品,再获取完整的页面源码。
步骤:
- 先安装Selenium和对应浏览器的驱动(比如ChromeDriver,要和你的Chrome版本匹配):
pip install selenium - 运行下面的代码:
from selenium import webdriver from bs4 import BeautifulSoup import pandas as pd # 初始化Chrome浏览器(记得把ChromeDriver路径配置好,或者放在环境变量里) driver = webdriver.Chrome() driver.get('https://www.sephora.com/shop/perfume') # 模拟滚动到底部,触发所有商品加载 last_scroll_height = driver.execute_script("return document.body.scrollHeight") while True: # 滚动到当前页面底部 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 等待3秒让商品加载(可以根据网络情况调整) driver.implicitly_wait(3) # 计算新的页面高度,判断是否加载完所有内容 new_scroll_height = driver.execute_script("return document.body.scrollHeight") if new_scroll_height == last_scroll_height: break last_scroll_height = new_scroll_height # 获取加载完成后的完整页面源码 soup = BeautifulSoup(driver.page_source, 'html.parser') driver.quit() # 关闭浏览器 # 提取所有商品容器 perfume_containers = soup.find_all('div', class_="css-12egk0t") brands = [] names = [] prices = [] for container in perfume_containers: # 处理品牌提取,兼容可能的不同class(如果还有其他结构,自己补充对应的class) brand = container.find('span', class_='css-ktoumz') or container.find('span', class_='css-另一个可能的class') if brand: brands.append(brand.text.strip()) else: brands.append(None) # 同理提取商品名称和价格,根据实际页面结构调整class name = container.find('span', class_='css-1pgnl76') names.append(name.text.strip() if name else None) price = container.find('span', class_='css-1b8x74j') prices.append(price.text.strip() if price else None) # 整理成DataFrame perfume_df = pd.DataFrame({ '品牌': brands, '香水名称': names, '价格': prices }) print(perfume_df)
方案二:直接调用API接口(更高效)
其实丝芙兰的商品数据是通过API接口返回的,你可以在浏览器开发者工具里找到这个接口,直接请求获取JSON格式的完整数据,不用处理页面结构的问题。
步骤:
- 打开浏览器F12,切换到「Network」标签,滚动页面,找到类似
catalog/products的XHR请求,复制它的URL和参数。 - 用
requests直接请求这个接口:
import requests import pandas as pd # 替换成你找到的API接口URL和参数 api_url = 'https://www.sephora.com/api/catalog/products' params = { 'categoryId': 'cat170006', # 香水分类的ID,从请求里复制 'currentPage': 1, 'pageSize': 60, 'sortBy': 'POPULARITY' } # 加上请求头模拟浏览器,避免被拦截 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } response = requests.get(api_url, params=params, headers=headers) product_data = response.json() brands = [] names = [] prices = [] # 从JSON数据里提取需要的字段 for product in product_data['products']: brands.append(product['brandName']) names.append(product['displayName']) prices.append(product['currentSku']['listPrice']) perfume_df = pd.DataFrame({ '品牌': brands, '香水名称': names, '价格': prices }) print(perfume_df)
这个方案比爬页面更稳定,因为API返回的数据结构很规整,不会因为页面UI更新而失效(只要接口不变)。
内容的提问来源于stack exchange,提问作者DJ-coding




