Target.com ist einer der größten Einzelhandelskataloge in den Vereinigten Staaten, mit Millionen öffentlicher Produktseiten in den Bereichen Elektronik, Bekleidung, Haushaltswaren und Lebensmittel. Jedes Listing enthält die Daten, die die meisten Einzelhandelsrecherchen antreiben: einen Titel, einen aktuellen Preis, eine TCIN-Kennung, eine Sternebewertung und ein klares Signal zur Verfügbarkeit. Preisbeobachter, Wettbewerbsanalysten und Produktforscher verfolgen diese Felder, weil sie eines der saubereren Signale dafür liefern, was ein Massenmarkthändler zu einem bestimmten Zeitpunkt berechnet und auf Lager hat.

Dieser Leitfaden zeigt, wie man Target-Produktdaten mit Python scrapt. Es wird ein kleines, lauffähiges Scraper-Skript erstellt, das eine Target-Such- oder Produktseite über die Crawling API abruft, für jedes Produkt einen sauberen Datensatz parst, die Paginierung über Ergebnisseiten abhandelt und in JSON und CSV exportiert. Der gesamte Walkthrough bleibt auf öffentliche Katalogdaten beschränkt: die Titel, Preise, Bewertungen und Verfügbarkeit, die jeder auf Target.com ohne Login einsehen kann.

Was du bauen wirst

Ein Python-Skript, das eine Target-Such-URL nimmt, die gerenderte Seite über die Crawling API abruft und für jedes Produkt einen strukturierten Datensatz extrahiert. Als laufendes Beispiel dient eine Suche nach "womens sweaters", dieselbe Abfrage wie im ursprünglichen Walkthrough, und folgende Felder werden aus jeder Produktkarte gezogen:

  • Titel der auf der Listingkarte angezeigte Produktname.
  • Preis der aktuell gelistete Preis, der ein einzelner Wert oder eine Spanne sein kann.
  • TCIN / SKU Targets eigene Produktkennung, aus der Produkt-URL gelesen.
  • Bewertung die durchschnittliche Sternebewertung, abgeleitet aus der Breite der Bewertungsleiste.
  • Bewertungsanzahl wie viele Bewertungen diese Bewertung stützen.
  • Verfügbarkeit ob der Artikel als auf Lager oder nicht verfügbar angezeigt wird.
  • Produkt-URL der absolute Link zur eigenen Detailseite des Artikels.

Warum eine einfache Anfrage bei Target scheitert

Richtet man einen einfachen HTTP-Client auf eine Target-Such-URL, erhält man ein nahezu leeres Ergebnis. Target rendert sein Suchraster clientseitig: Der Server liefert eine leichte Hülle, und die Produktkarten erscheinen erst nachdem das JavaScript der Seite ausgeführt wird. Eine requests.get()-Antwort zu parsen ergibt eine leere Liste, weil die gesuchten Produkte nie in dieser ersten HTML-Nutzlast enthalten waren.

Darüber hinaus beobachtet Target automatisierten Traffic und blockiert Anfragemuster, die nicht wie ein echter Browser aussehen. Ein funktionsfähiger Target-Scraper benötigt daher zwei Dinge in einer Anfrage: einen Browser, der die Seite rendert, und eine IP, die Target als echten Käufer einstuft. Das kann man selbst mit einem Headless-Browser und einem Pool aus rotierenden Residential-Proxys zusammenstellen, aber diesen Stack am Laufen zu halten, ist der Großteil der Arbeit. Die Crawling API bündelt beides in einem einzigen Aufruf: Man sendet ihr die Such-URL, sie rendert die Seite hinter einer vertrauenswürdigen Residential-IP, übernimmt die Rotation und das CAPTCHA-Lösen und gibt fertiges HTML zum Parsen zurück.

Voraussetzungen

Vor dem Schreiben von Code müssen einige Dinge bereitstehen. Keines davon dauert lange.

Python-Grundkenntnisse. Man sollte in der Lage sein, ein Python-Skript zu schreiben, auszuführen und Pakete mit pip zu installieren. Wer neu in der Sprache ist, findet in unserem Leitfaden zum Einstieg in Python-Scraping das für dieses Tutorial nötige Niveau.

Python 3.8 oder neuer. Die Version mit python --version (oder python3 --version) prüfen. Falls nicht vorhanden, unter python.org herunterladen und sicherstellen, dass Python im System-PATH enthalten ist.

Ein Crawlbase-Konto und Token. Für ein kostenloses Konto anmelden, das Dashboard öffnen und den Token von der Account-Docs-Seite kopieren. Crawlbase stellt zwei Token aus: einen normalen Token für statische Sites und einen JavaScript-Token für dynamische, JS-gerenderte Seiten. Target ist JS-gerendert, daher verwendet dieses Tutorial den JavaScript-Token. Das kostenlose Kontingent umfasst bis zu 20.000 Anfragen ohne Kreditkarte, was für den Aufbau und Test dieses Scrapers ausreicht. Den Token wie ein Passwort behandeln und aus der Versionskontrolle heraushalten.

Das Projekt einrichten

Eine virtuelle Umgebung erstellen, damit Projektabhängigkeiten isoliert bleiben, dann die beiden Bibliotheken installieren, die der Scraper benötigt. crawlbase ist der offizielle Client für die Crawling API, und beautifulsoup4 parst das zurückgegebene HTML, damit man jedes Feld aus den Produktkarten per CSS-Selektor extrahieren kann.

bash
python --version

python -m venv target_env
source target_env/bin/activate

pip install crawlbase beautifulsoup4

Unter Windows die Umgebung statt mit der source-Zeile mit target_env\Scripts\activate aktivieren. Sobald beide Bibliotheken installiert sind, die Skriptdatei anlegen, die im weiteren Verlauf aufgebaut wird:

bash
touch target_scraper.py

Targets Suchseite verstehen

Eine Target-Suche liegt unter einer stabilen URL: https://www.target.com/s?searchTerm=womens+sweaters. Die Seite legt ein Raster aus Produktkarten an, eine pro Artikel, jede mit denselben wenigen Feldern: ein Titel, ein Preis, eine Sternebewertungsleiste, eine Bewertungsanzahl und ein Link zur Detailseite des Produkts. Target markiert die meisten davon mit data-test-Attributen, die weitaus langlebiger sind als seine generierten Klassennamen.

Bevor man Selektoren schreibt, sollte man eine Suchseite im Browser öffnen, mit der rechten Maustaste auf eine Produktkarte klicken und "Untersuchen" wählen. Jede Karte sitzt innerhalb von div[data-test="product-grid"], der Titel-Link trägt data-test="product-title", der aktuelle Preis verwendet data-test="current-price", die Bewertungsanzahl verwendet data-test="rating-count", und die Bewertung selbst ist eine maskierte Leiste mit data-ref="rating-mask", deren CSS-Breite den Score kodiert. Die TCIN, Targets interne Produkt-ID, ist in der Produkt-URL nach dem /A--Marker eingebettet, also direkt aus dem Link gelesen.

Schritt 1: Die gerenderte Suchseite abrufen

Zunächst die fertige Seite abrufen. Die Klasse CrawlingAPI importieren, sie mit dem JavaScript-Token initialisieren, die Such-URL setzen und sie mit den JS-Rendering-Optionen anfordern. Den Status vor dem Parsen zu prüfen, hält Fehler laut statt still.

python
from crawlbase import CrawlingAPI
from urllib.parse import quote

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['headers']['cb_status']}")
    return None

if __name__ == "__main__":
    search_term = "womens sweaters"
    url = f"https://www.target.com/s?searchTerm={quote(search_term)}"
    html = crawl(url)
    print(html[:500] if html else "No HTML returned")

Die beiden Wait-Optionen sind wichtig für ein Raster, das sich nach dem Laden füllt. ajax_wait weist die API an, auf den Abschluss asynchroner Inhalte zu warten, und page_wait hält 5000 Millisekunden nach dem Laden inne, damit spät gerenderte Karten erscheinen, bevor die Seite erfasst wird. Die Crawling API berichtet ihr eigenes Ergebnis in response["headers"]["cb_status"], also das statt des rohen HTTP-Codes prüfen. Das Skript ausführen, und es sollte echtes Produkt-Markup zu sehen sein, keine leere Hülle. Das bestätigt, dass das Rendering funktioniert, bevor ein einziger Selektor geschrieben wird.

Crawlbase Target Scraper

Dieses leere Raster ist genau das Problem, das die Crawling API löst: Targets Listings existieren nur nach der JavaScript-Ausführung, hinter einer IP, der Target vertraut. Man sendet den Token und die Such-URL, sie führt die Seite in einem echten Browser aus, rotiert serverseitig durch Residential-IPs, übernimmt das CAPTCHA-Lösen und übergibt fertiges HTML. Man überspringt den Betrieb einer Headless-Browser-Flotte und eines Proxy-Pools. Im kostenlosen Kontingent von bis zu 20.000 Anfragen beginnen.

Schritt 2: Produktkarten mit BeautifulSoup parsen

Mit gerendertem HTML lädt man es in BeautifulSoup, findet alle Produktkarten und zieht jedes Feld per Selektor heraus. Die Bewertung benötigt einen kleinen Helfer: Target zeichnet die Sterneleiste als gefüllte Maske, und der Score liegt in der CSS-width der Leiste als Prozentwert, der dann in einen Wert von 5 umgerechnet wird.

python
from bs4 import BeautifulSoup

BASE = "https://www.target.com"
GRID = 'div[data-test="product-grid"] section[class^="styles__StyledRowWrapper"] div[class^="styles__StyledCardWrapper"]'

def extract_rating(element):
    style = element.get("style") if element else None
    if not style:
        return None
    for prop in style.split(";"):
        prop = prop.strip()
        if prop.startswith("width:"):
            value = prop[len("width:"):].strip()
            if value.endswith("%"):
                percentage = float(value[:-1])
                return round((percentage / 100) * 5, 2)
    return None

def extract_tcin(href):
    if href and "/A-" in href:
        return href.split("/A-")[1].split("?")[0].split("#")[0]
    return None

def scrape_target_listing(html):
    soup = BeautifulSoup(html, "html.parser")
    products = soup.select(GRID)
    results = []
    for product in products:
        try:
            title_el = product.select_one('a[data-test="product-title"]')
            rating_el = product.select_one('div[data-ref="rating-mask"]')
            reviews_el = product.select_one('span[data-test="rating-count"]')
            price_el = product.select_one('span[data-test="current-price"]')
            sold_out_el = product.select_one('[data-test="soldOut"]')

            href = title_el["href"] if title_el else None
            availability = "Out of stock" if sold_out_el else "In stock"

            results.append({
                "title": title_el.get_text(strip=True) if title_el else None,
                "price": price_el.get_text(strip=True) if price_el else None,
                "tcin": extract_tcin(href),
                "rating": extract_rating(rating_el),
                "review_count": reviews_el.get_text(strip=True) if reviews_el else None,
                "availability": availability,
                "product_url": BASE + href if href else None,
            })
        except Exception as e:
            print(f"Skipped a card: {e}")
    return results

Der Produktraster-Selektor verbindet drei Teile direkt aus dem Legacy-Skript: den data-test="product-grid"-Container, den Zeilen-Wrapper und den Karten-Wrapper. Innerhalb jeder Karte kommen Titel und Preis aus ihren data-test-Selektoren, die Bewertungsanzahl aus rating-count und die Bewertung aus der maskierten Leiste über extract_rating. Der Helfer extract_tcin liest Targets Produktkennung aus der URL nach /A-, und die Verfügbarkeit wird daraus abgeleitet, ob ein Ausverkauft-Marker vorhanden ist. Jeder if el else None-Guard hält die Extraktion robust, wenn ein Feld fehlt, was häufig vorkommt, da nicht jede Karte eine Bewertung oder Bewertungsanzahl zeigt.

Selektoren verschieben sich

Targets generierte Klassennamen (die styles__StyledCardWrapper-Präfixe) ändern sich ohne Vorankündigung, während seine data-test- und data-ref-Attribute weitaus stabiler sind. Auf die Attribut-Selektoren setzen und die Klassen-Präfix-Kette als Ausgangspunkt betrachten, nicht als Vertrag. Wenn ein Feld für jede Karte als None zurückkommt, die Live-Suchseite in den Browser-DevTools erneut untersuchen und den Selektor aktualisieren. Periodische Selektor-Wartung ist bei jedem produktiven Scraper normal.

Schritt 3: Paginierung über Ergebnisseiten abhandeln

Eine Seite mit Ergebnissen ist eine Demo; ein echter Job durchläuft das gesamte Ergebnisset. Target paginiert seine Suche mit dem Nao-Parameter in der URL, der den Startoffset für jede Seite festlegt. Ergebnisse kommen in Chargen von 24, also ist Nao=1 die erste Seite, Nao=25 die zweite usw. Den Offset erhöhen, jede Seite abrufen und stoppen, wenn es keinen aktivierten Weiter-Button gibt.

python
PER_PAGE = 24

def has_next_page(html):
    soup = BeautifulSoup(html, "html.parser")
    return bool(soup.select_one('button[data-test="next"]:not([disabled])'))

def scrape_all_pages(base_url, max_pages=5):
    all_products = []
    for page in range(max_pages):
        nao = page * PER_PAGE + 1
        url = f"{base_url}&Nao={nao}"
        html = crawl(url)
        if not html:
            break
        found = scrape_target_listing(html)
        if not found:
            break
        all_products.extend(found)
        print(f"Page {page + 1}: {len(found)} products")
        if not has_next_page(html):
            break
    return all_products

Der Nao-Offset wird aus dem Seitenindex berechnet, also fordert Seite 0 Nao=1, Seite 1 Nao=25 an, und die Schleife läuft weiter, bis has_next_page keinen aktivierten button[data-test="next"] findet. Die max_pages-Begrenzung und der Leer-Ergebnis-Break stoppen beide frühzeitig, damit eine Suche mit zwei Ergebnisseiten nie fünf Anfragen durchspult. Das Begrenzen von Seiten hält auch die kostenlosen Credits in Grenzen, solange noch getestet wird.

Schritt 4: Das Skript zusammensetzen und JSON und CSV exportieren

Jetzt das Abrufen, Parsen und Paginieren in ein lauffähiges Skript einbinden und die Datensätze in JSON und CSV schreiben, damit sie in ein Notebook oder eine Tabellenkalkulation geladen werden können.

python
import csv
import json
from urllib.parse import quote
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})
BASE = "https://www.target.com"
GRID = 'div[data-test="product-grid"] section[class^="styles__StyledRowWrapper"] div[class^="styles__StyledCardWrapper"]'
PER_PAGE = 24
FIELDS = ["title", "price", "tcin", "rating", "review_count", "availability", "product_url"]

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['headers']['cb_status']}")
    return None

def extract_rating(element):
    style = element.get("style") if element else None
    if not style:
        return None
    for prop in style.split(";"):
        prop = prop.strip()
        if prop.startswith("width:"):
            value = prop[len("width:"):].strip()
            if value.endswith("%"):
                percentage = float(value[:-1])
                return round((percentage / 100) * 5, 2)
    return None

def extract_tcin(href):
    if href and "/A-" in href:
        return href.split("/A-")[1].split("?")[0].split("#")[0]
    return None

def scrape_target_listing(html):
    soup = BeautifulSoup(html, "html.parser")
    products = soup.select(GRID)
    results = []
    for product in products:
        try:
            title_el = product.select_one('a[data-test="product-title"]')
            rating_el = product.select_one('div[data-ref="rating-mask"]')
            reviews_el = product.select_one('span[data-test="rating-count"]')
            price_el = product.select_one('span[data-test="current-price"]')
            sold_out_el = product.select_one('[data-test="soldOut"]')

            href = title_el["href"] if title_el else None
            availability = "Out of stock" if sold_out_el else "In stock"

            results.append({
                "title": title_el.get_text(strip=True) if title_el else None,
                "price": price_el.get_text(strip=True) if price_el else None,
                "tcin": extract_tcin(href),
                "rating": extract_rating(rating_el),
                "review_count": reviews_el.get_text(strip=True) if reviews_el else None,
                "availability": availability,
                "product_url": BASE + href if href else None,
            })
        except Exception as e:
            print(f"Skipped a card: {e}")
    return results

def has_next_page(html):
    soup = BeautifulSoup(html, "html.parser")
    return bool(soup.select_one('button[data-test="next"]:not([disabled])'))

def scrape_all_pages(base_url, max_pages=5):
    all_products = []
    for page in range(max_pages):
        url = f"{base_url}&Nao={page * PER_PAGE + 1}"
        html = crawl(url)
        if not html:
            break
        found = scrape_target_listing(html)
        if not found:
            break
        all_products.extend(found)
        print(f"Page {page + 1}: {len(found)} products")
        if not has_next_page(html):
            break
    return all_products

def export(rows, name="target_products"):
    with open(f"{name}.json", "w", encoding="utf-8") as f:
        json.dump(rows, f, indent=2, ensure_ascii=False)
    with open(f"{name}.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDS)
        writer.writeheader()
        writer.writerows(rows)
    print(f"Saved {len(rows)} products to {name}.json and {name}.csv")

def main():
    search_term = "womens sweaters"
    base_url = f"https://www.target.com/s?searchTerm={quote(search_term)}"
    rows = scrape_all_pages(base_url, max_pages=3)
    export(rows)

if __name__ == "__main__":
    main()

Das vollständige Skript mit python target_scraper.py ausführen. Es durchläuft bis zu drei Seiten der Suche, parst eine Zeile pro Produkt und schreibt sowohl target_products.json als auch target_products.csv. Die gemeinsame FIELDS-Liste hält die CSV-Spaltenreihenfolge synchron mit den Dictionary-Keys, damit die beiden Exporte nie auseinanderlaufen. Um eine andere Kategorie zu scrapen, search_term auf eine beliebige von Target unterstützte Abfrage ändern oder base_url auf eine Kategorieseite statt auf eine Suche richten.

Wie die Ausgabe aussieht

Man erhält eine saubere Liste von Produktdatensätzen, in Seitenreihenfolge, bereit zum Schreiben in JSON, CSV oder eine Datenbank.

json
[
  {
    "title": "Women's Fine Gauge Crewneck Sweater - A New Day",
    "price": "$20.00",
    "tcin": "88228365",
    "rating": 3.9,
    "review_count": "587",
    "availability": "In stock",
    "product_url": "https://www.target.com/p/women-s-fine-gauge-crewneck-sweater-a-new-day/-/A-88228365"
  },
  {
    "title": "Women's Crew Neck Cashmere-Like Pullover Sweater - Universal Thread",
    "price": "$20.00 - $25.00",
    "tcin": "88062926",
    "rating": 4.2,
    "review_count": "746",
    "availability": "In stock",
    "product_url": "https://www.target.com/p/women-s-crew-neck-cashmere-like-pullover-sweater-universal-thread/-/A-88062926"
  }
]

Zu beachten: rating und review_count kommen bei Produkten ohne Bewertungen als null zurück, was erwartet wird: die maskierte Bewertungsleiste wird auf diesen Karten schlicht nicht gerendert. Preise kommen als angezeigte Strings an, einschließlich Spannen wie "$20.00 - $25.00", also sie nachgelagert auf Zahlen normalisieren, wenn man sie vergleichen oder in Diagrammen darstellen möchte. Das ist genau das Feldset, das man für einen Preisanalyse-Workflow benötigt.

Über Abfragen skalieren und entsperrt bleiben

Eine Suche ist eine Demo; ein echter Recherchejob läuft über viele Abfragen oder Kategorien. Eine Zuordnung von Suchbegriffen zum Scrapen anlegen, darüber iterieren und die Anfragen verteilen. Das gleiche Feldset überträgt sich auf eine einzelne Produktdetailseite, wo Titel, Preis, TCIN, Bewertung und ein explizites Auf-Lager- oder Nicht-Vorrätig-Badge alle unter einer URL verfügbar sind. Selbst mit übernommenem Rendering beobachtet Target Scraper-artigen Traffic, also halten einige Gewohnheiten einen Lauf gesund, und sie gelten für jedes schwierige kommerzielle Ziel.

  • Anfragen verteilen. Anfragen mit einer Verzögerung zwischen Seiten und Abfragen aufteilen, statt alles mit voller Geschwindigkeit zu crawlen. Schwerere Jobs außerhalb der Stoßzeiten einplanen, um Targets Server zu entlasten.
  • Auf Rotation setzen. Ein Pool aus Residential-IPs verteilt Anfragen über viele echte Nutzeradressen, damit keine einzelne ein Rate-Limit auslöst. Die Crawling API übernimmt das; wer seinen eigenen Stack aufbaut, sollte hier besonders sorgfältig vorgehen.
  • Nur das Nötige behalten. Die Produktfelder speichern, die das Projekt benötigt, und den Rest verwerfen. Die Selektoren regelmäßig überprüfen, damit der Scraper mit Markup-Änderungen Schritt hält.

Das umfassendere Playbook zum Umgehen von Blockierungen findet sich unter wie man Websites scrapt, ohne blockiert zu werden, und zur Frage, warum Rendering hier wichtig ist, unter wie man JavaScript-Websites crawlt. Dasselbe Muster gilt für andere große Handelsketten, wie in den Anleitungen zum Scrapen von Best-Buy-Produktdaten und der Walmart-Suche mit Python.

Ob das Scrapen von Target erlaubt ist, hängt von Targets Nutzungsbedingungen, der jeweiligen Rechtsordnung und dem Verwendungszweck der Daten ab. Targets Bedingungen schränken automatisierten Zugriff ein, daher kann Scraping gegen diese Bedingungen verstoßen, unabhängig davon, wie sorgfältig das Tooling ist. Keiner der Codes hier ändert das; er lässt nur den technischen Teil funktionieren. Die Targets Nutzungsbedingungen und die robots.txt lesen und beide als Grenze für das Sammeln behandeln. Bei kommerzieller oder wettbewerbsorientierter Nutzung wird die rechtliche Lage komplexer; die Konsultation eines Rechtsexperten zum konkreten Fall ist die vernünftige Vorgehensweise.

Einige Grenzen sind es wert, einzuhalten. Nur öffentliche Daten sammeln: die Titel, Preise, TCINs, Bewertungen und Listing-Links, die jeder auf einer Target-Such- oder Produktseite ohne Account sehen kann. Das Anfragevolumen niedrig genug halten, damit Targets Server nicht belastet werden, und personenbezogene Daten meiden, einschließlich allem, was mit identifizierbaren Käufern, Rezensenten oder Filialmitarbeitern verknüpft ist, über das hinaus, was öffentlich gelistet ist. Urheberrechtlich geschützte Medien wie Targets Produktfotografie nicht weiterverbreiten, und wer die Daten kommerziell nutzen möchte, sollte Genehmigung oder eine offizielle Vereinbarung einholen, statt Schweigen als Zustimmung zu werten.

Dieser Leitfaden ist bewusst auf öffentliche Such- und Produktseiten beschränkt, da das die Grenze ist, die die Arbeit verteidigbar macht. Er deckt nichts hinter einem Login, konto- oder bestellbezogene Daten, Zahlungsdetails oder Versuche, Authentifizierung oder ein CAPTCHA zu umgehen, zu dem man nicht berechtigt ist, ab. Target betreibt ein Affiliate- und Partnerprogramm und bietet offiziellen Daten-Feeds für genehmigte Partner, und das ist der richtige Kanal für große Volumen, garantierte Struktur oder kommerzielle Rechte. Wenn ein Projekt mehr als öffentliche Katalogdaten benötigt, ist eine offizielle Vereinbarung der richtige Weg, kein clevererer Scraper.

Zusammenfassung

Wichtigste Erkenntnisse

  • Targets Daten sind öffentlich, aber JavaScript-gerendert. Das Produktraster existiert erst nach dem Ausführen der Seitenskripte, daher gibt eine einfache Anfrage eine leere Liste zurück.
  • Rendering und eine vertrauenswürdige IP werden zusammen benötigt. Die Crawling API rendert die Seite hinter einer Residential-IP in einem Aufruf, mit dem JavaScript-Token plus ajax_wait und page_wait.
  • Auf data-test-Attribute setzen. Titel, Preis, TCIN, Bewertung, Bewertungsanzahl und Verfügbarkeit aus Targets data-test- und data-ref-Markern abbilden, wobei damit zu rechnen ist, dass generierte Klassennamen sich verschieben.
  • Mit dem Nao-Offset paginieren. Target paginiert Ergebnisse in Chargen von 24 über den Nao-Parameter; stoppen, wenn kein aktivierter Weiter-Button mehr vorhanden ist, und von einer gemeinsamen Feldliste in JSON und CSV exportieren.
  • Bei öffentlichen Daten bleiben. Targets Bedingungen und robots.txt respektieren, für lizenzierte oder Massendaten offizielle Partner-Feeds bevorzugen und niemals Konten, Bestellungen oder personenbezogene Informationen berühren.

Häufig gestellte Fragen

Warum liefert eine einfache Anfrage keine Produkte von Target?

Target rendert sein Suchraster clientseitig: Die erste HTML-Nutzlast ist eine Hülle, und die Produktkarten erscheinen erst nach dem Ausführen des JavaScript der Seite. Eine rohe requests.get()-Anfrage parst diese Hülle und findet nichts, weshalb der Legacy-DIY-Versuch eine leere Liste zurückgab. Das Rendern der Seite über die Crawling API hinter einer vertrauenswürdigen IP löst sowohl das JavaScript- als auch das Blocking-Problem, weshalb der Scraper hier seine Anfragen darüber leitet.

Was ist eine TCIN und wie bekommt man sie?

TCIN ist Targets interne Produktkennung, das Äquivalent einer SKU auf der Site. Sie erscheint in jeder Produkt-URL nach dem /A--Marker, zum Beispiel bedeutet /A-88228365 TCIN 88228365. Der extract_tcin-Helfer liest sie direkt aus dem Produktlink, sodass man einen stabilen Schlüssel für jedes Element ohne eine zusätzliche Anfrage erhält, was bei der Deduplizierung oder dem Verbinden von Datensätzen über die Zeit praktisch ist.

Wie scrapt man eine bestimmte Target-Kategorie statt einer Suche?

Den Scraper auf die Kategorie-URL statt auf eine Such-URL richten. Das Produktraster, die data-test-Selektoren und der Nao-Paginierungsparameter verhalten sich auf Kategorieseiten genauso, daher übertragen sich derselbe Parser und dieselbe Paginierungsschleife. Einfach die base_url in main auf die gewünschte Kategorie ändern und den Rest des Skripts wie er ist lassen.

Wie liest man die Produktverfügbarkeit?

Auf Such- und Kategoriekarten zeigt ein nicht vorrätiger Artikel einen Ausverkauft-Marker, den der Scraper mit einem [data-test="soldOut"]-Check erkennt und als "Out of stock" aufzeichnet, standardmäßig "In stock". Für eine präzise, filialspezifische Verfügbarkeitsangabe die einzelne Produktseite scrapen, wo Target ein klares Auf-Lager- oder Nicht-Vorrätig-Badge und Versand- oder Abholoptionen mit Standortbindung anzeigt.

Warum sind manche Bewertungen in der Ausgabe null?

Ein null-Wert für Bewertung oder Bewertungsanzahl bedeutet, dass dieses Produkt noch keine Bewertungen hat, daher rendert Target die maskierte Bewertungsleiste nicht auf seiner Karte. Der extract_rating-Helfer liest den Score aus der CSS-Breite der Leiste, und wenn die Leiste fehlt, gibt er None zurück. Das ist erwartetes Verhalten, kein Selektor-Fehler; neue oder wenig besuchte Listings haben schlicht nichts anzuzeigen.

Wie vermeidet man Blockierungen beim Scrapen von Target?

Die Anfragerate pro IP niedrig halten, eine Verzögerung zwischen Seiten und Abfragen einbauen und über rotierende Residential-IPs leiten, damit keine einzelne Adresse ein Rate-Limit auslöst. Die Crawling API verwaltet Rotation, einen vertrauenswürdigen IP-Pool und CAPTCHA-Behandlung; wer seinen eigenen Stack aufbaut, sollte dort investieren. Die cb_status (legacy pc_status)-Codes beobachten, die die API zurückgibt, und zurückrudern, wenn Fehler auftreten.

Jetzt loslegen

Crawlen Sie jede Website im großen Maßstab, ohne gegen die Infrastruktur zu kämpfen.

Crawlbase übernimmt Proxys, Fingerprints und CAPTCHAs, damit Ihr Team Datenpipelines ausliefert, statt Crawl-Infrastruktur zu pflegen. 1.000 Anfragen kostenlos, keine Karte erforderlich.

Self-Service · Kein Verkaufsgespräch erforderlich · Enterprise-Crawl-Volumen verfügbar