Thu thập Target.com bằng Python năm 2026: 3 cách thực sự hiệu quả

Cập nhật lần cuối vào April 28, 2026
Thu thập Target.com bằng Python năm 2026: 3 cách thực sự hiệu quả

Target.com là một trong những website nhìn qua thì tưởng dễ thu thập dữ liệu — cho đến khi bạn bắt tay vào làm thật. Nếu bạn từng viết vội một script Python bằng Requests và BeautifulSoup, ném nó vào một trang sản phẩm của Target rồi thấy trường giá trả về None, thì bạn không hề đơn độc.

Sau khi thử nhiều cách thu thập dữ liệu trên hầu hết các website bán lẻ lớn, tôi có thể nói thẳng: Target luôn nằm trong nhóm khó nhất. Với 208–280 triệu lượt truy cập mỗi tháng, đây là một mỏ vàng dữ liệu sản phẩm — giá, xếp hạng, tồn kho, đánh giá — nhưng sự kết hợp giữa render phía client bằng React và cơ chế phát hiện bot của Akamai khiến những cách làm ngây thơ gần như thất bại ngay từ đầu. Dù vậy, vẫn có 3 cách Python thực sự hoạt động. Tôi sẽ lần lượt đi qua từng cách, giải thích vì sao lần thử đầu tiên thường hỏng, và chỉ cho bạn một lối tắt không cần code khi Python không đáng để bạn phải đau đầu.

Vì sao lần crawl Target.com đầu tiên bằng Python lại trả về None

Trước khi nói đến giải pháp, hãy nhìn vào vấn đề trước đã. Đây là đoạn code mà đa số người mới thường viết:

import requests
from bs4 import BeautifulSoup

url = "https://www.target.com/p/some-product/-/A-12345678"
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
soup = BeautifulSoup(response.text, "html.parser")

price = soup.select_one('[data-test="current-price"]')
print(price)  # None

Kết quả là gì? None. Lúc nào cũng vậy.

Đây không phải lỗi trong code của bạn. HTML mà requests.get() trả về từ Target về cơ bản chỉ là một bộ khung rỗng — một lớp vỏ React kiểu như “này, hãy tải JavaScript này để render trang thật”. Giá sản phẩm, xếp hạng, đánh giá và tình trạng còn hàng đều được JavaScript chèn vào sau lần tải trang đầu tiên. Vì thư viện Requests của Python không thực thi JavaScript, nên những phần tử đó đơn giản là không tồn tại trong response.

Các diễn đàn đầy rẫy developer gặp đúng bức tường này. Một bài phân tích của ScrapeOps nói thẳng: “Một phần tử hiện ra là None vì nó được render bằng Javascript và requests không thể lấy HTML đã được render bằng Javascript.” Một hướng dẫn của Crawlbase cũng xác nhận: “Khi bạn gửi một HTTP request đến URL của Target, phản hồi HTML thiếu dữ liệu có ý nghĩa.”

Và ngay cả khi bạn giải quyết được phần JavaScript, vẫn còn một lớp nữa: cơ chế phát hiện bot của Akamai trên Target sẽ nhận diện dấu vết TLS handshake của bạn và gắn cờ thư viện requests của Python trước cả khi có một byte HTML nào được trao đổi. Phần này tôi sẽ nói kỹ hơn ngay sau đây.

Điều gì khiến Target.com khó scrape bằng Python đến vậy

Target không chỉ là “một website dùng JavaScript”. Nó là một hệ thống phòng thủ nhiều lớp — và hiểu từng lớp là cách bạn chọn đúng phương pháp scrape.

Dữ liệu sản phẩm được render bằng JavaScript

Target.com được xây dựng trên React. Khi bạn mở một trang sản phẩm hoặc trang tìm kiếm trong trình duyệt thật, diễn ra như sau:

  1. Server gửi một HTML shell tối giản
  2. Các gói JavaScript được tải và thực thi
  3. Frontend gọi API nội bộ Redsky của Target
  4. Dữ liệu sản phẩm (giá, xếp hạng, hình ảnh, tình trạng còn hàng) được render vào DOM

Nếu bạn bỏ qua các bước 2–4 — mà requests.get() chính là như vậy — bạn sẽ nhận được một trang gần như trống. GroupBWT đã benchmark điều này: các request HTTP tĩnh chỉ lấy được khoảng 30% dữ liệu sẵn có trên Target. 70% còn lại cần chạy JavaScript hoặc truy cập API.

Trang kết quả tìm kiếm còn tệ hơn. Ban đầu chỉ một số ít sản phẩm xuất hiện trong HTML; phần còn lại chỉ tải khi bạn cuộn trang.

Hệ thống chống bot của Target: không chỉ là câu chuyện “dùng proxy đi”

Phần lớn hướng dẫn scraping thường lướt qua các biện pháp chống bot bằng câu “chỉ cần dùng proxy”. Nhưng cơ chế của Target đáng để nói cụ thể hơn.

TLS fingerprinting (quan trọng nhất). Trong quá trình bắt tay HTTPS, client của bạn gửi một gói “Client Hello” tiết lộ phiên bản TLS, bộ mã hóa, extension và elliptic curve. Những thông tin này được băm thành một fingerprint JA3. Thư viện requests của Python tạo ra một hash tĩnh, đã biết trước8d9f7747675e24454cd9b7ed35c58707 — nên các cơ sở dữ liệu chống bot nhận ra ngay lập tức. Chrome gửi 16 cipher suites được sắp xếp cẩn thận cùng giá trị GREASE; Python gửi hơn 60 theo thứ tự không giống trình duyệt. Việc chặn xảy ra trước cả khi nội dung HTTP được trao đổi.

Xếp hạng độ tin cậy IP. Akamai phân loại IP thành các mức tin cậy. IP trung tâm dữ liệu bị gắn điểm tin cậy âm rất mạnh vì thường được bot sử dụng, theo cách nói của Scrapfly. IP dân cư thì được chấm điểm dương. Với Target, dải IP trung tâm dữ liệu thường bị gắn cờ ngay lập tức.

Fingerprinting JavaScript. Akamai chèn JavaScript thu thập thông số engine JS, khả năng phần cứng, dữ liệu hệ điều hành, font, plugin và dữ liệu hành vi (tốc độ gõ, chuyển động chuột, thời điểm click). Từ đó tạo ra cookie _abck — một token fingerprint có trạng thái. Nếu không có _abck hợp lệ, request sẽ bị chặn.

Giới hạn tần suất. Target bắt đầu trả lỗi 429 ở khoảng 30–60 request mỗi phút trên mỗi IP. Một số người còn báo cáo phản hồi 200 OK “đánh lừa” nhưng thực ra chứa trang chặn “Pardon Our Interruption” — khiến việc phát hiện tự động càng khó hơn.

ScrapeOps chấm Target mức khó 7/10 tổng thể. Riêng phần vượt Akamai được chấm 9/10.

3 cách scrape Target.com bằng Python (đặt cạnh nhau)

Không có bài viết nào so sánh cả ba cách khả thi này ở cùng một chỗ. Dưới đây là đánh giá thực tế:

Tiêu chíRequests + BS4Selenium / PlaywrightRedsky API
Xử lý render JS❌ Không✅ Có✅ Có (JSON)
Tốc độ mỗi mục⚡ ~0,5–1 giây🐢 ~5–10 giây⚡ ~0,5–1 giây
Rủi ro bị chặn bot⚠️ Cao (TLS fingerprint)⚠️ Trung bình⚠️ Trung bình (khóa xác thực có thể đổi)
Độ phức tạp thiết lậpThấpTrung bìnhTrung bình–cao (reverse engineering)
Độ đầy đủ dữ liệu~30% (chỉ HTML tĩnh)~95% (toàn bộ trang)~90% (JSON có cấu trúc)
Phù hợp nhất choMetadata tĩnh, __TGT_DATA__Trang sản phẩm đầy đủ, đánh giáDữ liệu sản phẩm số lượng lớn

Bây giờ hãy cùng xây dựng từng cách.

Cách 1: scrape Target.com bằng Python Requests và BeautifulSoup

Cách này sẽ không lấy được giá được render bằng JavaScript trên trang tìm kiếm. Nhưng nó nhanh, nhẹ, và lấy được nhiều hơn bạn tưởng — nếu biết chỗ để tìm.

Mẹo ở đây là: Target nhúng một phần dữ liệu sản phẩm trong các thẻ <script> chứa biến __TGT_DATA__ với __PRELOADED_QUERIES__. Khối JSON này gồm tên sản phẩm, mô tả, tính năng, và đôi khi cả giá trên trang sản phẩm đơn lẻ. Bạn cũng có thể lấy tiêu đề sản phẩm và URL từ HTML trang kết quả tìm kiếm.

Bước 1: Thiết lập môi trường Python

Tạo thư mục dự án và cài các phụ thuộc:

mkdir target-scraper && cd target-scraper
python -m venv venv
source venv/bin/activate  # Trên Windows: venv\Scripts\activate
pip install requests beautifulsoup4 curl_cffi

Ở đây hãy dùng curl_cffi thay vì requests tiêu chuẩn. Nó giả lập TLS fingerprint của trình duyệt, và đây là yếu tố quan trọng nhất để tránh bị chặn trên Target. Các benchmark cho thấy tỷ lệ né chống bot của curl_cffi92%, so với chỉ 12% của requests tiêu chuẩn — tức cải thiện 15 lần.

Bước 2: scrape kết quả tìm kiếm của Target

Định dạng URL tìm kiếm của Target rất đơn giản: https://www.target.com/s?searchTerm={keyword}

from curl_cffi import requests as cureq
from bs4 import BeautifulSoup
import time, random

headers = {
    "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",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
}

url = "https://www.target.com/s?searchTerm=bluetooth+headphones"
resp = cureq.get(url, headers=headers, impersonate="chrome124")
soup = BeautifulSoup(resp.text, "html.parser")

# Thẻ sản phẩm dùng thuộc tính data-test này
cards = soup.find_all("div", {"data-test": "@web/site-top-of-funnel/ProductCardWrapper"})
for card in cards:
    link_tag = card.find("a")
    title = link_tag.get_text(strip=True) if link_tag else "N/A"
    href = "https://www.target.com" + link_tag["href"] if link_tag and link_tag.get("href") else "N/A"
    print(f"{title} — {href}")

Bạn sẽ lấy được tên sản phẩm và URL. Giá ư? Có lẽ không từ HTML này. Điều đó là bình thường.

Bước 3: trích xuất JSON nhúng từ trang sản phẩm

Các trang sản phẩm riêng lẻ nhúng dữ liệu phong phú hơn trong thẻ script __TGT_DATA__:

import re, json

product_url = "https://www.target.com/p/some-product/-/A-12345678"
resp = cureq.get(product_url, headers=headers, impersonate="chrome124")
soup = BeautifulSoup(resp.text, "html.parser")

# Tìm script __TGT_DATA__
scripts = soup.find_all("script")
for script in scripts:
    if script.string and "__TGT_DATA__" in script.string:
        # Trích JSON từ nội dung script
        match = re.search(r'__TGT_DATA__\s*=\s*({.*?});?\s*$', script.string, re.DOTALL)
        if match:
            tgt_data = json.loads(match.group(1))
            # Đi sâu vào cấu trúc JSON để lấy chi tiết sản phẩm
            queries = tgt_data.get("__PRELOADED_QUERIES__", {})
            # Dữ liệu sản phẩm nằm lồng bên trong — cấu trúc thay đổi theo trang
            print(json.dumps(queries, indent=2)[:500])  # Xem trước cấu trúc

Cấu trúc JSON bên trong __TGT_DATA__ chứa tên sản phẩm, mô tả, tính năng, và thường có cả dữ liệu giá. Cách lồng cụ thể sẽ thay đổi, nên bạn cần kiểm tra output và dò đường đi phù hợp.

Bước 4: xử lý phân trang

Phân trang của Target dùng tham số Nao. Trang 1 là Nao=0, trang 2 là Nao=24, trang 3 là Nao=48, và cứ thế tiếp tục (mỗi lần tăng 24):

for page in range(0, 120, 24):  # 5 trang đầu
    paginated_url = f"https://www.target.com/s?searchTerm=bluetooth+headphones&Nao={page}"
    resp = cureq.get(paginated_url, headers=headers, impersonate="chrome124")
    # Phân tích và trích xuất...
    time.sleep(random.uniform(2, 5))  # Lịch sự một chút

Bước 5: lưu dữ liệu đã scrape

import csv

with open("target_products.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "url", "price", "description"])
    writer.writeheader()
    for product in products:
        writer.writerow(product)

Bạn sẽ lấy được gì: tiêu đề sản phẩm, URL, mô tả và metadata nhúng. Bạn sẽ không lấy ổn định được gì: giá và xếp hạng động từ trang kết quả tìm kiếm. Với những thứ đó, bạn cần Cách 2 hoặc 3.

Cách 2: scrape Target.com bằng Selenium hoặc Playwright

Một trình duyệt headless sẽ render JavaScript, tải nội dung động và mô phỏng hành vi người dùng thật. Đây là cách giúp bạn lấy giá, xếp hạng và đánh giá.

Nếu so Selenium với Playwright: Playwright đã vượt Selenium về mức độ phổ biến45,1% so với 22,1% vào năm 2026 — và benchmark cho thấy nó nhanh hơn 2,5 lần (11 giây so với 28 giây cho 20 trang). Tôi vẫn sẽ minh họa bằng Selenium ở đây vì cộng đồng lớn hơn và nhiều tài liệu hơn, nhưng nếu bắt đầu từ đầu, Playwright là lựa chọn tốt hơn.

Bước 1: cài Selenium và ChromeDriver

pip install selenium webdriver-manager

webdriver-manager tự động xử lý phiên bản ChromeDriver — không còn cảnh đau đầu vì “ChromeDriver version mismatch” nữa:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager

options = Options()
options.add_argument("--headless=new")
options.add_argument("--window-size=1920,1080")
options.add_argument("--disable-blink-features=AutomationControlled")
options.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")

driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

Bước 2: tải trang Target và chờ nội dung

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver.get("https://www.target.com/s?searchTerm=bluetooth+headphones")

# Chờ card sản phẩm render (explicit wait > time.sleep)
WebDriverWait(driver, 15).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, '[data-test="product-title"]'))
)

Explicit wait là rất quan trọng. time.sleep(10) vừa lãng phí thời gian với trang tải nhanh, vừa không đủ với trang tải chậm — tệ cả hai phía. WebDriverWait sẽ kiểm tra mỗi 500ms cho đến khi phần tử xuất hiện hoặc hết thời gian chờ.

Bước 3: cuộn trang để tải toàn bộ sản phẩm

Target tải dần sản phẩm khi bạn cuộn. Nếu không cuộn, bạn chỉ lấy được 4–5 sản phẩm thay vì toàn bộ trang:

import time

last_height = driver.execute_script("return document.body.scrollHeight")
for _ in range(10):
    driver.execute_script("window.scrollBy(0, 300);")
    time.sleep(1.5)
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

ScrapeOps xác nhận qua thử nghiệm rằng 10 vòng cuộn với độ trễ 1,5 giây cho ra 8+ sản phẩm, so với chỉ 4–5 nếu không cuộn. Mỗi lần cuộn nên khoảng 200–300px để giống hành vi người thật.

Bước 4: trích xuất dữ liệu sản phẩm từ trang đã render

products = []
cards = driver.find_elements(By.CSS_SELECTOR, '[data-test="@web/site-top-of-funnel/ProductCardWrapper"]')

for card in cards:
    try:
        title = card.find_element(By.CSS_SELECTOR, '[data-test="product-title"]').text
    except:
        title = "N/A"
    try:
        price = card.find_element(By.CSS_SELECTOR, '[data-test="current-price"]').text
    except:
        price = "N/A"
    try:
        link = card.find_element(By.CSS_SELECTOR, 'a[href*="/p/"]').get_attribute("href")
    except:
        link = "N/A"

    products.append({"title": title, "price": price, "link": link})

for p in products:
    print(f'{p["title"]} — {p["price"]}')

Các selector data-test quan trọng của Target (đã xác minh năm 2026):

Trường dữ liệuSelector
Thẻ sản phẩmdata-test="@web/site-top-of-funnel/ProductCardWrapper"
Tiêu đề sản phẩmdata-test="product-title"
Giá hiện tạidata-test="current-price"
Giá trị xếp hạngdata-test="rating-value"
Số lượt đánh giádata-test="rating-count"

Bước 5: scrape đánh giá sản phẩm (phần thưởng thêm)

Chuyển đến trang sản phẩm riêng lẻ, cuộn tới phần đánh giá và trích xuất dữ liệu review:

from bs4 import BeautifulSoup

driver.get("https://www.target.com/p/some-product/-/A-12345678")
# Cuộn xuống để tải review
for _ in range(5):
    driver.execute_script("window.scrollBy(0, 500);")
    time.sleep(2)

soup = BeautifulSoup(driver.page_source, "html.parser")
reviews = soup.find_all("div", {"data-test": "review-card--text"})
for review in reviews:
    print(review.get_text(strip=True)[:100])

Đánh giá được tải qua tích hợp Bazaarvoice và hỗ trợ phân trang (tối đa 51 trang), sắp xếp theo độ mới, và bộ lọc chỉ ảnh. Benchmark của ScrapeOps cho thấy khoảng 5,1 giây cho mỗi mục khi dùng Selenium.

Đừng quên đóng trình duyệt khi xong:

driver.quit()

Cách 3: scrape Target.com bằng Redsky API

Frontend của Target lấy mọi thứ từ một API nội bộ tại redsky.target.com. Bạn có thể gọi trực tiếp bằng Python — không cần parse HTML, không cần trình duyệt, không cần render JavaScript. Response là JSON sạch với hơn 40 trường dữ liệu bao gồm giá, xếp hạng, đánh giá, hình ảnh, tình trạng còn hàng, hoàn tất đơn hàng, thông số kỹ thuật và biến thể. Nếu cần dữ liệu sản phẩm số lượng lớn, đây là cách nhanh và đáng tin nhất, bỏ xa các cách còn lại.

Bước 1: tìm Redsky API bằng Chrome DevTools

Phần lớn tutorial bỏ qua chỗ này. Cách tự tìm API như sau:

  1. Mở bất kỳ trang sản phẩm Target nào trong Chrome
  2. Mở DevTools (F12) → tab Network
  3. Lọc theo Fetch/XHR
  4. Tải lại trang
  5. Tìm request tới redsky.target.com hoặc redsky.a]target.com
  6. Click vào một request — xem Request URLHeaders

Bạn sẽ thấy dạng như:

https://redsky.target.com/redsky_aggregations/v1/web/pdp_fulfillment_v1?key=9f36aeafbe60771e321a7cc95a78140772ab3e96&tcin=12345678&store_id=2148&zip=55401

Các tham số chính:

  • key — API key (tĩnh, không xoay vòng — từng endpoint dùng key khác nhau)
  • tcin — Target.com Item Number (ID sản phẩm 8 chữ số)
  • store_id — vị trí cửa hàng Target
  • zip — mã ZIP cho dữ liệu hoàn tất đơn hàng

Lấy API key từ request headers. Nó được nhúng trong URL dưới dạng query parameter.

Bước 2: gọi trực tiếp Redsky API bằng Python

from curl_cffi import requests as cureq
import json

API_KEY = "9f36aeafbe60771e321a7cc95a78140772ab3e96"  # Lấy từ DevTools
TCIN = "12345678"

url = f"https://redsky.target.com/redsky_aggregations/v1/web/pdp_fulfillment_v1?key={API_KEY}&tcin={TCIN}&store_id=2148&zip=55401"

headers = {
    "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",
    "Accept": "application/json",
    "Origin": "https://www.target.com",
    "Referer": "https://www.target.com/",
    "Sec-Fetch-Site": "same-site",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Dest": "empty",
}

resp = cureq.get(url, headers=headers, impersonate="chrome124")
data = resp.json()

# Trích chi tiết sản phẩm từ JSON response
product = data.get("data", {}).get("product", {})
title = product.get("item", {}).get("product_description", {}).get("title", "N/A")
price = product.get("price", {}).get("formatted_current_price", "N/A")
rating = product.get("ratings_and_reviews", {}).get("statistics", {}).get("rating", {}).get("average", "N/A")

print(f"{title} — {price} — Rating: {rating}")

Không cần parse HTML. Response có cấu trúc rõ ràng, sạch và nhanh.

Bước 3: scrape kết quả tìm kiếm sản phẩm qua API

Endpoint product_summary_with_fulfillment_v1 nhận nhiều TCIN cùng lúc:

tcins = ["12345678", "23456789", "34567890"]
tcin_str = ",".join(tcins)

search_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"

resp = cureq.get(search_url, headers=headers, impersonate="chrome124")
results = resp.json()

for item in results.get("data", {}).get("product_summaries", []):
    title = item.get("title", "N/A")
    price = item.get("price", {}).get("formatted_current_price", "N/A")
    print(f"{title} — {price}")

Để có TCIN, bạn có thể trích từ HTML trang tìm kiếm (chúng xuất hiện trong URL sản phẩm dưới dạng /A-XXXXXXXX) hoặc từ JSON nhúng __TGT_DATA__.

Bước 4: mở rộng quy mô bằng request đồng thời

from concurrent.futures import ThreadPoolExecutor
import time, random

def fetch_product(tcin):
    url = f"https://redsky.target.com/redsky_aggregations/v1/web/pdp_fulfillment_v1?key={API_KEY}&tcin={tcin}&store_id=2148&zip=55401"
    time.sleep(random.uniform(2, 5))
    resp = cureq.get(url, headers=headers, impersonate="chrome124")
    return resp.json()

tcin_list = ["12345678", "23456789", "34567890", "45678901"]

with ThreadPoolExecutor(max_workers=3) as executor:
    results = list(executor.map(fetch_product, tcin_list))

Hãy giữ mức đồng thời ở mức vừa phải — 3–5 thread với độ trễ ngẫu nhiên 2–5 giây. Giới hạn tốc độ của Target nằm khoảng 30–60 request mỗi phút trên mỗi IP.

Những lưu ý quan trọng về Redsky API

Trước khi xây dựng pipeline sản xuất dựa trên API này, hãy nhớ vài điểm sau:

  • API key là tĩnh nhưng phụ thuộc endpoint. Các endpoint Redsky khác nhau dùng key khác nhau. Chúng không đổi liên tục, nhưng Target có thể đổi bất kỳ lúc nào.
  • Đây là một API nội bộ không được tài liệu hóa. Đội ngũ kỹ sư của Target đã xác nhận đây là API cố ý công khai ra ngoài, nên rủi ro pháp lý giảm bớt, nhưng nó không phải API công khai có SLA hỗ trợ.
  • Mỗi biến thể sản phẩm (màu, kích cỡ) có TCIN riêng. Bạn cần query từng biến thể riêng.
  • Thiếu các header Sec-Fetch-* sẽ bị chặn ngay. Đây là lỗi rất hay gặp — luôn thêm Sec-Fetch-Site, Sec-Fetch-ModeSec-Fetch-Dest.

Mẹo scrape Target.com ở quy mô lớn mà không bị chặn

Những thực hành này áp dụng ở quy mô sản xuất, bất kể bạn dùng phương pháp nào.

Xoay vòng proxy dân cư, không dùng proxy trung tâm dữ liệu

Triển khai Akamai của Target sẽ gắn cờ dải IP trung tâm dữ liệu ngay từ cái nhìn đầu tiên. Proxy dân cư là bắt buộc nếu muốn scrape bền vững. Giá cả thay đổi khá nhiều — Smartproxy/Decodo bắt đầu từ $4,50/GB, Bright Data ở mức $5,04/GB, và có thể giảm xuống khoảng $3–4/GB khi mua số lượng lớn.

Xoay IP sau mỗi 50–100 request, hoặc mỗi request nếu pool proxy của bạn hỗ trợ.

Giả mạo TLS fingerprint bằng curl_cffi

Đây là thay đổi có tác động lớn nhất mà bạn có thể làm. Coi như thay thế trực tiếp cho requests:

from curl_cffi import requests as cureq

# requests tiêu chuẩn — tỷ lệ thành công 12% trên site được bảo vệ
# resp = requests.get(url, headers=headers)

# curl_cffi — tỷ lệ thành công 92%
resp = cureq.get(url, headers=headers, impersonate="chrome124")

curl_cffi (hơn 8.200 sao trên GitHub) hỗ trợ các phiên bản Chrome từ chrome99 đến chrome146, cùng Safari, Edge và các biến thể mobile. Nó nhanh hơn 20–30% so với tls_client ở chế độ đồng bộ.

Thiết lập nhịp request và header thực tế

  • Độ trễ ngẫu nhiên: 2–7 giây giữa các request (không dùng khoảng cố định — tính ngẫu nhiên rất quan trọng)
  • Xoay vòng User-Agent: Duy trì một pool 5–10 chuỗi User-Agent trình duyệt thật và xoay vòng
  • Làm nóng session: Truy cập trang chủ target.com trước khi vào trang sản phẩm để tạo cookie
  • Tính nhất quán của header: Sec-Ch-Ua phải khớp với phiên bản trình duyệt của User-Agent bạn khai báo. Sec-Ch-Ua-Platform phải khớp với hệ điều hành bạn khai báo. Mâu thuẫn là dấu hiệu lộ liễu nhất.
  • Duy trì session: Giữ cookie xuyên suốt các request trong cùng một session. Scraperly khuyến nghị session ổn định 48 giờ với proxy dân cư xoay vòng.

Bỏ qua phần code: scrape Target.com với Thunderbit (lựa chọn không cần code)

Target.com, nói thật thì, là một trong những website bán lẻ khó scrape bằng code nhất. Render JavaScript, fingerprint TLS của Akamai, phát hiện proxy trung tâm dữ liệu, rắc rối phiên bản ChromeDriver — có quá nhiều chi tiết phải lo. Nếu bạn đang học Python, đó là một bài tập rất tốt. Nhưng nếu bạn cần dữ liệu sản phẩm Target cho công việc thật, phép tính chi phí–lợi ích thường không mấy hợp lý.

Với những ai cần dữ liệu mà không muốn ôm một dự án kỹ thuật lớn, Thunderbit sẽ tự xử lý phần khó.

Thunderbit xử lý các thách thức của Target.com như thế nào

AI Web Scraper của Thunderbit chạy ngay trong trình duyệt của bạn, nên tự nhiên nó render JavaScript — không cần thiết lập Selenium, không cần cấu hình browser headless, không cần lo phiên bản ChromeDriver. Trình duyệt chính là scraper.

Quy trình làm việc như sau:

  1. Cài Thunderbit Chrome Extension và mở một trang sản phẩm hoặc trang tìm kiếm của Target
  2. Bấm “AI Suggest Fields” — Thunderbit đọc trang và đề xuất tên cột (Tên sản phẩm, Giá, Xếp hạng, URL hình ảnh, v.v.)
  3. Bấm “Scrape” — dữ liệu được trích xuất trong vài giây, trực tiếp từ trang đã render

Không cần cấu hình proxy. Không cần giả mạo TLS fingerprint. Không còn kết quả None.

Scrape danh sách sản phẩm và trang chi tiết của Target

Quy trình nhiều trang là lúc mọi thứ trở nên thú vị. Hãy scrape một trang kết quả tìm kiếm của Target để lấy danh sách sản phẩm, rồi dùng Subpage Scraping để tự động truy cập từng URL sản phẩm và làm giàu bảng của bạn với dữ liệu từ trang chi tiết — mô tả, review đầy đủ, thông số kỹ thuật — mà không cần viết code phân trang hay quản lý session trình duyệt.

Xuất trực tiếp ra Excel, Google Sheets, Airtable hoặc Notion. Không cần boilerplate csv.writer, không lo lỗi mã hóa file.

Tự động hóa các lần scrape Target.com định kỳ

Với việc theo dõi giá hoặc tồn kho liên tục, Scheduled Scraper của Thunderbit cho phép bạn mô tả lịch bằng ngôn ngữ tự nhiên (ví dụ: “mỗi thứ Hai lúc 9 giờ sáng”). Không cron job, không thiết lập server, không phải giữ một script Python chạy sống trên VPS. Điều này đặc biệt hữu ích cho các team ecommerce theo dõi giá của đối thủ81% nhà bán lẻ ở Mỹ hiện đã dùng tự động thu thập giá, và ROI của giá tình báo trung bình lên tới 27:1.

Khi nào nên dùng cách nào để scrape Target.com bằng Python

Đây là khung ra quyết định nhanh:

Tình huống của bạnPhương pháp đề xuất
Đang học Python, dự án nhỏCách 1: Requests + BS4 (cho dữ liệu tĩnh và __TGT_DATA__)
Cần trang sản phẩm đầy đủ với giá và đánh giáCách 2: Selenium / Playwright
Trích xuất dữ liệu sản phẩm số lượng lớn ở quy mô lớnCách 3: Redsky API
Cần dữ liệu nhanh mà không muốn viết codeThunderbit (không cần code)
Theo dõi giá định kỳThunderbit Scheduled Scraper hoặc Redsky API + cron
Nghiên cứu một lần, đội ngũ không chuyên kỹ thuậtThunderbit — thành thật mà nói là đường nhanh nhất

Nếu bạn đang xây dựng một pipeline dữ liệu cho production, Cách 3 (Redsky API) cho tốc độ và độ tin cậy tốt nhất. Nếu bạn chỉ làm nghiên cứu một lần hoặc đội ngũ không rành Python, Thunderbit sẽ tiết kiệm hàng giờ. Còn nếu bạn đang học web scraping, lộ trình Cách 1 → Cách 2 → Cách 3 là một tiến trình tự nhiên, giúp bạn học được điều thực tế ở mỗi bước.

Những cân nhắc pháp lý và đạo đức khi scrape Target.com

Cũng nên nói ngắn gọn về phần này. robots.txt của Target có khoảng hơn 120 đường dẫn Disallow nhưng đáng chú ý là không chặn /p/ (sản phẩm) hoặc /c/ (danh mục) — các trang sản phẩm và danh mục được phép crawl một cách rõ ràng. Các trang giỏ hàng, tài khoản và thanh toán thì bị hạn chế.

Điều khoản sử dụng của Target có cấm truy cập tự động. Tuy nhiên, việc Redsky API được cố ý đưa ra công khai (theo xác nhận từ đội ngũ kỹ sư Target) làm giảm rủi ro pháp lý cho việc thu thập dữ liệu dựa trên API.

Các tiền lệ pháp lý quan trọng cần biết:

  • hiQ v. LinkedIn (Tòa phúc thẩm Khu vực 9, 2022): thu thập dữ liệu công khai không vi phạm CFAA
  • Meta v. Bright Data (2024): Meta thua kiện — tòa xác định không có vi phạm CFAA khi thu thập dữ liệu công khai

Với scraping thương mại quy mô lớn, hãy hỏi ý kiến luật sư. Với nghiên cứu thị trường, so sánh giá và dự án cá nhân dùng dữ liệu công khai, bạn đang ở vùng khá an toàn. Luôn tôn trọng giới hạn tốc độ và đừng làm quá tải server của Target.

Kết luận và điểm rút ra chính

Target.com xứng đáng với mức độ khó của nó. Cách làm ngây thơ bằng Requests + BeautifulSoup thất bại vì Target render dữ liệu sản phẩm bằng JavaScript và Akamai fingerprint TLS handshake của bạn trước cả khi bạn nhận được response. Nhưng với phương pháp đúng, việc trích xuất dữ liệu lại khá thẳng thắn.

Ba cách, xếp theo độ tin cậy:

  1. Redsky API — nhanh nhất, đáng tin nhất cho dữ liệu số lượng lớn, trả về JSON sạch. Cần reverse-engineer endpoint API qua DevTools.
  2. Selenium / Playwright — xử lý render JavaScript, lấy được mọi thứ trên trang. Chậm hơn nhưng đầy đủ.
  3. Requests + BeautifulSoup — chỉ giới hạn ở HTML tĩnh và JSON __TGT_DATA__ nhúng. Nhanh nhưng không đầy đủ.

Những thắng lợi kỹ thuật lớn nhất:

  • Dùng curl_cffi thay cho requests tiêu chuẩn để tăng 15 lần khả năng né chống bot
  • Proxy dân cư là bắt buộc — IP trung tâm dữ liệu bị gắn cờ ngay lập tức
  • Thêm header Sec-Fetch-* trong mọi request — thiếu chúng là bị chặn ngay
  • Làm nóng session (truy cập trang chủ trước) giúp tăng đáng kể tỷ lệ thành công

Và nếu Python không đáng để bạn phải đau đầu cho trường hợp của mình, Chrome extension của Thunderbit sẽ tự động xử lý render JavaScript, các biện pháp chống bot và xuất dữ liệu. Hãy thử gói miễn phí và xem liệu nó có giúp bạn có thứ mình cần chỉ trong vài phút thay vì vài giờ hay không.

Để xem thêm các hướng dẫn scraping và mẹo trích xuất dữ liệu, hãy ghé blog Thunderbit hoặc kênh YouTube của chúng tôi.

Câu hỏi thường gặp

Tôi có thể scrape Target.com chỉ bằng Python Requests và BeautifulSoup không?

Có, nhưng chỉ ở mức một phần. Bạn có thể trích xuất tiêu đề sản phẩm, URL và một số dữ liệu JSON nhúng từ các thẻ script __TGT_DATA__ trên trang sản phẩm. Tuy nhiên, giá, xếp hạng, đánh giá và tình trạng còn hàng trên trang kết quả tìm kiếm đều được render bằng JavaScript và sẽ không xuất hiện với HTTP request tĩnh. Để lấy dữ liệu đầy đủ, hãy dùng Selenium/Playwright hoặc Redsky API.

Vì sao scraper Target.com của tôi trả về None cho giá?

Target tải dữ liệu giá bằng JavaScript sau lần tải trang ban đầu. Khi bạn dùng requests.get(), bạn chỉ nhận được HTML shell được render trước — trước khi JavaScript chạy và chèn dữ liệu sản phẩm vào DOM. Các phần tử giá theo nghĩa đen là chưa hề tồn tại trong response. Hãy dùng một trình duyệt headless (Selenium hoặc Playwright) để render JavaScript, gọi trực tiếp Redsky API để lấy JSON, hoặc dùng một công cụ như Thunderbit để scrape từ trang đã render trong trình duyệt.

Scrape Target.com có hợp pháp không?

Việc thu thập dữ liệu công khai nhìn chung được phép theo án lệ hiện tại của Mỹ (hiQ v. LinkedIn, Meta v. Bright Data). robots.txt của Target cho phép crawl trang sản phẩm và danh mục. Tuy nhiên, Điều khoản sử dụng của Target cấm truy cập tự động, nên vẫn tồn tại vùng xám. Với nghiên cứu thị trường và so sánh giá bằng dữ liệu công khai, bạn đang ở vị thế pháp lý tương đối ổn. Với vận hành thương mại quy mô lớn, hãy hỏi luật sư.

Redsky API của Target là gì và làm sao truy cập nó?

Redsky là API nội bộ của Target, cung cấp dữ liệu sản phẩm cho frontend. Nó không phải API công khai có tài liệu và API key để bạn đăng ký, mà là backend mà ứng dụng React của họ gọi để render trang sản phẩm. Bạn có thể phát hiện endpoint của nó bằng cách mở Chrome DevTools, lọc tab Network theo XHR/Fetch, và tìm request tới redsky.target.com. API key được nhúng trong URL request dưới dạng query parameter. Đội ngũ kỹ sư Target đã xác nhận đây là API cố ý công khai.

Làm sao để tránh bị chặn khi scrape Target.com?

Thay đổi có tác động lớn nhất là dùng curl_cffi thay cho requests Python tiêu chuẩn để giả mạo TLS fingerprint của trình duyệt — chỉ riêng điều này đã nâng tỷ lệ thành công từ 12% lên 92%. Ngoài ra: dùng proxy dân cư (không dùng trung tâm dữ liệu), xoay vòng User-Agent, thêm độ trễ ngẫu nhiên 2–7 giây giữa các request, bao gồm đầy đủ header Sec-Fetch-*, và làm nóng session bằng cách truy cập trang chủ trước. Hoặc dùng một công cụ như Thunderbit để tự động xử lý các biện pháp chống bot mà không cần cấu hình gì.

Tìm hiểu thêm

Ke
Ke
CTO tại Thunderbit | Chuyên gia Khoa học Dữ liệu cấp cao & ML Với gần một thập kỷ kinh nghiệm trong học máy và khoa học dữ liệu, Ke Shen là cựu sinh viên Đại học Columbia và từng là Chuyên gia Khoa học Dữ liệu cấp cao tại Walmart Labs. Sở hữu chuyên môn sâu về Python, R, Java và Thống kê, được đồng nghiệp công nhận, anh chia sẻ những góc nhìn thực chiến về cách đưa các thuật toán AI phức tạp từ lý thuyết vào kiến trúc sẵn sàng cho môi trường sản xuất.
Mục lục

Cào một trang web chỉ bằng cách hỏi

Nói bạn cần gì bằng tiếng Anh đơn giản. Hoặc tốt hơn, không cần nói gì cả.

Dùng Thunderbit ngay miễn phí
Trích xuất dữ liệu bằng AI
Dễ dàng chuyển dữ liệu sang Google Sheets, Airtable hoặc Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week