使用Beautiful Soup爬取Mecca护肤页面遇AttributeError及数据获取问题
问题与解决方案
问题概述
爬取Mecca护肤页面的产品品牌、名称及成分列表,已成功获取产品链接,但提取具体信息时要么无结果返回,要么触发AttributeError: 'NoneType' object has no attribute 'text'错误。
核心原因
- 动态CSS类名:页面中使用的
css-738lkl、css-pdiqc3这类类名是动态生成的,会随页面更新变化,无法稳定定位元素。 - 请求头缺失:直接用
requests发送请求会被网站识别为爬虫,返回不完整的静态HTML,无法获取实际渲染的内容。 - 动态内容加载:部分产品信息可能通过JavaScript异步加载,静态请求无法获取。
解决方案
1. 补充请求头模拟浏览器访问
添加User-Agent等请求头,避免被反爬机制拦截:
import requests from bs4 import BeautifulSoup # 模拟浏览器请求头 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' } # 修正产品链接拼接逻辑(原代码会出现重复域名) base_url = "https://www.mecca.com" productlinks = [] for x in range(1,5): soup = BeautifulSoup(requests.get(f'{base_url}/en-au/skincare/?page={x}', headers=headers).content, "html.parser") products = soup.find_all('div', class_="css-1r7iqog") for item in products: link = item.find('a', href=True) if link: productlinks.append(base_url + link['href'])
2. 使用语义化属性定位元素
放弃依赖动态CSS类,改用网站提供的data-testid属性定位,这类属性更稳定:
product_data = [] for link in productlinks: response = requests.get(link, headers=headers) soup = BeautifulSoup(response.content, "html.parser") # 提取品牌和名称 title_area = soup.find('div', {'data-testid': 'product-title'}) brand = title_area.find('span', {'data-testid': 'product-brand'}).text.strip() if title_area else '未获取到品牌' name = title_area.find('span', {'data-testid': 'product-name'}).text.strip() if title_area else '未获取到名称' # 提取成分 ingredients = '未获取到成分' ingredient_area = soup.find('div', {'data-testid': 'ingredients'}) if ingredient_area: ingredient_text = ingredient_area.find('p') if ingredient_text: ingredients = ingredient_text.text.strip() product_data.append({ '品牌': brand, '产品名称': name, '成分': ingredients }) # 打印结果 for item in product_data: print(f"品牌: {item['品牌']}\n名称: {item['产品名称']}\n成分: {item['成分']}\n---")
3. 处理动态加载内容(备选方案)
如果上述方法仍无法获取内容,使用Selenium模拟浏览器渲染页面:
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 import time driver = webdriver.Chrome() product_data = [] for link in productlinks: driver.get(link) time.sleep(1) # 给页面加载留缓冲时间 try: # 等待成分区域加载完成 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, '[data-testid="ingredients"] p')) ) brand = driver.find_element(By.CSS_SELECTOR, '[data-testid="product-brand"]').text.strip() name = driver.find_element(By.CSS_SELECTOR, '[data-testid="product-name"]').text.strip() ingredients = driver.find_element(By.CSS_SELECTOR, '[data-testid="ingredients"] p').text.strip() product_data.append({ '品牌': brand, '产品名称': name, '成分': ingredients }) except Exception as e: print(f"处理链接 {link} 时出错: {str(e)}") continue driver.quit() # 打印结果 for item in product_data: print(f"品牌: {item['品牌']}\n名称: {item['产品名称']}\n成分: {item['成分']}\n---")
注意事项
- 添加请求间隔:在循环中加入
time.sleep(1),避免短时间内发送大量请求触发反爬。 - 定期检查定位器:网站可能更新页面结构,若后续出错需重新确认
data-testid属性或元素层级。
内容的提问来源于stack exchange,提问作者user22276310
相关产品推荐
相关产品推荐

