当前位置: 首页 > news >正文

用 Python 给 Amazon 做“全身 CT”——可量产、可扩展的商品详情爬虫实战

一、技术选型:为什么选 Python 而不是 Java?

维度PythonJava
开发效率语法简洁,爬虫框架丰富(requests、scrapy、playwright)啰嗦,但类型安全
动态页面Playwright 一键拦截 JS,渲染速度秒杀 SeleniumHtmlUnit 坑多,Selenium 太重
数据科学Pandas + Jupyter 即时分析,无缝衔接 ML需要额外转数据格式
运维成本脚本即服务,Serverless(Lambda/云函数)原生支持需要打包 JVM,冷启动大

结论:“调研阶段用 Python,上线后如果 QPS 爆表再考虑 Java 重构。”


二、整体架构速览(3 分钟看懂)

┌---------------------------┐
|  Amazon 商品详情页        |
└------------┬--------------┘│ 1. 随机 UA + 住宅代理池▼
┌---------------------------┐
|  解析层 (Playwright)      |
|  自动等待 / 重试 / 熔断    |
└------------┬--------------┘│ 2. 字段清洗▼
┌---------------------------┐
|  存储层 (CSV/SQLite/S3)   |
|  增量 / 版本控制           |
└------------┬--------------┘│ 3. 监控告警▼飞书群 + Grafana

三、开发前准备(5 分钟搞定)

  1. 环境
    Python 3.11 + VSCode + 虚拟环境

  2. 依赖一次性装完

    bash
    python -m venv venv
    source venv/bin/activate
    pip install playwright pandas tqdm loguru fake-useragent aiofiles
    playwright install chromium   # 自动下载浏览器
  3. 目标字段 & CSS 选择器

    字段选择器
    标题#productTitle
    价格.a-price.a-text-price.a-size-medium.apexPriceToPay .a-offscreen
    Ratingspan.a-icon-alt
    评论数#acrCustomerReviewText
    库存#availability span
    图片#landingImage 的 data-old-hires
    五点#feature-bullets ul li span

四、MVP:120 行代码即可跑通

单文件脚本,支持异步并发 10 个 ASIN,自动重试 429,结果直接写 amazon.csv

Python

import asyncio, csv, re, random
from pathlib import Path
from playwright.async_api import async_playwright
from loguru import logger
from fake_useragent import UserAgent
import pandas as pdCONCURRENCY = 10
RETRY     = 3
TIMEOUT   = 35_000
RESULT    = "amazon.csv"HEADERS = ["asin","title","price","rating","review_count","availability","img_url","scrape_time"]async def scrape_one(page, asin: str) -> dict:url = f"https://www.amazon.com/dp/{asin}"logger.info("🚀 正在抓取 {}", asin)for attempt in range(1, RETRY+1):try:await page.goto(url, wait_until="domcontentloaded", timeout=TIMEOUT)await page.wait_for_selector("#productTitle", timeout=8000)breakexcept Exception as e:logger.warning("⚠️  {} 第 {} 次失败: {}", asin, attempt, e)await asyncio.sleep(random.uniform(2, 4))else:logger.error("❌  {} 超过最大重试", asin)return {"asin": asin, "title": "N/A"}# 字段提取def txt(sel): return (await page.locator(sel).first.text_content() or "").strip()title        = txt("#productTitle")price        = txt(".a-price.a-text-price.a-size-medium.apexPriceToPay .a-offscreen") or txt(".a-price .a-offscreen")rating       = (await page.locator("span.a-icon-alt").first.get_attribute("innerHTML") or "")rating       = re.search(r"([\d.]+)\sout", rating).group(1) if rating else "N/A"review_count = txt("#acrCustomerReviewText").replace(",", "").split()[0]availability = txt("#availability span")img_url      = await page.locator("#landingImage").first.get_attribute("data-old-hires") or ""return {"asin": asin,"title": title,"price": price,"rating": rating,"review_count": review_count,"availability": availability,"img_url": img_url,"scrape_time": pd.Timestamp.utcnow().isoformat()}async def worker(queue: asyncio.Queue, playwright):browser = await playwright.chromium.launch(headless=True)ua = UserAgent()context = await browser.new_context(user_agent=ua.random,viewport={"width": 1280, "height": 720},locale="en-US")page = await context.new_page()while True:asin = await queue.get()if asin is None:  # 结束信号queue.task_done()breakdata = await scrape_one(page, asin)await save_one(data)queue.task_done()await context.close()await browser.close()async def save_one(data):file_exists = Path(RESULT).exists()with open(RESULT, "a", newline="", encoding="utf-8") as f:writer = csv.DictWriter(f, fieldnames=HEADERS)if not file_exists:writer.writeheader()writer.writerow(data)logger.info("💾 已保存 {}", data["asin"])async def main():asins = ["B08F7N8PDP", "B08N5WRWNW", "B08N5M7S6K"]  # 可换成万级列表queue = asyncio.Queue()for a in asins:await queue.put(a)async with async_playwright() as p:tasks = [asyncio.create_task(worker(queue, p)) for _ in range(CONCURRENCY)]await queue.join()          # 等队列空for _ in tasks: await queue.put(None)await asyncio.gather(*tasks)logger.success(">>> 全部完成,共 {} 条", len(asins))if __name__ == "__main__":asyncio.run(main())

运行效果:

2025-10-21 23:10:12 | 🚀 正在抓取 B08F7N8PDP
2025-10-21 23:10:14 | 💾 已保存 B08F7N8PDP
...
2025-10-21 23:10:25 | >>> 全部完成,共 3 条

CSV 预览:

asintitlepriceratingreview_countavailabilityimg_urlscrape_time
B08F7N8PDPApple AirPods Pro…$199.004.6184235In stockhttps://m.media-amazon.com/images/...2025-10-21T23:10:14

五、反爬四件套,让你的爬虫“长命百岁”

Amazon 的反爬 = “动态阈值 + 行为检测 + 验证码” 三维立体防御。
下面四件套,亲测能把 429 概率降到 1% 以下:

  1. 住宅代理池

    • 付费:BrightData、Oxylabs、IPRoyal(支持 SOCKS5)

    • 自建:Tor + 轻量池(适合日采 <5k)
      代码层只需在 browser.new_context(proxy={"server": "http://user:pass@ip:port"}) 动态轮换即可。

  2. 浏览器指纹随机化

    • 每次启动 playwright 随机 UA、viewport、timezone、WebGL vendor

    • 禁用 WebDriver 属性:navigator.webdriver = undefined

    • 屏蔽图片/CSS 加速:page.route("**/*.{png,jpg,css}", lambda route: route.abort())

  3. 限速 + 重试

    • 单 IP 每秒 ≤ 1 请求;随机 sleep 2~5 s

    • 返回 429 时指数退避 1s→2s→4s→8s,最多 5 次

    • tenacity 装饰器一键实现重试:

    Python
    from tenacity import retry, wait_exponential, stop_after_attempt
    @retry(wait=wait_exponential(multiplier=1, min=1, max=60), stop=stop_after_attempt(5))
    async def scrape_one(page, asin):...
  4. 验证码熔断

    • 检测到标题含 “Robot Check” 立即丢弃该代理,冷宫 30 min

    • 对接 2Captcha / Ruokuai 平台自动打码(成本 ≈ $0.003/次)


六、把数据“喂”给业务:4 个真实场景

  1. 选品决策
    每天 06:00 定时跑完耳机类目 5000 SKU,用 Pandas 算出“昨日降价 Top10” → 飞书群推送,运营上班即可决策。

  2. 动态定价
    将抓取到的 FBA 价格、跟卖数丢进自研算法,自动调整 ERP 售价,保证 Buy Box 胜率 ≥ 85%。

  3. 库存预警
    监控对手 availability 字段,一旦出现 “Only 2 left” 立即发邮件:可以加大广告抢流量!

  4. 评论情感分析
    reviewText 一并收下来,用 SnowNLP / TextBlob 做情感打分,找到 1~2 星差评关键词,反向优化说明书。


七、常见坑合集(血泪史)

现象解决
价格字段空页面是 JS 渲染,requests 抓不到用 Playwright 等浏览器驱动
评分 null新上架无评论代码里判空,默认值 “N/A”
被重定向验证码标题含 “Robot Check”立即丢弃代理,冷宫 30 min
图片 URL 失效带时效参数及时转存到自家 OSS
CSV 中文乱码Excel 打开是 “???”写文件时 utf-8-sig 带 BOM

八、10 万级 ASIN 分布式方案

单脚本玩 3 个 ASIN 没毛病,老板一句“给我把全站 30 万 SKU 每天扫一遍”怎么办?
把上面的 MVP 拆成“三件套”即可水平扩展:

  1. 调度层
    Airflow + KubernetesPodOperator,把 30 万 ASIN 按热度拆成 4 档,分别给 4 个 DAG(小时级/日级/周级/月级)。

  2. 抓取节点
    K8s 部署 20 个 Pod,每个 Pod 消费 Redis 队列,抓取完回写 S3(Parquet 格式)。

  3. 监控大盘
    Prometheus 采集“成功数 / 429 数 / 平均耗时”,Grafana 一屏展示;超过阈值自动飞书 + 邮件。


九、Docker 一键部署(附 Dockerfile)

dockerfile

FROM mcr.microsoft.com/playwright/python:v1.42.0-focal
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY scraper.py .
CMD ["python", "scraper.py"]

构建 & 运行:

bash

docker build -t amz-py .
docker run --rm -v $(pwd)/data:/app/data amz-py

十、写在最后的“防吃牢饭”提示

Amazon 的数据受《计算机欺诈与滥用法》(CFAA)及《数字千年版权法》(DMCA)保护,请务必

  1. 仅抓取“公开可见、无需登录” 的页面;

  2. 遵守 robots.txt(Amazon 几乎全站 allow:/,但频率需合理);

  3. 数据仅限内部商业分析,不得直接转载、转售或公开 API 化

  4. 生产环境先行法律评估,必要时与律师确认合规条款。

http://www.dtcms.com/a/512661.html

相关文章:

  • 开箱即用,15分钟极速部署:富唯智能精密仪器搬运机器人重塑工业自动化
  • 网站建设个人实训报告seo免费入门教程
  • 一个服务器下怎么做两个网站吗网站上海备案查询系统
  • STM32实现呼吸灯效果原理
  • 做营销网站要多少钱网站开发平台建设
  • html css js网页制作成品——HTML+CSS仙台有树电视剧网页设计(5页)附源码
  • 开发避坑指南(64):修复IllegalArgumentException:参数值类型与期望类型不匹配
  • 企业网站怎样做seo优化 应该如何做凡科建站官网怎么样
  • 【Java进阶】GC友好的编程方式
  • 甘肃肃第八建设集团网站福州市高速公路建设指挥部网站
  • 鸿蒙NEXT媒体开发全栈解析:从播放器到录屏的一站式解决方案
  • 郑州做网站排名dede网站首页
  • python 做网站很快吗广州自助网站推广建站
  • AD22 热风焊盘在哪设置
  • CMake进阶:生成器表达式
  • 从 Vite 到现代构建范式:一个关于“快”的技术哲学
  • 2025世界智能制造大会(南京)将带来那些新技术与新体验?
  • 杭州网站建设杭州上海哪个网站好用
  • 做网站的文案是指网站怎么做才能赚钱吗
  • 完善企业能力等级评价体系 构建高质量发展新标尺
  • Vue2 封装二维码弹窗组件
  • 哪里有做网站较好的公司龙华做网站怎么样
  • 在1688做公司网站前端开发语言的特点是
  • 少儿教育网站建设价格免费看电视剧的网站在线观看
  • (四)从零学 React Props:数据传递 + 实战案例 + 避坑指南
  • 上传自己做的网站吗关键词优化百家号
  • 连云港做网站公司校园网的规划与设计
  • DeepSeek-OCR:视觉压缩的革命性突破——当OCR遇上LLM的“降维打击“
  • 盐城网站开发市场做网站怎么去工信部缴费
  • ps做游戏网站伊宁网站建设优化