/ 内;主图链接常为
的 src 或 。因此,我们应构建一个选择器策略库,而非固定路径:# selector_strategy.py:按网站域名定义轻量级解析规则
SELECTOR_MAP = {
"amazon.com": {
"title": ["h1#productTitle", "[data-hook='product-title']"],
"price": ["#priceblock_ourprice", ".a-price-whole", "meta[property='product:price:amount']"],
"image": ["#landingImage", "#imgTagWrapperId img"],
"url": lambda soup: soup.find("link", {"rel": "canonical"})["href"] if soup.find("link", {"rel": "canonical"}) else None
},
"taobao.com": {
"title": ["h1.title", ".tb-main-title"],
"price": [".price", ".tm-price", "em[data-price]"],
"image": ["#J_ImgBooth img", ".tb-gallery .thumb li img"],
"url": lambda soup: soup.find("meta", {"name": "mobile-agent"})["content"].split("url=")[-1] if soup.find("meta", {"name": "mobile-agent"}) else None
}
}二、动态选择器执行引擎
不依赖单一选择器,而是按优先级顺序尝试多个候选选择器,首个返回非空结果者胜出。配合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
from bs4 import BeautifulSoup
def extract_field(driver, selectors, field_name):
"""尝试多个CSS选择器,返回首个有效文本/属性值"""
for selector in selectors:
try:
# 若为函数,则直接调用(如URL的特殊逻辑)
if callable(selector):
soup = BeautifulSoup(driver.page_source, 'html.parser')
result = selector(soup)
if result:
return result
# 否则用Selenium查找元素
element = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.CSS_SELECTOR, selector))
)
if field_name == "url":
return element.get_attribute("href") or element.get_attribute("src")
elif field_name == "image":
return element.get_attribute("src") or element.get_attribute("data-src")
else:
return element.text.strip() or element.get_attribute("textContent").strip()
except:
continue
return None # 所有选择器均失败
def scrape_product(url):
driver = webdriver.Chrome() # 生产环境建议复用driver或使用无头模式
try:
driver.get(url)
domain = urlparse(url).netloc.lower()
# 自动匹配策略
strategy = SELECTOR_MAP.get(domain) or SELECTOR_MAP.get("default", {})
result = {
"url": url,
"title": extract_field(driver, strategy.get("title", []), "title"),
"price": extract_field(driver, strategy.get("price", []), "price"),
"image_url": extract_field(driver, strategy.get("image", []), "image")
}
return result
finally:
driver.quit()三、关键注意事项与最佳实践
- ✅ 合规先行:每次请求前检查 https://example.com/robots.txt,遵守 Crawl-Delay 和 User-agent 规则;对 Disallow 路径主动跳过。
- ✅ 反爬韧性:添加随机延时(time.sleep(random.uniform(1,3)))、轮换User-Agent、启用无头模式及代理IP池(如需高频采集)。
- ✅ 容错设计:所有字段提取必须有默认值(如 None 或 "N/A"),避免因单个字段缺失导致整条数据丢弃。
- ✅ 模板识别增强:对未知域名,可先用轻量级规则(如检测 或 script[type="application/ld+json"] 中的JSON-LD结构)自动推断网站类型,再 fallback 到通用XPath模糊匹配(如 //h1|//h2[contains(@class,'title')]|//*[@itemprop='name'])。
- ❌ 切勿暴力试探:避免对同一域名发起高并发请求;不模拟登录态绕过风控;不抓取用户隐私或受版权保护的内容。
该方案将“适配新网站”的成本从数小时降至数分钟:仅需分析目标站源码,补充3–5个高置信度CSS选择器到 SELECTOR_MAP 即可。它不是万能黑盒,而是以结构化思维将爬虫从“脚本”升维为“可配置服务”,真正支撑起产品级的电商数据聚合需求。