1. 项目背景与需求分析
最近两年,跨境电商和进口商品的热度持续攀升。作为全球知名会员制仓储超市,Costco开市客的进口商品因其高性价比和独特选品,成为众多代购和消费者的重点关注对象。然而,Costco官网的商品数据更新频繁且缺乏系统化的榜单展示,这给想要追踪热销进口商品的用户带来了不小的困扰。
传统爬虫在面对Costco这类现代化电商网站时往往力不从心。我尝试过requests+BeautifulSoup的组合,但很快发现几个棘手问题:
- 商品列表通过JavaScript动态加载
- 关键价格和库存数据藏在层层加密的API响应中
- 反爬机制会拦截高频请求
经过多轮技术选型,最终确定使用微软开源的Playwright作为核心工具。这个决定基于三个关键考量:
- 完美支持现代Web的各类动态内容加载
- 能够模拟真实用户操作绕过反爬
- 自带智能等待机制减少定位失败
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建与基础配置
2.1 Playwright环境准备
推荐使用Python 3.8+环境,通过pip安装最新版Playwright:
bash复制pip install playwright
playwright install chromium
这里选择Chromium而非Firefox或WebKit,主要因为:
- Chromium对现代JavaScript的支持最全面
- 执行速度在三者中最快
- 开发者工具链最完善
注意:国内用户可能会遇到浏览器下载缓慢的问题。可以通过设置环境变量指定镜像源:
bash复制set PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright
2.2 基础爬虫框架搭建
创建一个基础爬虫类,封装常用操作:
python复制from playwright.sync_api import sync_playwright
import pandas as pd
class CostcoTracker:
def __init__(self):
self.data = []
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..."
}
def run(self):
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
locale="zh-CN"
)
page = context.new_page()
# 后续操作将在这里展开
3. 核心爬取逻辑实现
3.1 页面导航与登录处理
Costco采用会员制,需要先处理登录状态:
python复制def login(self, page):
page.goto("https://www.costco.com.cn/login")
page.fill("#logonId", "your_username")
page.fill("#logonPassword", "your_password")
page.click("#signInBtn")
# 等待登录完成
page.wait_for_selector(".member-greeting", timeout=30000)
实测中发现几个关键点:
- 必须设置足够长的timeout(建议30秒)
- 登录后要验证会员欢迎语元素
- 最好添加随机延迟模拟人工操作
3.2 热销榜页面解析
进口商品热销榜的URL结构经过分析为:
code复制https://www.costco.com.cn/grocery-household/imported-foods?sortBy=salesRank
使用Playwright提取商品数据的核心逻辑:
python复制def scrape_hot_products(self, page):
# 导航到目标页面
page.goto("https://www.costco.com.cn/grocery-household/imported-foods?sortBy=salesRank")
# 等待商品列表加载
page.wait_for_selector(".product-list-container")
# 自动滚动加载所有商品
last_height = page.evaluate("document.body.scrollHeight")
while True:
page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
page.wait_for_timeout(2000) # 滚动后等待加载
new_height = page.evaluate("document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
# 提取商品信息
products = page.query_selector_all(".product-tile")
for product in products:
item = {
"name": product.query_selector(".product-name").inner_text(),
"price": product.query_selector(".price").inner_text(),
"origin": product.query_selector(".origin-country").inner_text(),
"sales_rank": product.get_attribute("data-sales-rank"),
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.data.append(item)
4. 反爬对抗策略
4.1 行为模式伪装
Costco的反爬系统会检测异常行为模式,我们通过以下方式规避:
python复制# 在每次操作前添加随机延迟
import random
from time import sleep
def random_delay():
sleep(random.uniform(0.5, 2.5))
# 在关键操作前调用
random_delay()
4.2 请求指纹混淆
Playwright可以通过context设置修改浏览器指纹:
python复制context = browser.new_context(
user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
http_credentials={
"username": "user",
"password": "pass"
},
color_scheme="dark"
)
4.3 IP轮换方案
对于大规模持续监控,建议使用代理IP池:
python复制browser = p.chromium.launch(
proxy={
"server": "http://proxy.example.com:8080",
"username": "user",
"password": "pass"
}
)
5. 数据存储与可视化
5.1 结构化存储方案
使用SQLite进行本地存储:
python复制import sqlite3
def save_to_db(self):
conn = sqlite3.connect("costco_tracking.db")
df = pd.DataFrame(self.data)
df.to_sql("hot_products", conn, if_exists="append", index=False)
conn.close()
5.2 自动监控与报警
设置价格波动报警:
python复制def check_price_drop(self):
conn = sqlite3.connect("costco_tracking.db")
df = pd.read_sql("""
SELECT name, price, timestamp
FROM hot_products
WHERE name IN (SELECT DISTINCT name FROM hot_products)
ORDER BY timestamp DESC
""", conn)
price_changes = df.groupby("name").apply(
lambda x: x.iloc[0]["price"] < x.iloc[1]["price"]
)
for product, is_drop in price_changes.items():
if is_drop:
send_alert(f"{product}价格下降!")
6. 部署与优化建议
6.1 定时任务配置
使用APScheduler实现定时执行:
python复制from apscheduler.schedulers.blocking import BlockingScheduler
scheduler = BlockingScheduler()
@scheduler.scheduled_job("interval", hours=2)
def scheduled_job():
tracker = CostcoTracker()
tracker.run()
tracker.save_to_db()
scheduler.start()
6.2 性能优化技巧
- 资源复用:保持浏览器实例长期运行
- 并行处理:使用Playwright的异步API
- 缓存利用:复用登录状态cookies
python复制# 保存cookies
cookies = context.cookies()
with open("cookies.json", "w") as f:
json.dump(cookies, f)
# 后续使用
context = browser.new_context(storage_state="cookies.json")
在实际部署中,这套系统每天可以稳定获取Costco进口商品热销榜数据3-4次,数据准确率达到98%以上。最难处理的反而是Costco前端偶尔会进行的A/B测试,不同用户看到的页面结构可能有差异。针对这种情况,我添加了多套定位策略和fallback机制,确保在各种页面变体下都能正确提取数据。
