可视化 eBay 竞争对手定价:从原始 JSONL 到价格趋势仪表盘

发布: (2026年2月5日 GMT+8 14:13)
7 min read
原文: Dev.to

Source: Dev.to

在竞争激烈的电子商务领域,价格往往是唯一决定客户是点击你商品的 “Buy It Now” 还是竞争对手商品的因素。抓取数据只是第一步——真正的价值在于将原始数据转化为可操作的洞察:实时发现被压价、识别价格底线,以及跟踪随时间的趋势。

本指南展示了如何构建一个端到端的流水线,以实现:

  1. 抓取 eBay 商品数据,使用 Playwright
  2. 处理 数据,使用 Pandas
  3. 可视化 竞争对手的价格变动,在 Streamlit 仪表盘中。

1. 设置

我们将使用 Ebay.com‑Scrapers 仓库,其中包含针对 eBay 结构优化的生产就绪爬虫。

前置条件

  • Python 3.8+
  • 一个 ScrapeOps API Key(用于绕过反机器人)——获取方式请参见
  • 基本的终端操作技能

安装

# Clone the repo
git clone https://github.com/scraper-bank/Ebay.com-Scrapers.git
cd Ebay.com-Scrapers/python/playwright/product_data

# Install dependencies
pip install playwright playwright-stealth pandas streamlit

# Install the Chromium browser used by Playwright
playwright install chromium

我们使用 playwright/product_data 实现,因为它可以提取诸如 productIdpriceavailability 等细粒度信息,这对于时间序列跟踪至关重要。

2. 配置竞争对手的爬虫

默认的爬虫只处理单个 URL。若要跟踪竞争对手,需要定期对 产品页面列表 运行爬虫。

创建一个名为 run_tracker.py 的包装脚本,循环遍历目标 URL 并保存结果。爬虫会自动在文件名后追加时间戳(例如 ebay_com_product_page_scraper_data_20260116_090000.jsonl),从而便于进行历史追踪。

# run_tracker.py
import asyncio
from scraper.ebay_com_scraper_product_v1 import extract_data, API_KEY
from playwright.async_api import async_playwright

# List of competitor product URLs to monitor
COMPETITOR_URLS = [
    "https://www.ebay.com/itm/123456789012",
    "https://www.ebay.com/itm/987654321098",
]

async def run_monitoring_session():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()

        for url in COMPETITOR_URLS:
            print(f"Scraping competitor: {url}")
            await page.goto(url)
            data = await extract_data(page)

            # Data saving is handled by the DataPipeline class in the core scraper
            print(f"Extracted Price: {data.price} {data.currency}")

        await browser.close()

if __name__ == "__main__":
    asyncio.run(run_monitoring_session())

3. 理解数据结构

爬虫会输出 JSONL(JSON Lines) 文件——一种可流式处理的格式,对大规模价格跟踪数据集来说内存使用更高效。

示例记录

{
  "productId": "123456789012",
  "name": "Apple iPhone 15 Pro - 128GB - Blue Titanium",
  "price": 899.0,
  "currency": "USD",
  "availability": "in_stock",
  "seller": { "name": "TopTierElectronics", "rating": 99.8 }
}

关键细节

  • 价格清洗 – 爬虫会将类似 "$899.00" 的字符串转换为浮点数 (899.0)。
  • 可用性 – 当竞争对手出现 out_of_stock 时,需要决定在图表上如何表示(例如,断开折线或绘制为零)。

4. 使用 Pandas 进行数据摄取与清洗

每次爬虫运行都会生成一个新文件。第一步是将所有文件合并为一个按时间顺序排列的 DataFrame。我们从文件名中提取时间戳,以构建时间轴。

import pandas as pd
import glob
import re
import json
from datetime import datetime

def load_historical_data(directory="./"):
    """Load all JSONL files generated by the scraper into a single DataFrame."""
    all_data = []
    # Find all JSONL files matching the scraper’s naming pattern
    files = glob.glob(f"{directory}/ebay_com_product_page_scraper_data_*.jsonl")

    for file in files:
        # Extract timestamp from filename: e.g., 20260116_090000
        match = re.search(r'(\d{8}_\d{6})', file)
        if not match:
            continue

        timestamp = datetime.strptime(match.group(1), "%Y%m%d_%H%M%S")

        with open(file, "r", encoding="utf-8") as f:
            for line in f:
                item = json.loads(line)
                item["scrape_timestamp"] = timestamp
                all_data.append(item)

    df = pd.DataFrame(all_data)
    # Ensure price is numeric
    df["price"] = pd.to_numeric(df["price"], errors="coerce")
    return df

Source:

5. 使用 Streamlit 构建仪表盘

现在我们创建一个可视化界面,让你可以按产品名称筛选,并查看价格在天或周之间的波动。

dashboard.py

import streamlit as st
import pandas as pd

# Load the helper function from the previous section
from load_data import load_historical_data   # adjust import path as needed

st.set_page_config(page_title="eBay Price Tracker", layout="wide")
st.title("📈 eBay Competitor Price Trends")

# Load data
df = load_historical_data()

# Sidebar filters
available_products = df["name"].unique()
selected_products = st.sidebar.multiselect(
    "Select Products to Track",
    options=available_products,
    default=available_products[:2],
)

filtered_df = df[df["name"].isin(selected_products)]

# Main chart
if not filtered_df.empty:
    # Pivot data so each product has its own time series
    pivot = (
        filtered_df.pivot_table(
            index="scrape_timestamp",
            columns="name",
            values="price",
            aggfunc="first",
        )
        .sort_index()
    )
    st.line_chart(pivot)
else:
    st.info("No data available for the selected products.")

运行仪表盘:

streamlit run dashboard.py

现在你将拥有一个交互式仪表盘,它:

  • 显示任意选中竞争对手产品的价格趋势。
  • 当新的 JSONL 文件出现时自动更新(只需刷新页面)。
  • 通过折线图中的间断突出显示缺货期间。

额外的价格历史图(可选)

# each product has its own column for the line chart
chart_data = filtered_df.pivot(
    index='scrape_timestamp',
    columns='name',
    values='price'
)

st.subheader("Price History")
st.line_chart(chart_data)

# Metrics
cols = st.columns(len(selected_products))
for i, product in enumerate(selected_products):
    latest_price = filtered_df[filtered_df['name'] == product].iloc[-1]['price']
    cols[i].metric(label=product[:30] + "...", value=f"${latest_price}")
else:
    st.write("Please select a product to see the price trend.")

使用以下命令运行仪表盘:

streamlit run dashboard.py

6. 自动化工作流

仪表板只有在数据是最新的情况下才有价值。每天早上手动运行爬虫效率低下。

Linux / macOS

设置 cron 任务 每 6 小时运行一次 run_tracker.py 脚本:

0 */6 * * * /usr/bin/python3 /path/to/run_tracker.py

Windows

使用 任务计划程序 实现相同的效果。完成自动化后,Streamlit 仪表板将在每次刷新页面时更新为最新的价格数据。

总结

我们已经从简单的数据提取转向构建一个功能性业务工具。通过将 ScrapeOps eBay 仓库的抓取能力与 Pandas 和 Streamlit 的分析能力相结合,您现在拥有了一个自定义的价格情报平台。

关键要点

  • JSONL 高效 – 记录时间序列抓取数据的最佳格式。
  • 文件名时间戳 – 将元数据存储在文件名中,可防止内部 JSON 结构更改时的数据丢失。
  • 可视化有效 – 在折线图上看到 5 % 的价格下降,比扫描原始文本文件更容易采取行动。

想了解更多关于绕过反机器人措施的内容,请查看 eBay Scraping Breakdown

Back to Blog

相关文章

阅读更多 »