使用 Python 抓取 eBay:真正能跑的程式碼

最後更新於 April 16, 2026

多數 eBay 爬蟲教學的有效期大概只有三個月。我會這麼說,是因為 Thunderbit 團隊親眼看過開發者反覆踩進壞掉的程式片段、過時的 CSS 選擇器,以及那些「看起來能用」的 GitHub 倉庫——其實早在兩次 eBay 改版前就悄悄失效了。

eBay 擁有 ,是開放網路上繼 Amazon 之後最大的長尾價格資料庫。這些資料支撐了從轉售定價到競品分析等各種應用。但若要用程式化方式取得它,情況就像在追移動標靶:eBay 以 React 打造的前端會頻繁變動 CSS 類名,A/B 測試會讓不同使用者看到不同的 DOM 結構,而 Akamai Bot Manager 也會擋在你和 HTML 之間。這篇指南會提供今天還能用的 Python 程式碼,說明爬蟲為什麼會壞掉,幫你建立更耐用的做法,客觀比較 eBay API 與直接爬取的差異,並在 Python 不值得花時間時,提供一條免寫程式的替代路徑。

用 Python 抓 eBay 到底是什麼意思?

用 Python 爬 eBay,指的是撰寫程式自動下載 eBay 網頁、解析 HTML(或隱藏的 JSON),再把結構化資料擷取出來——像是標題、價格、賣家資訊、售出日期、規格變體——整理成你真正能使用的格式,例如 CSV、試算表或資料庫。

你可以抓取幾種 eBay 頁面:

  • 搜尋結果頁(例如所有 "AirPods Pro" 商品)
  • 單一商品詳情頁(完整規格、圖片、賣家資訊)
  • 已售出 / 已完成商品頁(實際成交價格與日期)
  • 賣家個人檔案與評價

Python 是這類工作的首選語言。它的生態系——Requests、BeautifulSoup、lxml、pandas——讓你可以很直接地抓頁面、解析 HTML、整理資料。不過,直接爬網站 HTML 和使用 eBay 官方 API 之間,還是有很大的差別;下一段我會一起說清楚。

為什麼要爬 eBay?商業團隊的真實應用場景

如果你正在看這篇文章,八成已經有自己的理由。不過,我還是想把討論拉回實際商業價值,因為 eBay 資料的投資報酬率真的很驚人。Bain 發現,已實現價格只要提升 ,這個結論適用於成千上萬家企業。McKinsey 則指出,零售業的動態定價可帶來

我最常看到的使用情境如下:

使用情境所需資料商業成效
價格監控與重新定價在售商品價格、運費、商品狀況競爭定價、守住利潤空間
競品分析商品組合、促銷活動、運送條件策略定位、補足品項缺口
市場研究與趨勢洞察上架速度、類別趨勢、需求模式找到新產品、預測需求
轉售定價 / 鑑價售出價格、售出日期、商品狀況公允市價、買入決策
情緒分析評價、星等、退貨政策產品品質洞察、顧客滿意度
潛在客戶開發賣家檔案、店鋪資訊、聯絡方式對高 GMV 賣家進行 B2B 開發

ebayscraping_stats_77c7da1611.png

核心概念很簡單:eBay 的確有資料,但它被鎖在網頁裡。

爬蟲的價值,就是把這些資料轉化成競爭優勢。

eBay 官方 API 與 Python 網頁爬蟲:該選哪一個?

這是我希望更多教學都能誠實回答的問題。eBay 提供官方 API——主要是 ——很多人也會想知道,究竟該用 API 還是直接爬取。答案完全取決於你需要什麼資料。

比較項目eBay Browse / Finding APIPython 網頁爬蟲
已售出 / 已完成商品有限——存在 Marketplace Insights API,但 常常無法取得存取權可透過 LH_Sold=1&LH_Complete=1 URL 參數完整取得
速率限制基本方案每天 5,000 次呼叫自行管理(取決於代理伺服器)
資料欄位預先定義(標題、價格、類別、賣家基本資訊)頁面上看得到的都能抓(評價、完整規格、變體矩陣)
架設複雜度OAuth 2.0、應用程式註冊、API 金鑰pip install + 程式碼
穩定性端點穩定HTML 一變就壞
成本有免費額度,量大需付費程式免費,但規模化後要付代理成本
變體 / MSKU 資料部分可得——很多情況只提供父 SKU完整可得(透過隱藏 JSON 解析)
分頁深度10,000 筆硬上限理論上沒上限

補充一下:舊版 Finding API(包含 findCompletedItems)已在 。如果你還在用 ebaysdk-python 或任何呼叫 Finding 模組的函式庫,它現在在正式環境裡已經壞掉了。

**我的建議:**如果你要查的是在售商品、需要穩定且中等量的結構化目錄資料,請用 Browse API。若你需要的是售出價格、評價、變體資料,或 API 沒有公開的欄位,就改用 Python 爬蟲。很多團隊兩者都會一起用。

用 Python 抓 eBay 需要哪些工具與函式庫?

在寫程式之前,先把工具備齊。多數 eBay 頁面不需要無頭瀏覽器——資料其實已經嵌在伺服器渲染後的 HTML 裡。

函式庫用途
requestshttpx下載 eBay 頁面的 HTTP 客戶端
curl_cffi具備真實瀏覽器 TLS 指紋的 HTTP 客戶端(繞過 Akamai 的關鍵)
beautifulsoup4用 CSS 選擇器抽取 HTML 的解析器
lxmlBeautifulSoup 的高速解析後端
jmespath查詢巢狀 JSON 區塊的語法
pandas資料處理與匯出 CSV / Excel
gspread串接 Google Sheets

一行安裝全部套件:

1pip install requests httpx curl_cffi beautifulsoup4 lxml jmespath pandas gspread

請使用 Python 3.11+——pandas 3.0 需要 3.10 以上,而 3.11 在 I/O 密集型工作上可帶來 10–60% 的速度提升。

有一個函式庫值得特別提一下:curl_cffi 會是 2026 年 eBay 爬蟲最有感的升級。eBay 使用 ,Akamai 主要透過 TLS 指紋來辨識爬蟲。單純的 requests 會產生很像 Python 的 JA3 指紋,很容易立刻被標記。curl_cffi 則能模擬真實 Chrome 瀏覽器的 TLS 握手,對大約 90% 受 Akamai 保護的目標都能奏效,通常不必動用無頭瀏覽器。

逐步教學:如何用 Python 抓取 eBay 搜尋結果

這是本文的核心教學。我們會抓 eBay 搜尋結果頁上的商品列表。

  • 難度: 初學者到中階
  • 所需時間: 第一次成功抓取約 30 分鐘
  • 你需要: Python 3.11+、上述函式庫、終端機,以及一個目標 eBay 搜尋網址

第 1 步:建立 Python 專案

建立專案資料夾並安裝相依套件:

1mkdir ebay-scraper && cd ebay-scraper
2python -m venv venv
3source venv/bin/activate  # Windows: venv\Scripts\activate
4pip install requests curl_cffi beautifulsoup4 lxml pandas

建立一個名為 scrape_ebay.py 的檔案,這就是你的工作區。

第 2 步:建立 eBay 搜尋網址

eBay 的搜尋網址結構很直觀。關鍵參數是 _nkw(關鍵字):

1import urllib.parse
2keyword = "airpods pro"
3base_url = "https://www.ebay.com/sch/i.html"
4params = {
5    "_nkw": keyword,
6    "_ipg": "120",    # 每頁筆數:60、120 或 240(240 可能觸發 bot 標記)
7    "_pgn": "1",      # 頁碼
8}
9url = f"{base_url}?{urllib.parse.urlencode(params)}"
10print(url)
11# https://www.ebay.com/sch/i.html?_nkw=airpods+pro&_ipg=120&_pgn=1

其他常用參數:

  • LH_BIN=1 — 只顯示立即購買
  • _sacat=175673 — 指定類別
  • _sop=12 — 依最佳匹配排序(10 = 含運費最低,13 = 最新上架)
  • LH_Complete=1&LH_Sold=1 — 已售出 / 已完成商品(下方有專章說明)

第 3 步:送出請求並處理回應

這裡就是 curl_cffi 發揮價值的地方。直接使用 requests.get() 很常會收到 Akamai 回傳的 403。用 curl_cffi 則可以偽裝成真實 Chrome 瀏覽器:

1from curl_cffi import requests as cffi_requests
2import random, time
3USER_AGENTS = [
4    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
5    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
6    "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0",
7]
8HEADERS = {
9    "User-Agent": random.choice(USER_AGENTS),
10    "Accept-Language": "en-US,en;q=0.9",
11    "Accept-Encoding": "gzip, deflate, br",
12}
13def fetch_page(url, max_retries=5):
14    delay = 2
15    for attempt in range(max_retries):
16        try:
17            r = cffi_requests.get(url, impersonate="chrome124", headers=HEADERS, timeout=30)
18            if r.status_code == 200:
19                return r.text
20            if r.status_code in (403, 429, 503):
21                retry_after = r.headers.get("Retry-After")
22                sleep_for = float(retry_after) if retry_after else delay + random.uniform(0, 1)
23                print(f"  狀態碼 {r.status_code}{sleep_for:.1f} 秒後重試...")
24                time.sleep(sleep_for)
25                delay *= 2
26                continue
27            r.raise_for_status()
28        except Exception as e:
29            print(f"  請求錯誤:{e},重試中...")
30            time.sleep(delay)
31            delay *= 2
32    raise RuntimeError(f"重試 {max_retries} 次後仍失敗:{url}")

指數退避加上隨機抖動很重要——固定睡眠間隔本身就是 bot 指紋的一種。

第 4 步:從搜尋頁解析商品列表

eBay 目前正處在兩種搜尋結果版型的過渡期。一個耐用的爬蟲必須同時支援兩種:

欄位舊版版型新版版型
卡片容器li.s-itemli.s-carddiv.su-card-container
標題.s-item__title.s-card__title
連結a.s-item__link[href]a.su-link[href]
價格span.s-item__price.s-card__price

同時處理兩種版型的解析程式如下:

1from bs4 import BeautifulSoup
2def parse_search_results(html):
3    soup = BeautifulSoup(html, "lxml")
4    cards = soup.select("li.s-item, li.s-card, div.su-card-container")
5    results = []
6    for card in cards:
7        # 標題——同時嘗試兩種版型
8        title_el = card.select_one(".s-item__title, .s-card__title")
9        title = title_el.get_text(strip=True) if title_el else None
10        # 跳過虛假的「Shop on eBay」占位卡片
11        if not title or "Shop on eBay" in title:
12            continue
13        # 價格
14        price_el = card.select_one("span.s-item__price, .s-card__price")
15        price = price_el.get_text(strip=True) if price_el else None
16        # 連結
17        link_el = card.select_one("a.s-item__link[href], a.su-link[href]")
18        url = link_el["href"].split("?")[0] if link_el else None
19        # 圖片
20        img_el = card.select_one("img.s-item__image-img, .s-card__image img")
21        image = None
22        if img_el:
23            image = img_el.get("src") or img_el.get("data-src")
24        # 運費
25        ship_el = card.select_one("span.s-item__shipping, span.s-item__logisticsCost, .s-card__attribute-row")
26        shipping = ship_el.get_text(strip=True) if ship_el else None
27        results.append({
28            "title": title,
29            "price": price,
30            "url": url,
31            "image": image,
32            "shipping": shipping,
33        })
34    return results

第一張假卡片這個坑非常經典。很多 eBay 搜尋頁面上的第一個 li.s-item 其實只是隱藏的占位內容,標題是「Shop on eBay」,沒有真正的價格。務必要把它過濾掉。

第 5 步:處理分頁,抓取多頁資料

eBay 用 _pgn 參數處理分頁。下一頁連結則使用 a.pagination__next

1import urllib.parse
2def scrape_ebay_search(keyword, max_pages=5):
3    all_results = []
4    for page_num in range(1, max_pages + 1):
5        params = {"_nkw": keyword, "_ipg": "120", "_pgn": str(page_num)}
6        url = f"https://www.ebay.com/sch/i.html?{urllib.parse.urlencode(params)}"
7        print(f"正在抓取第 {page_num} 頁:{url}")
8        html = fetch_page(url)
9        results = parse_search_results(html)
10        if not results:
11            print(f"  第 {page_num} 頁沒有結果,停止抓取。")
12            break
13        all_results.extend(results)
14        print(f"  找到 {len(results)} 筆商品(總計:{len(all_results)})")
15        # 禮貌等待——3 到 8 秒的隨機抖動
16        time.sleep(random.uniform(3, 8))
17    return all_results

3–8 秒的隨機等待不是可選項。

eBay 的 Akamai 層會對單一 IP 持續超過每秒 1 次的請求進行標記。

第 6 步:將抓到的資料匯出成 CSV 或 JSON

1import pandas as pd
2results = scrape_ebay_search("airpods pro", max_pages=3)
3df = pd.DataFrame(results)
4df.to_csv("ebay_airpods.csv", index=False)
5df.to_json("ebay_airpods.json", orient="records", indent=2)
6print(f"已將 {len(df)} 筆商品匯出為 CSV 和 JSON。")

現在你應該已經有一份乾淨的 eBay 商品試算表了。在我的電腦上,抓 3 頁(360 筆商品)加上延遲大約花了 45 秒。

如何用 Python 抓 eBay 商品詳情頁

搜尋結果只會給你摘要。商品詳情頁才有真正有用的內容:完整描述、賣家回饋分數、商品規格、圖片輪播,以及變體資料。

解析單一商品頁面

eBay 商品頁位於 /itm/<ITEM_ID>。最穩定的擷取方式是 JSON-LD——eBay 會在頁面中嵌入 Product schema 區塊,幾乎不受 CSS 改版影響:

1import json
2def parse_item_page(html):
3    soup = BeautifulSoup(html, "lxml")
4    item = {}
5    # 1. JSON-LD —— 最穩定的擷取路徑
6    for tag in soup.find_all("script", type="application/ld+json"):
7        try:
8            data = json.loads(tag.string or "")
9        except (json.JSONDecodeError, TypeError):
10            continue
11        if isinstance(data, dict) and data.get("@type") == "Product":
12            item["title"] = data.get("name")
13            item["brand"] = (data.get("brand") or {}).get("name")
14            item["images"] = data.get("image")
15            offers = data.get("offers") or {}
16            item["price"] = offers.get("price")
17            item["currency"] = offers.get("priceCurrency")
18            break
19    # 2. 針對 JSON-LD 沒有的欄位,使用 CSS 備援
20    def first_text(selectors):
21        for sel in selectors:
22            el = soup.select_one(sel)
23            if el and el.get_text(strip=True):
24                return el.get_text(strip=True)
25        return None
26    item.setdefault("title", first_text([
27        "h1.x-item-title__mainTitle",
28        "h1.x-item-title__mainTitle .ux-textspans--BOLD",
29    ]))
30    item["condition"] = first_text([
31        ".x-item-condition-text .ux-textspans",
32    ])
33    item["seller"] = first_text([
34        ".x-sellercard-atf__info__about-seller a .ux-textspans",
35    ])
36    item["shipping"] = first_text([
37        "div.ux-labels-values--shipping .ux-textspans--BOLD",
38    ])
39    # 3. 商品規格
40    specifics = {}
41    for dl in soup.select(".ux-layout-section-evo__item--table-view dl.ux-labels-values"):
42        k = dl.select_one(".ux-labels-values__labels-content .ux-textspans")
43        v = dl.select_one(".ux-labels-values__values-content .ux-textspans")
44        if k and v:
45            specifics[k.get_text(strip=True).rstrip(":")] = v.get_text(strip=True)
46    item["specifics"] = specifics
47    return item

這個模式——先抓 JSON-LD,再用 CSS 備援——是打造不會每季都壞掉的爬蟲關鍵。下面還會再提到。

抓取 eBay 商品變體(MSKU 資料)

有些 eBay 商品有多種變體——不同顏色、尺寸、容量。可見的 DOM 通常只會顯示一個價格區間,例如 "$899 to $1,099",直到使用者點選某個選項。每個變體的實際價格,其實藏在一個叫做 MSKU 的隱藏 JavaScript 物件裡。

這也是 eBay API 只能提供部分資料(父 SKU)的地方,因此直接爬取反而更合適。

1import re, json
2def extract_variants(html):
3    # 非貪婪比對很重要——貪婪的 .+ 會把整個頁面都吃掉
4    m = re.search(r'"MSKU"\s*:\s*(\{.+?\})\s*,\s*"QUANTITY"', html, re.DOTALL)
5    if not m:
6        return []
7    try:
8        msku = json.loads(m.group(1))
9    except json.JSONDecodeError:
10        return []
11    item_labels = {str(k): v["displayLabel"] for k, v in msku.get("menuItemMap", {}).items()}
12    skus = []
13    for combo_key, variation_id in msku.get("variationCombinations", {}).items():
14        option_ids = combo_key.split("_")
15        options = [item_labels.get(oid, oid) for oid in option_ids]
16        var = msku.get("variationsMap", {}).get(str(variation_id), {})
17        bin_model = var.get("binModel", {})
18        price_spans = bin_model.get("price", {}).get("textSpans", [{}])
19        price = price_spans[0].get("text") if price_spans else None
20        qty = var.get("quantity")
21        skus.append({
22            "options": options,
23            "price": price,
24            "quantity_available": qty,
25            "variation_id": variation_id,
26        })
27    return skus

正是這個 regex 裡的非貪婪 (.+?),最常讓每個 eBay 爬蟲出問題。若改成貪婪的 .+,它會一路吃到頁面裡最後一個 "QUANTITY",導致 JSON 解析失敗。我至少看過三篇「能用」的教學都踩過這個雷。

如何用 Python 抓 eBay 已售出與已完成商品

這正是「爬蟲」相較於 API 最有說服力的用途。已售出資料——實際成交了什麼、成交價是多少、何時成交——是市場研究、轉售定價與鑑價的黃金標準。eBay Browse API 明確不提供這些資料。雖然 理論上有,但它屬於「Limited Release」,而且

你需要的網址參數是 LH_Complete=1(已完成)和 LH_Sold=1(限制為真正已售出)。兩個都要加。 在某些類別中,只加 LH_Sold=1 會默默退回到在售商品——這是社群最常踩的第 1 個坑。

1def scrape_sold_listings(keyword, max_pages=3):
2    all_sold = []
3    for page_num in range(1, max_pages + 1):
4        params = {
5            "_nkw": keyword,
6            "_ipg": "120",
7            "_pgn": str(page_num),
8            "LH_Complete": "1",
9            "LH_Sold": "1",
10        }
11        url = f"https://www.ebay.com/sch/i.html?{urllib.parse.urlencode(params)}"
12        print(f"正在抓取已售出第 {page_num} 頁...")
13        html = fetch_page(url)
14        soup = BeautifulSoup(html, "lxml")
15        cards = soup.select("li.s-item")
16        for card in cards:
17            title_el = card.select_one(".s-item__title")
18            title = title_el.get_text(strip=True) if title_el else None
19            if not title or "Shop on eBay" in title:
20                continue
21            # 只保留真正已售出的商品(綠色 POSITIVE 價格標示)
22            sold_tag = card.select_one(
23                ".s-item__title--tag .POSITIVE, .s-item__caption--signal.POSITIVE"
24            )
25            if sold_tag is None:
26                continue  # 已完成但未售出的商品——略過
27            price_el = card.select_one("span.s-item__price")
28            price = price_el.get_text(strip=True) if price_el else None
29            # 解析售出日期
30            sold_date = None
31            import re, datetime as dt
32            card_text = card.get_text()
33            m = re.search(r"Sold\s+([A-Z][a-z]{2}\s+\d{1,2},\s*\d{4})", card_text)
34            if m:
35                sold_date = dt.datetime.strptime(m.group(1), "%b %d, %Y").strftime("%Y-%m-%d")
36            link_el = card.select_one("a.s-item__link[href]")
37            url = link_el["href"].split("?")[0] if link_el else None
38            all_sold.append({
39                "title": title,
40                "sold_price": price,
41                "sold_date": sold_date,
42                "url": url,
43            })
44        if not cards:
45            break
46        time.sleep(random.uniform(3, 8))
47    return all_sold

HTML 上的關鍵差異在於:已售出商品會把價格顯示成綠色(包在 .POSITIVE 容器裡),而未售出的已完成商品則會以紅色刪除線顯示。務必要用 .POSITIVE 這個 class 來過濾。

為什麼 eBay 爬蟲會壞掉,以及如何打造更耐用的版本

如果你的 eBay 爬蟲失效了,你並不孤單。這是我讀過的每一篇 eBay 爬蟲論壇討論中最常見的痛點。問題不是你的爬蟲「會不會」壞,而是「什麼時候」會壞。

原因如下:

  • eBay 採用 React 風格渲染,部署時會產生動態 CSS 類名,常常改動
  • A/B 測試會讓不同使用者看到不同的 DOM 結構(現在雙版型的 s-item / s-card 就是活生生的例子)
  • 定期改版會改變 HTML 的巢狀結構,即使資料本身沒變
  • 舊選擇器像 #itemTitle#prcIsum 早就被移除,但教學還是常常拿來舉例

正如 所說:「eBay 網頁爬取真正的挑戰,在於處理 eBay 的 CSS 選擇器變更。eBay 會定期更新前端,導致依賴特定 class 名稱的爬蟲失效。」

ebayscraping_section_50be5cc410.png

讓 eBay 爬蟲更長壽的防禦策略

以下四種策略,能讓你的爬蟲撐過 eBay 每季的重整:

1. 優先解析 JSON-LD,而不是 CSS 選擇器。 eBay 會在每個商品頁中嵌入結構化的 Product schema 資料。資料層的變動遠少於呈現層——設計師每季都會重構 CSS 類名,但像 pricenameseller 這些後端欄位通常對應內部 API,不太會改名。

2. 使用層層備援的選擇器。 絕不要只依賴一個 CSS 選擇器,務必提供替代方案:

1def first_text(soup, selectors):
2    for sel in selectors:
3        el = soup.select_one(sel)
4        if el and el.get_text(strip=True):
5            return el.get_text(strip=True)
6    return None
7title = first_text(soup, [
8    "h1.x-item-title__mainTitle",
9    "h1.x-item-title__mainTitle .ux-textspans--BOLD",
10    "[data-testid='x-item-title'] h1",
11])

3. 解析隱藏的 JSON 區塊。 MSKU 變體物件和內嵌 JavaScript 資料不受 CSS 變動影響,因為它們是伺服器端產生的。雖然從 <script> 標籤裡用 regex 抓資料,前期工作比較多,但後續維護成本會低很多。

4. 記錄選擇器失敗。 加上監控,讓你知道的是「何時」某個選擇器失效,而不只是資料變空:

1if title is None:
2    print(f"WARNING: title selector failed for {url}")

5. 使用 curl_cffi 搭配瀏覽器模擬。 這可以在不使用無頭瀏覽器的情況下,處理 Akamai 的 TLS 指紋偵測。

AI 驅動的替代方案:不用再維護選擇器

如果你已經受夠每隔幾個月就要修一次選擇器,那其實還有另一條根本不同的路。像 這類工具會用 AI 每次重新閱讀頁面,並即時推導擷取邏輯。McGill University 的研究測試了 AI 與選擇器式爬蟲在 3,000 個頁面上的表現,結果發現 ,而產業基準也指出可

做法eBay HTML 改版時會壞嗎?維護成本
硬編碼 CSS 選擇器會,每季都可能壞高——需要持續修補
隱藏 JSON / JSON-LD 擷取很少
AI 爬取(Thunderbit)不會——每次執行都重新推導選擇器幾乎不用維護

我稍後會更詳細介紹 Thunderbit 的流程。先記住這個重點:如果你要做的是會跑好幾個月的爬蟲,請優先投資 JSON-first 擷取與備援選擇器;如果你完全不想維護選擇器,那 AI 方案非常值得一看。

如何自動化定期抓取 eBay 進行價格監控

一次性抓取很有用,但價格監控、庫存追蹤與競品分析,都需要週期性資料收集。幾乎每篇競品文章都會提到價格監控,但很少真的教你怎麼自動化。

方案 1:Cron Job(Linux / macOS)或工作排程器(Windows)

最簡單的做法,就是把 Python 腳本包進 cron job。請務必使用 venv 裡 Python 的絕對路徑,因為 cron 的執行環境非常精簡:

1crontab -e
2# 每天早上 08:15 執行
315 8 * * * /Users/me/ebay/venv/bin/python /Users/me/ebay/scrape_ebay.py >> /Users/me/ebay/scrape.log 2>&1

在 Windows 上可以使用 PowerShell:

1$A = New-ScheduledTaskAction -Execute "C:\Users\me\ebay\venv\Scripts\python.exe" -Argument "C:\Users\me\ebay\scrape_ebay.py"
2$T = New-ScheduledTaskTrigger -Daily -At 8:15am
3Register-ScheduledTask -TaskName "eBayScraper" -Action $A -Trigger $T

這種方式需要一台全天開機的機器,而且代理伺服器與反爬策略都得自己管理。

方案 2:雲端函式(Serverless)

AWS Lambda 或 Google Cloud Functions 可以讓你不用專屬伺服器也能跑爬蟲。架設成本較高——你得打包依賴、處理 timeout(Lambda 上限 15 分鐘),而且代理還是要自己管。不過好處是不必維護伺服器。

方案 3:用 Thunderbit 免寫程式排程

的 Scheduled Scraper 功能,讓你可以直接用自然語言描述排程(例如「每天早上 8 點」),輸入 eBay 網址,再按下 Schedule。它會在雲端執行,內建反爬處理。

做法設定成本需要伺服器嗎?能處理反爬嗎?
Cron + Python 腳本中等需要(必須常駐)你自己管理代理
雲端函式(Lambda)不需要(Serverless)你自己管理代理
Thunderbit Scheduled Scraper低(用文字描述即可)不需要(雲端執行)內建

若要保存週期性抓取資料,做價格歷史紀錄時最合適的是本機 SQLite 資料庫。請用 ON CONFLICT ... DO UPDATE,不要用 INSERT OR REPLACE,因為後者會

1CREATE TABLE IF NOT EXISTS listings (
2    item_id       TEXT PRIMARY KEY,
3    title         TEXT NOT NULL,
4    price         REAL,
5    last_price    REAL,
6    first_seen_at TEXT DEFAULT (datetime('now')),
7    last_seen_at  TEXT DEFAULT (datetime('now'))
8);
9CREATE TABLE IF NOT EXISTS price_history (
10    item_id     TEXT NOT NULL,
11    observed_at TEXT NOT NULL DEFAULT (datetime('now')),
12    price       REAL NOT NULL,
13    PRIMARY KEY (item_id, observed_at)
14);

不想寫程式?兩分鐘用 Thunderbit 抓 eBay

前面我花了 2,000 多字講 Python 程式碼。現在我想誠實說說:什麼時候你其實不需要它。

如果你是要做一次性的市場研究、轉售商在比對價格,或是電商團隊今天就要拿到資料、卻沒有開發排程,那 Python 很可能太重了。設定環境、維護選擇器、管理代理——只是為了「我只想把這 200 筆商品放進試算表」的需求,實在有點大材小用。

Thunderbit 如何抓 eBay(步驟說明)

  1. 安裝 —— 不需要信用卡。
  2. 在 Chrome 中開啟任一 eBay 搜尋結果頁或商品頁。
  3. 在 Thunderbit 側邊欄按下「AI Suggest Fields」。AI 會讀取頁面,並建議欄位:標題、價格、商品狀況、運費、賣家、評分。
  4. 按下「Scrape」。 擴充功能會自動處理分頁並填入資料表。針對 eBay,Thunderbit 已經內建 ,一鍵就能用。
  5. 匯出 到 Google Sheets、Airtable、Notion、CSV、JSON 或 Excel——免費。

整個流程不到 2 分鐘。

我有實測過。

子頁面補充:不用額外程式就能拿到詳情頁資料

在抓完搜尋結果頁後,Thunderbit 可以自動前往每個商品的詳情頁,並附加更多欄位——完整規格、賣家資訊、描述、所有圖片。這等於把前面我們寫的 20 多行 Python 子頁面抓取程式,濃縮成一次點擊。

什麼情況下還是該用 Python?

以下情況 Python 仍然有優勢:

  • 大規模爬取(每次執行數萬頁)
  • 高度客製化的解析邏輯或資料轉換
  • 整合到既有資料流程(Airflow、dbt、Kafka)
  • 需要細緻的 TLS / session 控制,做進階反爬處理
  • 單位經濟效益——當規模到數百萬筆時,維護好的自建架構會比點數型 SaaS 更划算

對大多數一次性或中等規模專案來說,Thunderbit 速度更快、也更簡單。若是大規模正式資料管線,Python 則能讓你完全掌控流程。

用 Python 抓 eBay 時,怎麼避免被封鎖?

eBay 的 Akamai 層不是假的。實務上真正有效的方法如下:

  • 使用 curl_cffi 並設定 impersonate="chrome124"——這是比單純 requests 最大的提升
  • 輪換 User-Agent,從目前常見的瀏覽器版本清單中切換(Chrome 143、Firefox 124、Safari 26)
  • 加入隨機延遲,每次請求間隔 ——固定間隔本身就會暴露特徵
  • 當抓取量超過幾十頁時,使用住宅代理或輪替代理。資料中心 IP(AWS、GCP、DigitalOcean)很快就會被 Akamai 標記。
  • 遵守 robots.txt——多數受限的瀏覽網址都明確標示為 Disallowed;商品詳情頁(/itm/<id>)通常不是
  • 妥善處理 CAPTCHA——偵測到後改用不同 IP 重試,或使用 CAPTCHA 解題服務
  • 不要狂打伺服器。 這個先例顯示,當爬蟲真的拖慢伺服器效能時,侵害動產的法律風險就會浮現。把每個 IP 控制在每秒 1 次請求,基本上就遠低於那條線。

若是高流量商業用途,建議把 Browse API 用在在售商品上,再針對已售比較資料和 API 沒有的欄位做定向爬取。這種混合策略,在技術和法律上都更乾淨。

用 Python 爬 eBay 合法嗎?

我不是律師,這篇文章也不是法律建議,所以我只簡短說明。

法律環境近年來對抓取公開資料越來越有利。幾個重要判例包括:

  • (第九巡迴上訴法院,2022):抓取公開可存取資料不違反 CFAA
  • Van Buren v. United States(美國最高法院,2021):限縮 CFAA 中「超出授權存取」的適用範圍
  • (加州北區地院,2024):未登入狀態下的抓取不構成違反平台服務條款,因為爬蟲不是「使用者」

不過,eBay 在 中,明確禁止「代買代理、LLM 驅動的 bot,或任何試圖在沒有人工審查下完成下單的端到端流程」。界線其實很清楚:只讀式抓取公開頁面,法律基礎相對穩;自動化結帳則不行。

最佳做法是:只抓公開可見的資料,不要建立假帳號,也不要繞過登入牆,不要批量轉售受版權保護的商品圖片。若是商業規模專案,請諮詢法律顧問。

結論與重點整理

Python 是抓 eBay 最靈活的方法,但也需要隨著網站 HTML 的變動持續維護。判斷方式如下:

  • 用 eBay Browse API:適合在售商品的穩定、中等量、結構化查詢
  • 用 Python 爬蟲:適合已售商品、評價、變體資料,以及 API 沒有公開的欄位
  • :如果你想要 eBay 資料,但不想寫或維護程式

本指南的程式碼把耐用性放在第一位:先抓 JSON-LD,再用 CSS 備援,變體則從隱藏 JSON 解析。這種分層做法,可以讓你的爬蟲在 eBay 前端團隊下次改版時,不至於立刻陣亡。

如果你想試試免寫程式的方式, 現在就能讓你在 eBay 頁面上實測。若你想看看 怎麼運作,點一下就行。

想了解更多網頁爬蟲工具,可以參考我們的指南:。你也可以在 看教學影片。

試試 Thunderbit 來抓 eBay

常見問題

1. 可以免費用 Python 抓 eBay 嗎?

可以。所有函式庫(Requests、BeautifulSoup、curl_cffi、pandas)都是免費且開源的。成本會出現在規模化之後——若要大量抓取,住宅代理通常每月約 50–500 美元,視流量而定。若是小型專案(幾百頁),只要妥善控制頻率,用家用 IP 也能抓。

2. 要怎麼用 Python 抓 eBay 已售出商品與已完成商品?

在搜尋網址參數加入 LH_Complete=1&LH_Sold=1。兩個都要加——只加 LH_Sold=1 在某些類別中會悄悄退回在售商品。接著檢查價格元素是否帶有 .POSITIVE CSS class,這代表真實成交,而不是未售出的過期刊登。

3. eBay 會擋網頁爬蟲嗎?

eBay 使用 Akamai Bot Manager,主要透過 TLS 指紋與行為分析偵測爬蟲。單純的 requests 常常會拿到 403。使用 curl_cffi 搭配瀏覽器模擬、輪換 User-Agent、以及每次請求間加入 3–8 秒隨機延遲,通常能處理大多數封鎖情況。規模大時,住宅代理會有幫助。

4. 我應該用 eBay API 還是網頁爬蟲?

如果你要的是在售商品的穩定、中等量查詢(每天最多 5,000 次呼叫),請用 Browse API。若你需要已售價格歷史、完整變體 / MSKU 資料、評價,或 API 沒有公開的欄位,就用爬蟲。Marketplace Insights API 理論上有已售資料,但權限受限,而且

5. 不寫程式,最簡單的 eBay 抓取方式是什麼?

會用 AI 讀取 eBay 頁面、建議資料欄位,並一鍵擷取商品資料。它能處理分頁、子頁面補充,還能匯出到 Google Sheets、Excel、Airtable 或 Notion。預先建立好的 讓常見情境更快上手。

延伸閱讀

Ke
Ke
CTO @ Thunderbit. Ke is the person everyone pings when data gets messy. He's spent his career turning tedious, repetitive work into quiet little automations that just run. If you've ever wished a spreadsheet could fill itself in, Ke has probably already built the thing that does it.
目錄

試試 Thunderbit

只要 2 次點擊,就能抓取潛在客戶與其他資料。AI 驅動。

取得 Thunderbit 免費使用
用 AI 擷取資料
輕鬆將資料轉移到 Google Sheets、Airtable 或 Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week