如何用Selenium从动态URL批量采集商品公斤价与描述
iFood商品详情页公斤价与描述采集方案
需要采集iFood某店铺商品的**公斤价(Preço do quilo)**和完整描述,但店铺主页面仅显示500克这类小份量价格,必须进入商品详情页(通过主页面URL拼接&item=商品ID生成)才能获取目标数据。现有Selenium代码仅能抓取主页面信息,无法进入详情页采集,以下是修改方案:
核心修改思路
- 提取商品ID:从主页面商品卡片的属性或链接中提取商品ID,用于构造详情页URL
- 构造详情页链接:通过主页面URL拼接
&item=商品ID直接访问详情页,比点击跳转更高效 - 定位目标元素:在详情页中定位显示公斤价和完整描述的元素
- 替换强制等待:用Selenium显式等待替代
time.sleep,提升代码稳定性 - 异常容错处理:增加多层异常捕获,避免单个商品或页面出错导致程序中断
修改后的完整代码
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 selenium.common.exceptions import TimeoutException, WebDriverException import json # 目标店铺链接列表 lista = [ "https://www.ifood.com.br/delivery/brasilia-df/oba-hortifruti---212-sul-asa-sul/8b66f111-5766-409e-97aa-6034868aa230?corredor=4e10f079-d107-437b-b278-e71a964b444b&originArea=aisleMenu" ] driver = webdriver.Chrome() # 根据你的浏览器类型选择对应Driver wait = WebDriverWait(driver, 10) # 显式等待超时时间设置为10秒 for shop_url in lista: try: # 访问店铺主页面 driver.get(shop_url) # 滚动加载所有商品 scrolls = 5 while scrolls > 0: driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") # 等待页面滚动加载完成 wait.until(lambda d: d.execute_script("return document.body.scrollHeight") > driver.execute_script("return window.pageYOffset + window.innerHeight")) scrolls -= 1 # 最后一次滚动到底部确保所有商品加载 driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") wait.sleep(1) # 获取所有商品卡片元素 items = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'product-card-content'))) for item in items: # 提取商品ID,优先从data-item-id属性获取 item_id = None try: item_id = item.get_attribute("data-item-id") if not item_id: # 属性不存在则从商品链接中解析 item_link = item.find_element(By.TAG_NAME, "a").get_attribute("href") item_id = item_link.split("&item=")[-1] except: print("无法提取商品ID,跳过该商品") continue # 构造详情页URL detail_url = f"{shop_url}&item={item_id}" try: # 访问商品详情页 driver.get(detail_url) # 等待详情页核心元素加载完成 wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'product-detail__description'))) # 获取商品完整描述 descricao = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'product-detail__description'))).text # 获取公斤价,兼容多种可能的元素定位 preco_quilo = "" try: # 优先通过文本定位公斤价元素 price_unit = wait.until(EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'Preço do quilo')]/following-sibling::span"))) preco_quilo = price_unit.text except: try: # 备用定位方式:通过class定位 preco_quilo = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'product-price__unit'))).text except: preco_quilo = "未找到公斤价" # 整理并输出数据 item_data = { 'descricao': descricao, 'preco_quilo': preco_quilo, 'item_id': item_id } print(json.dumps(item_data, ensure_ascii=False)) # 返回店铺主页面,继续处理下一个商品 driver.back() # 等待主页面商品列表重新加载完成 wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'product-card-content'))) except (TimeoutException, WebDriverException) as e: print(f"处理商品ID {item_id} 时出错: {str(e)}") driver.back() continue except (TimeoutException, WebDriverException) as e: print(f"访问店铺链接 {shop_url} 时出错: {str(e)}") except Exception as e: print(f"处理店铺 {shop_url} 时发生未知错误: {str(e)}") driver.quit()
代码说明
- 采用
WebDriverWait显式等待,确保元素加载完成后再操作,避免因页面加载慢导致的元素找不到问题 - 兼容两种商品ID提取方式,提升适配性
- 针对公斤价设计了双重定位逻辑,适配不同页面结构
- 每次处理完商品后返回主页面,保证遍历流程不中断
- 多层异常捕获,单个商品或页面出错不会导致整个程序终止
内容的提问来源于stack exchange,提问作者João Felix
相关产品推荐
相关产品推荐

