Target.com 是那種看起來很簡單、實際上卻不太好抓的網站。您如果曾經寫過一個用 Requests 和 BeautifulSoup 的 Python 小腳本,丟到 Target 的商品頁,結果價格欄位回傳 None,其實一點也不孤單。
我測試過多數大型零售網站的抓取方式,可以很肯定地說:Target 一直都屬於最棘手的那一類。它每月有 ,商品資料像是價格、評分、庫存、評論都很有價值,但 Target 結合了 React 的前端渲染與 Akamai 的機器人偵測,讓天真的抓取方法幾乎一開始就失敗。不過,確實有三種 Python 方法真正可行。我會逐一說明,解釋為什麼第一種嘗試通常會失敗,並示範一個不用寫程式的替代方案,讓您在 Python 不值得折騰時也有退路。
為什麼您第一次用 Python 抓 Target.com 會回傳 None
先別急著想解法,先看問題出在哪。這是多數初學者會寫的程式:
1import requests
2from bs4 import BeautifulSoup
3url = "https://www.target.com/p/some-product/-/A-12345678"
4response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
5soup = BeautifulSoup(response.text, "html.parser")
6price = soup.select_one('[data-test="current-price"]')
7print(price) # None
輸出是什麼?None。每次都一樣。
這不是您程式的錯。requests.get() 從 Target 拿回來的 HTML 幾乎只是個骨架——一個 React 外殼,意思是「嘿,載入這段 JavaScript 來渲染真正的頁面吧」。商品價格、評分、評論與可用性,都是在初始頁面載入之後才由 JavaScript 注入。因為 Python 的 Requests 不會執行 JavaScript,所以那些元素根本不會出現在回應裡。
論壇上到處都是撞上這堵牆的開發者。某篇 說得很直接:「元素會顯示為 None,是因為它是由 Javascript 渲染,而 requests 無法抓取由 Javascript 渲染的 HTML。」也證實:「當您向 Target URL 發送 HTTP 請求時,HTML 回應中沒有什麼有用的資料。」
而且就算您解決了 JavaScript 問題,還有第二層:Target 的 Akamai 機器人偵測會先對您的 TLS 握手做指紋辨識,在傳送任何一個 HTML 位元組之前,就先把 Python 的 requests 庫標記出來。這點我等一下會再講。
為什麼 Target.com 這麼難用 Python 抓
Target 不只是「一個用了 JavaScript 的網站」。它其實是一套分層防禦系統——了解每一層,才能選對抓取方法。
JavaScript 渲染的商品資料
Target.com 是用 React 建置的。當您在真正的瀏覽器裡打開商品頁或搜尋頁時,流程是這樣:
- 伺服器送出最小化的 HTML 骨架
- JavaScript bundle 載入並執行
- 前端呼叫 Target 內部的 Redsky API
- 商品資料(價格、評分、圖片、可用性)渲染進 DOM
如果您跳過第 2 到第 4 步——也就是 requests.get() 做的事——您拿到的就只是一個空頁面。,靜態 HTTP 請求在 Target 上大約只能抓到 的可用資料。其餘 70% 需要 JavaScript 執行或 API 存取。
搜尋結果頁更糟。初始 HTML 只會出現少數幾個商品;其餘商品得等您往下捲動才會載入。
Target 的反機器人防禦:不只是泛泛地說「用代理」
多數抓取教學對反機器人措施都只會輕描淡寫地說「用代理就好」。但 Target 的防線其實更值得細講。
TLS 指紋辨識(最關鍵的一層)。 在 HTTPS 握手期間,您的客戶端會送出一個「Client Hello」封包,裡面會暴露您的 TLS 版本、cipher suites、擴充套件與橢圓曲線。這些資訊會被雜湊成一個 JA3 指紋。Python 的 requests 會產生一個 ——8d9f7747675e24454cd9b7ed35c58707——反機器人資料庫會立刻標記它。Chrome 會送出 16 個經過仔細排序、包含 GREASE 值的 cipher suites;Python 則會以非瀏覽器順序送出 60 多個。封鎖會在任何 HTTP 內容交換之前就發生。
IP 信譽評分。 Akamai 會把 IP 分到不同信任等級。資料中心 IP 在 裡會得到「顯著的負面信任分數,因為它們很可能被機器人使用」。住宅 IP 則會得到正面分數。以 Target 來說,資料中心 IP 範圍幾乎會立刻被標記。
JavaScript 指紋辨識。 Akamai 會注入 JavaScript,收集您的 JS 引擎規格、硬體能力、作業系統資料、字型、外掛程式與行為資料(打字速度、滑鼠移動、點擊時間)。這會生成 _abck cookie——一種有狀態的指紋權杖。沒有有效的 _abck,請求就會被封鎖。
速率限制。 Target 大約每個 IP 每分鐘觸發 30 到 60 次請求時就會出現 429 錯誤。有些使用者回報會收到,但實際內容是「Pardon Our Interruption」封鎖頁,這讓自動化偵測更棘手。
整體來看,。而 Akamai 繞過部分則被評為 。
用 Python 抓 Target.com 的 3 種方法(並排比較)
外面沒有一篇文章會把這三種可行方法完整放在一起比較。下面我直接整理給您:
| 比較項目 | Requests + BS4 | Selenium / Playwright | Redsky API |
|---|---|---|---|
| 支援 JS 渲染 | ❌ 否 | ✅ 是 | ✅ 是(JSON) |
| 每筆速度 | ⚡ 約 0.5–1 秒 | 🐢 約 5–10 秒 | ⚡ 約 0.5–1 秒 |
| 反機器人風險 | ⚠️ 高(TLS 指紋) | ⚠️ 中 | ⚠️ 中(驗證金鑰可能變動) |
| 設定複雜度 | 低 | 中 | 中高(逆向工程) |
| 資料完整度 | 約 30%(僅靜態 HTML) | 約 95%(整頁) | 約 90%(結構化 JSON) |
| 最適合用途 | 靜態中繼資料、__TGT_DATA__ | 完整商品頁、評論 | 大量商品資料擷取 |
接下來我們一種一種來做。
方法 1:用 Python Requests 和 BeautifulSoup 抓 Target.com
這個方法抓不到搜尋頁上由 JavaScript 渲染的價格。不過它速度快、很輕量,而且如果您知道該看哪裡,其實能抓到比您想像更多的資料。
關鍵在於:Target 會在 <script> 標籤裡嵌入一部分商品資料,裡面有個 __TGT_DATA__ 變數,含有 __PRELOADED_QUERIES__。這個 JSON 區塊會包含商品名稱、描述、特色,有時候甚至會在單一商品頁中包含價格。您也可以從搜尋結果 HTML 中擷取商品標題與 URL。
步驟 1:設定 Python 環境
建立專案資料夾並安裝相依套件:
1mkdir target-scraper && cd target-scraper
2python -m venv venv
3source venv/bin/activate # Windows 上:venv\Scripts\activate
4pip install requests beautifulsoup4 curl_cffi
這裡建議用 curl_cffi 取代標準 requests。它會偽裝瀏覽器的 TLS 指紋,這是避免被 Target 擋下來最重要的一步。 curl_cffi 的反機器人繞過成功率有 ,而標準 requests 只有 ——大約提升 15 倍。
步驟 2:抓取 Target 搜尋結果
Target 的搜尋 URL 格式很直接:https://www.target.com/s?searchTerm=\{keyword\}
1from curl_cffi import requests as cureq
2from bs4 import BeautifulSoup
3import time, random
4headers = {
5 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
6 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
7 "Accept-Language": "en-US,en;q=0.9",
8}
9url = "https://www.target.com/s?searchTerm=bluetooth+headphones"
10resp = cureq.get(url, headers=headers, impersonate="chrome124")
11soup = BeautifulSoup(resp.text, "html.parser")
12# 商品卡片使用這個 data-test 屬性
13cards = soup.find_all("div", {"data-test": "@web/site-top-of-funnel/ProductCardWrapper"})
14for card in cards:
15 link_tag = card.find("a")
16 title = link_tag.get_text(strip=True) if link_tag else "N/A"
17 href = "https://www.target.com" + link_tag["href"] if link_tag and link_tag.get("href") else "N/A"
18 print(f"\{title\} — \{href\}")
您會拿到商品名稱和 URL。價格呢?多半不會出現在這份 HTML 裡。這很正常。
步驟 3:從商品頁擷取嵌入的 JSON 資料
單一商品頁會把更豐富的資料嵌在 __TGT_DATA__ script tag 裡:
1import re, json
2product_url = "https://www.target.com/p/some-product/-/A-12345678"
3resp = cureq.get(product_url, headers=headers, impersonate="chrome124")
4soup = BeautifulSoup(resp.text, "html.parser")
5# 找出 __TGT_DATA__ script
6scripts = soup.find_all("script")
7for script in scripts:
8 if script.string and "__TGT_DATA__" in script.string:
9 # 從 script 內容中擷取 JSON
10 match = re.search(r'__TGT_DATA__\s*=\s*({.*?});?\s*$', script.string, re.DOTALL)
11 if match:
12 tgt_data = json.loads(match.group(1))
13 # 導向 JSON 結構找商品細節
14 queries = tgt_data.get("__PRELOADED_QUERIES__", {})
15 # 商品資料被巢狀包在裡面——實際結構會因頁面而異
16 print(json.dumps(queries, indent=2)[:500]) # 預覽結構
__TGT_DATA__ 裡的 JSON 結構包含商品名稱、描述、特色,以及常常會有價格資料。實際巢狀層級會變動,所以您需要先看輸出,再決定怎麼走。
步驟 4:處理分頁
Target 的搜尋分頁使用 Nao 參數。第 1 頁是 Nao=0,第 2 頁是 Nao=24,第 3 頁是 Nao=48,以此類推(每次加 24):
1for page in range(0, 120, 24): # 前 5 頁
2 paginated_url = f"https://www.target.com/s?searchTerm=bluetooth+headphones&Nao=\{page\}"
3 resp = cureq.get(paginated_url, headers=headers, impersonate="chrome124")
4 # 解析與擷取...
5 time.sleep(random.uniform(2, 5)) # 禮貌一點
步驟 5:儲存抓到的資料
1import csv
2with open("target_products.csv", "w", newline="", encoding="utf-8") as f:
3 writer = csv.DictWriter(f, fieldnames=["title", "url", "price", "description"])
4 writer.writeheader()
5 for product in products:
6 writer.writerow(product)
您能拿到什麼: 商品標題、URL、描述與嵌入式中繼資料。您不容易穩定拿到什麼: 搜尋結果頁的動態價格和評分。這些通常要靠方法 2 或 3。
方法 2:用 Selenium 或 Playwright 抓 Target.com
無頭瀏覽器會渲染 JavaScript、載入動態內容,並模擬真實使用者行為。這就是能抓到價格、評分與評論的方法。
關於 Selenium 和 Playwright 的選擇:——2026 年是 ——而且基準測試顯示它還 (20 頁 11 秒對 28 秒)。我這裡會示範 Selenium,因為它社群更大、教學更多;但如果您是從零開始,Playwright 其實是更好的選擇。
步驟 1:安裝 Selenium 與 ChromeDriver
1pip install selenium webdriver-manager
webdriver-manager 會自動處理 ChromeDriver 版本,從此不用再煩惱「ChromeDriver 版本不相符」:
1from selenium import webdriver
2from selenium.webdriver.chrome.service import Service
3from selenium.webdriver.chrome.options import Options
4from webdriver_manager.chrome import ChromeDriverManager
5options = Options()
6options.add_argument("--headless=new")
7options.add_argument("--window-size=1920,1080")
8options.add_argument("--disable-blink-features=AutomationControlled")
9options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
10driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
步驟 2:載入 Target 頁面並等待內容出現
1from selenium.webdriver.common.by import By
2from selenium.webdriver.support.ui import WebDriverWait
3from selenium.webdriver.support import expected_conditions as EC
4driver.get("https://www.target.com/s?searchTerm=bluetooth+headphones")
5# 等待商品卡片渲染完成(顯式等待 > time.sleep)
6WebDriverWait(driver, 15).until(
7 EC.presence_of_element_located((By.CSS_SELECTOR, '[data-test="product-title"]'))
8)
顯式等待很重要。time.sleep(10) 對載入快的頁面是在浪費時間,對載入慢的頁面又不夠久——兩頭都吃虧。WebDriverWait 會每 500 毫秒輪詢一次,直到元素出現或逾時。
步驟 3:捲動頁面以載入全部商品
Target 會隨著您捲動才懶載入商品。不捲動的話,您可能只會看到 4 到 5 個商品,而不是整頁:
1import time
2last_height = driver.execute_script("return document.body.scrollHeight")
3for _ in range(10):
4 driver.execute_script("window.scrollBy(0, 300);")
5 time.sleep(1.5)
6 new_height = driver.execute_script("return document.body.scrollHeight")
7 if new_height == last_height:
8 break
9 last_height = new_height
,10 次捲動、每次延遲 1.5 秒,可抓到 8 個以上商品;不捲動則只有 4 到 5 個。每次捲動建議 200 到 300px,比較像真人行為。
步驟 4:從渲染後的頁面擷取商品資料
1products = []
2cards = driver.find_elements(By.CSS_SELECTOR, '[data-test="@web/site-top-of-funnel/ProductCardWrapper"]')
3for card in cards:
4 try:
5 title = card.find_element(By.CSS_SELECTOR, '[data-test="product-title"]').text
6 except:
7 title = "N/A"
8 try:
9 price = card.find_element(By.CSS_SELECTOR, '[data-test="current-price"]').text
10 except:
11 price = "N/A"
12 try:
13 link = card.find_element(By.CSS_SELECTOR, 'a[href*="/p/"]').get_attribute("href")
14 except:
15 link = "N/A"
16 products.append({"title": title, "price": price, "link": link})
17for p in products:
18 print(f'{p["title"]} — {p["price"]}')
Target 可用的關鍵 data-test 選擇器(2026 年驗證):
| 資料欄位 | 選擇器 |
|---|---|
| 商品卡片 | data-test="@web/site-top-of-funnel/ProductCardWrapper" |
| 商品標題 | data-test="product-title" |
| 目前價格 | data-test="current-price" |
| 評分值 | data-test="rating-value" |
| 評分數量 | data-test="rating-count" |
步驟 5:抓取商品評論(加分項)
前往單一商品頁,捲動到評論區,然後擷取評論資料:
1from bs4 import BeautifulSoup
2driver.get("https://www.target.com/p/some-product/-/A-12345678")
3# 往下捲動以載入評論
4for _ in range(5):
5 driver.execute_script("window.scrollBy(0, 500);")
6 time.sleep(2)
7soup = BeautifulSoup(driver.page_source, "html.parser")
8reviews = soup.find_all("div", {"data-test": "review-card--text"})
9for review in reviews:
10 print(review.get_text(strip=True)[:100])
評論透過 Bazaarvoice 整合載入,支援分頁(最多 51 頁)、依最近排序,以及只看圖片的篩選。 顯示,Selenium 每筆大約要 5.1 秒。
做完記得關閉瀏覽器:
1driver.quit()
方法 3:用 Redsky API 抓 Target.com
Target 前端會從 redsky.target.com 這個內部 API 抓取所有資料。您可以直接用 Python 呼叫它——不用解析 HTML、不用瀏覽器、不用 JavaScript 渲染。回傳的是乾淨的 JSON,裡面有 40 多個資料欄位,涵蓋價格、評分、評論、圖片、可用性、履約、規格與變體。若是大量商品資料,這是最快也最可靠的方法,差距非常明顯。
步驟 1:用 Chrome DevTools 找出 Redsky API
多數教學會直接跳過這步,但其實您自己也能找到 API:
- 用 Chrome 打開任一 Target 商品頁
- 開啟 DevTools(F12)→ Network 分頁
- 用 Fetch/XHR 篩選
- 重新整理頁面
- 找到對
redsky.target.com或redsky.a]target.com的請求 - 點進去看 Request URL 與 Headers
您會看到類似這樣的網址:
1https://redsky.target.com/redsky_aggregations/v1/web/pdp_fulfillment_v1?key=9f36aeafbe60771e321a7cc95a78140772ab3e96&tcin=12345678&store_id=2148&zip=55401
關鍵參數:
key— API 金鑰(固定,不會輪替——不同端點會用不同的 key)tcin— Target.com Item Number(8 位數商品 ID)store_id— Target 門市代碼zip— 用於履約資料的郵遞區號
把 API key 從 request headers 裡擷取出來。它其實已經作為 query parameter 寫在網址中了。
步驟 2:直接用 Python 呼叫 Redsky API
1from curl_cffi import requests as cureq
2import json
3API_KEY = "9f36aeafbe60771e321a7cc95a78140772ab3e96" # 從 DevTools 擷取
4TCIN = "12345678"
5url = f"https://redsky.target.com/redsky_aggregations/v1/web/pdp_fulfillment_v1?key=\{API_KEY\}&tcin=\{TCIN\}&store_id=2148&zip=55401"
6headers = {
7 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
8 "Accept": "application/json",
9 "Origin": "https://www.target.com",
10 "Referer": "https://www.target.com/",
11 "Sec-Fetch-Site": "same-site",
12 "Sec-Fetch-Mode": "cors",
13 "Sec-Fetch-Dest": "empty",
14}
15resp = cureq.get(url, headers=headers, impersonate="chrome124")
16data = resp.json()
17# 從 JSON 回應擷取商品資料
18product = data.get("data", {}).get("product", {})
19title = product.get("item", {}).get("product_description", {}).get("title", "N/A")
20price = product.get("price", {}).get("formatted_current_price", "N/A")
21rating = product.get("ratings_and_reviews", {}).get("statistics", {}).get("rating", {}).get("average", "N/A")
22print(f"\{title\} — \{price\} — 評分:\{rating\}")
不用解析 HTML。回應結構清楚、乾淨又快速。
步驟 3:透過 API 抓取商品搜尋結果
product_summary_with_fulfillment_v1 端點一次可以接受多個 TCIN:
1tcins = ["12345678", "23456789", "34567890"]
2tcin_str = ",".join(tcins)
3search_url = f"https://redsky.target.com/redsky_aggregations/v1/web/product_summary_with_fulfillment_v1?key=\{API_KEY\}&tcins=\{tcin_str\}&store_id=2148&zip=55401"
4resp = cureq.get(search_url, headers=headers, impersonate="chrome124")
5results = resp.json()
6for item in results.get("data", {}).get("product_summaries", []):
7 title = item.get("title", "N/A")
8 price = item.get("price", {}).get("formatted_current_price", "N/A")
9 print(f"\{title\} — \{price\}")
要取得 TCIN,可以從搜尋頁 HTML 中擷取(商品 URL 會顯示成 /A-XXXXXXXX),或者從內嵌的 __TGT_DATA__ JSON 裡拿。
步驟 4:用並行請求擴大規模
1from concurrent.futures import ThreadPoolExecutor
2import time, random
3def fetch_product(tcin):
4 url = f"https://redsky.target.com/redsky_aggregations/v1/web/pdp_fulfillment_v1?key=\{API_KEY\}&tcin=\{tcin\}&store_id=2148&zip=55401"
5 time.sleep(random.uniform(2, 5))
6 resp = cureq.get(url, headers=headers, impersonate="chrome124")
7 return resp.json()
8tcin_list = ["12345678", "23456789", "34567890", "45678901"]
9with ThreadPoolExecutor(max_workers=3) as executor:
10 results = list(executor.map(fetch_product, tcin_list))
並行數量要保守——3 到 5 個執行緒,外加 2 到 5 秒的隨機延遲。Target 的速率限制大約是每個 IP 。
關於 Redsky API 的重要注意事項
在您把這個做成正式生產管線之前,先留意幾件事:
- API key 雖然固定,但只對特定端點有效。 不同 Redsky 端點會使用不同的 key。它們不常輪替,但 Target 隨時可能改。
- 這是未公開文件的內部 API。 Target 的工程團隊已經,這降低了法律風險,但它並不是有 SLA 的官方公開 API。
- 商品變體(顏色、尺寸)各自有獨立的 TCIN。 您需要逐一查詢每個變體。
- 少了
Sec-Fetch-*headers 會立刻被擋。 這是常見陷阱——務必包含Sec-Fetch-Site、Sec-Fetch-Mode和Sec-Fetch-Dest。
如何在大規模抓取 Target.com 時避免被封鎖
以下做法適用於正式規模,不論您用哪一種方法。
使用住宅代理輪換,不要用資料中心代理
Target 的 Akamai 會一眼認出資料中心 IP 範圍。要長期抓取,住宅代理幾乎是必需品。價格差異很大——,,大量使用時可降到每 GB 3 到 4 美元。
每 50 到 100 次請求輪換一次 IP;如果您的代理池支援,也可以每次請求都換。
用 curl_cffi 偽裝 TLS 指紋
這是您能做的、影響最大的單一改動。直接替換 requests:
1from curl_cffi import requests as cureq
2# 標準 requests —— 在受保護網站上的成功率約 12%
3# resp = requests.get(url, headers=headers)
4# curl_cffi —— 成功率約 92%
5resp = cureq.get(url, headers=headers, impersonate="chrome124")
(GitHub 8,200+ 星)支援從 chrome99 到 chrome146 的 Chrome 版本,也支援 Safari、Edge 與行動裝置變體。在同步模式下,它比 tls_client 。
設定合理的請求節奏與標頭
- 隨機延遲: 每次請求間隔 2 到 7 秒(不要固定間隔——隨機性很重要)
- User-Agent 輪換: 維護 5 到 10 組真實瀏覽器 User-Agent 字串並輪替使用
- Session 預熱: 先拜訪
target.com首頁,再進入商品頁,以建立 cookie - 標頭一致性: 您的
Sec-Ch-Ua必須和您聲稱的瀏覽器版本一致。Sec-Ch-Ua-Platform也必須和您聲稱的作業系統一致。不一致很容易被看穿。 - Session 持續性: 在同一個 session 裡保留 cookies。搭配輪換住宅代理,維持 48 小時的 session 穩定度。
不想寫程式?用 Thunderbit 抓 Target.com(無程式碼替代方案)
說真的,Target.com 是程式化抓取零售網站中比較難的一種。JavaScript 渲染、Akamai 的 TLS 指紋辨識、資料中心代理偵測、ChromeDriver 版本問題——每一項都會卡您。如果您是在學 Python,這很適合作為練習;但如果您是為了實際工作要拿到 Target 商品資料,投入產出常常不划算。
如果您想直接拿到資料、不想碰工程細節, 會自動處理最難的部分。
Thunderbit 如何處理 Target.com 的難題
Thunderbit 的人工智慧網頁爬蟲是在瀏覽器中執行,這代表它會自然渲染 JavaScript——不用裝 Selenium,不用設定無頭瀏覽器,也不用管 ChromeDriver 版本。瀏覽器本身就是爬蟲。
流程如下:
- 安裝 並前往 Target 的商品頁或搜尋頁
- 點擊「AI Suggest Fields」——Thunderbit 會讀取頁面並提出欄位名稱建議(商品標題、價格、評分、圖片 URL 等)
- 點擊「Scrape」——資料會在幾秒內直接從渲染後的頁面擷取出來
不用設定代理。不用偽裝 TLS 指紋。不會再看到 None。
抓取 Target 商品列表與詳細頁
多頁工作流程最有意思。您可以先抓 Target 搜尋結果頁拿到商品清單,再用 子頁面抓取 自動逐一拜訪每個商品 URL,並把詳細頁資料豐富到表格中——像是描述、完整評論、規格等,不必自己寫分頁程式,也不用管理瀏覽器 session。
可以直接匯出到 Excel、Google Sheets、Airtable 或 Notion。沒有 csv.writer 的樣板程式,也沒有檔案編碼問題。
自動化重複性的 Target.com 抓取
如果您要持續監控價格或追蹤庫存,Thunderbit 的 排程爬蟲 可以讓您用自然語言描述排程(例如「每週一上午 9 點」)。不用 cron job、不用架伺服器、不用在 VPS 上維持 Python 腳本一直跑。這對追蹤的電商團隊特別有用——現在都在使用自動化價格抓取,而價格情報的平均投資報酬率高達 。
用 Python 抓 Target.com 時,什麼情況該用哪一種方法
給您一個快速決策框架:
| 你的情況 | 建議方法 |
|---|---|
| 在學 Python、小型專案 | 方法 1:Requests + BS4(靜態資料與 __TGT_DATA__) |
| 需要完整商品頁,包含價格與評論 | 方法 2:Selenium / Playwright |
| 大量擷取商品資料 | 方法 3:Redsky API |
| 需要快速拿資料,不想寫程式 | Thunderbit(無程式碼) |
| 需要持續監控價格 | Thunderbit 排程爬蟲或 Redsky API + cron |
| 一次性的研究專案,團隊非技術背景 | Thunderbit——老實說是最快的路徑 |
如果您是在打造正式的資料管線,方法 3(Redsky API)在速度和穩定性上表現最好。如果您只是做一次性研究,或團隊沒有 Python 能力,Thunderbit 可以幫您省下好幾個小時。如果您是在學網頁抓取,方法 1 → 方法 2 → 方法 3 是很自然的學習路線,而且每一步都能學到真正有用的東西。
抓取 Target.com 的法律與倫理考量
這部分值得簡短說明。Target 的 robots.txt 大約有 120 多條 Disallow 路徑,但明顯沒有封鎖 /p/(商品)或 /c/(分類)——商品頁與分類頁都明確允許爬取。購物車、帳號與結帳頁則是受限制的。
Target 的服務條款確實禁止自動化存取。不過,Redsky API 被(Target 工程團隊已確認),這會降低以 API 為基礎進行資料收集的法律風險。
您應該知道的主要法律判例:
- (第九巡迴法院,2022):抓取公開可得資料不違反 CFAA
- (2024):Meta 敗訴——法院認定抓取公開資料不構成 CFAA 違反
如果是大規模商業抓取,請諮詢法律顧問。若是市場研究、價格比較或個人專案,且使用的是公開資料,基本上站得住腳。務必尊重速率限制,不要讓 Target 的伺服器負載過高。
結論與重點整理
Target.com 的難度名符其實。天真的 Requests + BeautifulSoup 做法會失敗,是因為 Target 透過 JavaScript 渲染商品資料,而且 Akamai 甚至會在您拿到回應前就先對 TLS 握手做指紋辨識。不過,選對方法後,抓取其實並不複雜。
三種方法的可靠度排名:
- Redsky API —— 速度最快、最適合大量資料、回傳乾淨 JSON。需要先用 DevTools 逆向找出 API 端點。
- Selenium / Playwright —— 能處理 JavaScript 渲染,可以拿到頁面上的所有內容。速度較慢,但資料完整。
- Requests + BeautifulSoup —— 只適用於靜態 HTML 與嵌入的
__TGT_DATA__JSON。速度快,但不完整。
最大的技術重點:
- 用
curl_cffi取代標準requests,反機器人繞過能力可提升 - 住宅代理是必要條件——資料中心 IP 會立刻被標記
- 每次請求都加入
Sec-Fetch-*headers——少了會立刻被擋 - session 預熱(先拜訪首頁)會明顯提高成功率
如果對您的用途來說,Python 抓取太麻煩,會自動處理 JavaScript 渲染、反機器人措施與資料匯出。試試看,看看能不能在幾分鐘內而不是幾小時內拿到您要的資料。
想看更多抓取教學和資料擷取技巧,可以參考 或我們的 。
常見問題
我可以只用 Python Requests 和 BeautifulSoup 抓 Target.com 嗎?
部分可以。您可以從商品頁的 __TGT_DATA__ script tag 擷取商品標題、URL 和一些嵌入式 JSON 資料。但搜尋結果頁上的價格、評分、評論與可用性都是 JavaScript 渲染的,靜態 HTTP 請求看不到。要拿完整資料,請用 Selenium/Playwright 或 Redsky API。
為什麼我的 Target.com 爬蟲價格欄位會回傳 None?
Target 會在初始頁面載入後再用 JavaScript 載入價格資料。當您使用 requests.get() 時,拿到的是尚未渲染完成的 HTML 骨架——也就是 JavaScript 執行、把商品資料注入 DOM 之前的版本。價格元素在回應裡根本不存在。請改用能渲染 JavaScript 的無頭瀏覽器(Selenium 或 Playwright)、直接呼叫 Redsky API 取得 JSON,或者使用像 這類會從渲染後瀏覽器頁面擷取資料的工具。
抓取 Target.com 合法嗎?
依照目前美國的判例,抓取公開可得資料通常是被允許的(hiQ v. LinkedIn、Meta v. Bright Data)。Target 的 robots.txt 也允許商品頁與分類頁被爬取。不過,Target 的服務條款禁止自動化存取,所以仍有灰色地帶。若是用公開資料做市場研究或價格比較,法律上通常較站得住腳;若是大規模商業運作,請諮詢律師。
Target 的 Redsky API 是什麼?我要怎麼存取?
Redsky 是 Target 的內部 API,負責前端商品資料。它不是那種您註冊帳號、拿 API 文件與 API key 的公開 API;它是 React 應用在渲染商品頁時所呼叫的後端。您可以打開 Chrome DevTools,切到 Network 分頁並用 XHR/Fetch 篩選,找出對 redsky.target.com 的請求來發現端點。API key 會以 query parameter 的形式嵌在 request URL 中。Target 工程團隊已確認這個 API 是刻意對外可見的。
我要怎麼避免在抓 Target.com 時被封鎖?
最有影響的一個改動,就是用 curl_cffi 取代標準 Python requests,偽裝瀏覽器的 TLS 指紋——單這一步就能把成功率從 。除此之外:使用住宅代理(不要用資料中心)、輪換 User-Agent 字串、每次請求之間加入 2 到 7 秒隨機延遲、加入所有 Sec-Fetch-* headers,並先拜訪首頁做 session 預熱。或者,直接用像 這樣會自動處理反機器人措施的工具,完全不用設定。
延伸閱讀