Jeder Scraper steht und fällt mit einer einzigen Entscheidung: wie er das gewünschte Element in einer Seite voller Markup lokalisiert. Trifft man die falsche Wahl, bricht das Skript beim nächsten Mal, wenn die Website einen Klassennamen leicht ändert oder ein Wrapper verschoben wird; trifft man die richtige, läuft derselbe Parser monatelang. Die beiden Abfragesprachen, auf die man hier zurückgreift, sind XPath und CSS-Selektoren für Web Scraping, und die meisten funktionierenden Scraper verwenden eine Mischung aus beiden, anstatt eine Seite zu wählen.

Dieser Leitfaden ist eine praktische Selektorreferenz. Wir gehen CSS-Selektoren und XPath nebeneinander durch, zeigen den äquivalenten Ausdruck in jeder Sprache für dieselben Elemente, führen beides gegen echte Python-Bibliotheken aus und behandeln, wann eine Sprache die andere klar schlägt. Am Ende wissen Sie, welche Sie auf einer gegebenen Seite greifen, und wie Sie Selektoren schreiben, die ein Redesign überleben, anstatt daran zu zerbrechen.

Die beiden Sprachen auf einen Blick

CSS-Selektoren sind die Muster, die Sie bereits in Stylesheets schreiben: .price, #header, div > span. Browser werten sie ständig aus, jede Scraping-Bibliothek unterstützt sie, und sie lesen sich für die häufigen Fälle sauber. Sie sind der kürzeste Weg zu "dieses Element greifen", wenn eine Seite sinnvolle Klassen und IDs hat.

XPath ("XML Path Language") ist eine vollständige Abfragesprache zum Navigieren in einem Dokumentbaum. Es behandelt die Seite als Knoten, die Sie in jede Richtung gehen können: zu Kindern hinunter, zu Vorfahren hinauf, zu Geschwistern seitwärts. Es kann auf Textinhalt matchen, mit booleschen Bedingungen filtern und Prädikate auf Weisen kombinieren, die CSS einfach nicht ausdrücken kann. Diese Macht kostet etwas Ausführlichkeit, zahlt sich aber auf unübersichtlichen oder tief verschachtelten Seiten aus.

Beide zielen auf dasselbe DOM ab. Der Unterschied liegt in Reichweite und Ergonomie: CSS ist knapp und vertraut, XPath ist präzise und ausdrucksstark. Zu wissen, wo jede Sprache aufhört, ist das ganze Spiel.

CSS-Selektoren, Feld für Feld

CSS-Selektoren lokalisieren Elemente nach Tag, Klasse, ID, Attribut, Beziehung und Position. Hier sind die Bausteine, die Sie täglich verwenden werden, mit dem Markup, das jeder anspricht.

Tag, Klasse und ID. Die drei häufigsten Ausgangspunkte. Ein bloßer Tag-Name matcht jedes Element dieses Typs, ein führender Punkt matcht eine Klasse, und ein führendes Rautezeichen matcht eine ID.

css
a                  /* every anchor on the page */
.product-title     /* any element with class product-title */
#product-price     /* the element with id product-price */
span.price-label   /* span elements that also have class price-label */

Nachkomme vs. direktes Kind. Ein Leerzeichen bedeutet "irgendwo darin, wie auch immer tief". Ein > bedeutet "direktes Kind nur", eine Ebene darunter. Der Unterschied ist wichtig, wenn ein Layout dasselbe Tag in mehreren Tiefen verschachtelt und Sie nur das unmittelbare wollen.

css
div.price-container span      /* any span inside, at any depth */
div.price-container > span    /* only spans that are direct children */

Attribute. Eckige Klammern matchen auf jedes Attribut, nicht nur Klasse und ID. Exaktes Matchen mit [attr=val], Teilstring mit [attr*=val], Präfix mit [attr^=val], Suffix mit [attr$=val]. Attributselektoren sind oft Ihr stabilster Anker, da Datenattribute sich weniger ändern als visuelle Klassen.

css
a[role='link']            /* anchors with role exactly "link" */
[data-testid='price']     /* any element with that test id */
a[href^='/product/']      /* anchors whose href starts with /product/ */

Position. Pseudo-Klassen wählen nach Platz in der Geschwisterreihenfolge aus. :first-child, :last-child und das Arbeitstier :nth-of-type(n) ermöglichen es Ihnen, das n-te Element eines gegebenen Tags zu greifen, was die Methode ist, um "die zweite Zeile" oder "das vierte Listenelement" aus einem sich wiederholenden Block herauszuziehen.

css
.product-list li:first-child       /* first item in the list */
ul.specs li:nth-of-type(3)         /* the third li */
table tr:nth-of-type(2) td         /* cells in the second row */

Dieser Satz deckt den überwältigenden Anteil echter Extraktionsarbeit ab. Wo CSS an seine Grenzen stößt, ist das Matchen auf den Text, den ein Element enthält, und das Gehen nach oben im Baum von einem bekannten Knoten. Dafür greifen Sie auf XPath zurück.

XPath, Feld für Feld

XPath drückt einen Pfad durch das Dokument aus. Ein führendes // bedeutet "überall im Baum suchen", ein einzelnes / bedeutet "direktes Kind", und eckige Klammern halten Prädikate, die die gematchten Knoten filtern. Hier sind dieselben Arten von Zielen in XPath geschrieben.

Tag und Nachkomme. Der doppelte Schrägstrich ist Ihr alltäglicher Öffner; er findet passende Elemente in jeder Tiefe.

xpath
//div                         (: every div on the page :)
//div[@class='price-container']/span   (: direct span children :)

Prädikate auf Attributen. Innerhalb der Klammern testen Sie Attribute mit @. Exaktes Matchen ist [@class='x']; für Klassen, die mehrere durch Leerzeichen getrennte Werte tragen, ist contains(@class, 'x') sicherer, da es matcht, wenn x einer von mehreren ist.

xpath
//*[@id='product-price']                  (: by id :)
//*[contains(@class, 'product-title')]    (: class among many :)
//a[@href]                                (: any anchor that has an href :)

Text-Matching. Dies ist XPaths Hauptmerkmal. Sie können ein Element anhand des enthaltenen Texts auswählen, exakt mit text()='...' oder locker mit contains(text(), '...'). CSS hat nichts Gleichwertiges.

xpath
//button[text()='Add to Cart']
//span[contains(text(), 'In stock')]
//label[normalize-space()='Email address']

Position. XPath-Indizes sind 1-basiert und leben in Prädikaten. Sie können auch Funktionen wie last() und position() verwenden, um vom Ende oder einem Bereich zu greifen.

xpath
(//div[@class='product'])[1]      (: first matching product :)
//ul[@class='specs']/li[3]        (: the third li :)
//ul/li[last()]                   (: the final li :)

Achsen. Der wahre Kraftzug. Achsen ermöglichen es Ihnen, sich in Richtungen zu bewegen, die CSS nicht kann: following-sibling, preceding-sibling, parent und ancestor. Der klassische Fall ist ein Label-Wert-Paar, bei dem Sie den Label-Text kennen und den Wert daneben wollen.

xpath
(: the value cell next to the "Founded" label :)
//th[text()='Founded']/following-sibling::td

(: walk up from a price to its product card :)
//span[@class='price']/ancestor::div[@class='card']

Diese letzten zwei sind die Art von Abfrage, die in CSS überhaupt keine saubere Entsprechung hat, was genau der Grund ist, warum XPath im Werkzeugkasten bleibt.

Nebeneinander: dasselbe Element, beide Wege

Das Nebeneinanderstellen der Sprachen macht die Kompromisse konkret. Bei den häufigen Zielen sind die beiden nahezu gleichwertig, und CSS liest sich in der Regel kürzer.

text
Goal                      CSS                          XPath
all anchors               a                            //a
class match               .product-title               //*[contains(@class,'product-title')]
id match                  #product-price               //*[@id='product-price']
tag + class               span.price-label             //span[@class='price-label']
descendant                .box span                    //*[@class='box']//span
direct child              .box > span                  //*[@class='box']/span
attribute exact           a[role='link']               //a[@role='link']
nth of type               li:nth-of-type(3)            //li[3]
text match                (not possible)               //button[text()='Buy']
walk up the tree          (not possible)               //span/ancestor::div[@class='card']

Das Muster ist klar: Bei Tag, Klasse, ID, Attribut und Position ist die Wahl meist Geschmackssache, und CSS gewinnt bei der Kürze. Die letzten zwei Zeilen sind, wo XPath allein steht.

Beides in Python ausführen

Theorie reicht nur so weit; hier ist, wie jede Sprache im Code aussieht. Wir verwenden parsel (die Selektorbibliothek, auf der Scrapy aufgebaut ist), weil es sowohl CSS als auch XPath gegen dasselbe geparste Dokument spricht, sodass Sie sie Zeile für Zeile vergleichen können. BeautifulSoup und lxml sind die anderen häufigen Wahlmöglichkeiten, danach erwähnt.

bash
python -m venv selectors_env
source selectors_env/bin/activate

pip install parsel

Laden Sie etwas Markup einmal und fragen Sie es dann auf beide Arten ab. Beachten Sie, dass parsels .css() und .xpath() beide eine Selektorliste zurückgeben, sodass das Zugriffsmuster unabhängig von der Sprache identisch ist.

python
from parsel import Selector

html = """
<div class="card">
  <h2 class="product-title">Wireless Mouse</h2>
  <span class="price">$24.99</span>
  <a role="link" href="/product/mouse">Details</a>
</div>
"""

sel = Selector(text=html)

# CSS: concise and familiar
title = sel.css("h2.product-title::text").get()
price = sel.css("span.price::text").get()
link  = sel.css("a[role='link']::attr(href)").get()

# XPath: the same three fields
title = sel.xpath("//h2[@class='product-title']/text()").get()
price = sel.xpath("//span[@class='price']/text()").get()
link  = sel.xpath("//a[@role='link']/@href").get()

print(title, price, link)

Bei BeautifulSoup ist der CSS-Pfad soup.select_one("span.price") und soup.select(...) für mehrere; es unterstützt XPath nicht nativ. Wenn Sie XPath speziell benötigen, ist lxml das Standardwerkzeug: tree.xpath("//span[@class='price']/text()") auf einem geparsten lxml.html-Dokument. parsel ist die bequeme Mitte, weil es Ihnen beide APIs auf einem Objekt gibt.

CSS wird intern zu XPath kompiliert

Bibliotheken wie parsel und lxml übersetzen einen CSS-Selektor in XPath, bevor sie ihn ausführen (über das cssselect-Paket). Deshalb hat alles, was Sie in CSS ausdrücken können, eine XPath-Entsprechung, aber nicht umgekehrt: Text-Matching und Aufwärts-Achsen haben keine CSS-Form zum Übersetzen. Wenn ein CSS-Selektor nicht sagen kann, was Sie meinen, ist der Wechsel zu XPath der natürliche nächste Schritt, keine Umgehung.

Wann XPath gewinnt

Greifen Sie auf XPath zurück, wenn die Seite zurückschlägt. Drei Situationen machen es zur klaren Wahl.

  • Sie müssen auf Text matchen. "Der Button, der 'In den Warenkorb' sagt" oder "die Zeile, deren Label 'Gegründet' lautet" können nur durch Inhalt ausgedrückt werden. //button[text()='Add to Cart'] und contains(text(), ...) haben keine CSS-Entsprechung.
  • Sie müssen den Baum nach oben gehen. Wenn Sie ein Blatt zuverlässig finden können, wie einen eindeutigen Preis, aber das gewünschte Element sein Container ist, klettert ancestor::div[@class='card'] zurück nach oben. CSS geht nur hinunter und quer, niemals hinauf.
  • Sie benötigen zusammengesetzte Bedingungen. XPath-Prädikate kombinieren mit and und or: //div[@class='item' and @data-available='true'], oder gleichzeitiges Filtern nach Position und Attribut. Bedingungen auf diese Weise zu stapeln ist in CSS umständlich oder unmöglich.

Das Label-und-Wert-Muster ist das, auf das Sie am häufigsten treffen. In einer Spezifikationstabelle oder Profil-Sidebar sitzt das gewünschte Feld in einer Zelle neben einem stabilen Label, während seine eigene Klasse generisch oder abwesend ist. Das Verankern am Label-Text und seitliches Schreiten mit following-sibling ist weit dauerhafter als das Zählen von :nth-of-type-Positionen, die sich verschieben, wenn ein Feld hinzugefügt oder entfernt wird.

Wann CSS gewinnt

Für die alltägliche Mehrheit ist CSS der bessere Standard. Es ist kürzer, lesbarer, und die Syntax ist eine, die die meisten Entwickler bereits von der Frontend-Arbeit mitbringen, sodass ein Teamkollege Ihre Selektoren überprüfen kann, ohne eine zweite Sprache zu lernen. Auf einer gut strukturierten Seite mit sinnvollen Klassen und IDs sagt .product-card .price alles, was Sie benötigen, in weniger Raum als sein XPath-Zwilling.

CSS passt auch natürlich zu Browser-Automatisierungstools. Wenn Sie einen Headless-Browser steuern und dynamischen Inhalt scrapen, tragen dieselben CSS-Selektoren, die Sie in document.querySelector schreiben würden, direkt über, was Ihren Selektorwortschatz über die statischen Parse- und Live-DOM-Teile eines Projekts hinweg konsistent hält. Für einfache, schnelle, wiederholte Extraktion auf einem ordentlichen Layout ist CSS das richtige Werkzeug, und Sie eskalieren nur zu XPath, wenn CSS das Ziel wirklich nicht ausdrücken kann.

Crawlbase Crawling API

Selektoren sind unvermeidlich, wenn Sie rohes HTML selbst parsen, aber sie sind nicht immer Ihre Aufgabe zu schreiben. Die Scraper API parst häufige Seitentypen, wie Produktseiten, Suchergebnisse und Rezensionen, automatisch in strukturiertes JSON, sodass Sie bei unterstützten Zielen XPath und CSS vollständig überspringen und einfach Felder aus der Antwort lesen. Wo Sie benutzerdefiniertes Parsing benötigen, kombinieren Sie es mit gerendertem HTML und parsen Sie mit den obigen Selektoren. Starten Sie im kostenlosen Tarif.

Selektoren schreiben, die nicht brechen

Das Schwierige beim Scraping ist nicht das Wählen einer Sprache; es ist das Schreiben von Selektoren, die das nächste Deploy der Website überleben. Dieselben Robustheitsregeln gelten für XPath und CSS.

  • Stabile Attribute gegenüber visuellen Klassen bevorzugen. Gehashte oder Utility-Klassen wie css-1x7a9q oder mt-4 werden generiert und ändern sich oft. Ein data-testid, eine id, ein itemprop oder eine ARIA-role ist weitaus wahrscheinlicher, einen Restyling-Vorgang zu überleben. Verankern Sie daran, wenn sie vorhanden sind.
  • Lange, tiefe Ketten vermeiden. Ein Selektor wie body > div > div > section > div:nth-child(2) > ul > li kodiert das gesamte Layout, sodass jeder irgendwo entlang dieses Pfads hinzugefügte Wrapper es bricht. Matchen Sie stattdessen den nächsten bedeutsamen Container und einen stabilen Hook.
  • Nicht auf fragile Positionen verlassen. :nth-of-type(4) setzt voraus, dass die Anzahl sich nie ändert. Wenn ein stabiles Label oder Attribut verfügbar ist, verankern Sie daran und navigieren Sie relativ (was XPath-Achsen auszeichnet), anstatt einen Index fest zu codieren.
  • contains für mehrwertige Klassen verwenden. Ein Element mit class="btn btn-primary active" matcht nicht exakt auf [@class='btn-primary']. Verwenden Sie contains(@class, 'btn-primary') in XPath, oder den einfachen .btn-primary-Klassenselektor in CSS, der bereits eine Klasse unter mehreren matcht.
  • Laut statt still scheitern. Verpacken Sie die Extraktion so, dass ein fehlendes Feld None zurückgibt, anstatt abzubrechen, und protokollieren Sie dann, welcher Selektor leer zurückkam. Das verwandelt eine Seitenänderung von einem mysteriösen leeren Datensatz in ein klares Signal, welcher Selektor Wartung benötigt.

Behandeln Sie Selektoren als Code, der Pflege benötigt. Markup driftet, und ein Scraper, der letztes Quartal sauber lief, wird schließlich leere Felder zurückgeben. Die Lösung ist fast immer, das Live-Element in den Dev-Tools erneut zu überprüfen und den Selektor zu verfeinern, nicht den Scraper neu aufzubauen. Für das breitere Setup geht der Leitfaden zum Scrapen einer Website mit Python durch Abrufen, Parsen und Speichern von Anfang bis Ende, und diese Selektormuster fügen sich direkt in diesen Ablauf ein.

Selektoren ganz überspringen

Manchmal ist der beste Selektor kein Selektor. Wenn Ihr Ziel ein häufiger Seitentyp ist, gibt die Crawling API direkt geparste JSON-Daten zurück, sodass es nichts zu selektieren gibt. Für alles andere rufen und parsen Sie noch selbst, und das gerenderte HTML, das Sie parsen, kann von der Crawling API kommen, wenn eine Seite clientseitig gerendert oder gesichert ist. In jedem Fall sind die Selektorkenntnisse hier das, was rohes Markup in saubere Datensätze verwandelt, und beide Sprachen zu kennen bedeutet, dass Sie nie stecken bleiben, weil eine von ihnen ein Element nicht erreichen kann.

Zusammenfassung

Wichtigste Erkenntnisse

  • Beide zielen auf dasselbe DOM ab. CSS-Selektoren sind knapp und vertraut; XPath ist ausführlicher aber ausdrucksstärker. Die meisten echten Scraper verwenden eine Mischung.
  • CSS deckt Tag, Klasse, ID, Attribut und Position ab mit kurzen, lesbaren Mustern: .class, #id, div > span, [attr=val], :nth-of-type(n).
  • XPath tut, was CSS nicht kann: auf Text matchen mit text() und contains(), den Baum nach oben gehen mit ancestor, seitwärts schreiten mit following-sibling und Bedingungen mit and/or kombinieren.
  • Beides in Python mit parsel ausführen (.css() und .xpath() auf einem Objekt); BeautifulSoup ist nur CSS, lxml ist die erste Wahl für XPath.
  • Robustheit schlägt Cleverness. Stabile Attribute bevorzugen, tiefe Ketten und fragile Indizes vermeiden, contains für mehrwertige Klassen verwenden und laut scheitern, wenn ein Feld fehlt.
  • Selektoren können übersprungen werden bei unterstützten Seitentypen mit der automatischen Parsierung der Crawling API, und handgeschriebene Selektoren für benutzerdefinierte Ziele reservieren.

Häufig gestellte Fragen

Was ist für Anfänger besser, XPath oder CSS-Selektoren?

CSS-Selektoren, in den meisten Fällen. Die Syntax überschneidet sich mit dem, was Sie bereits vom Styling von Seiten kennen, liest sich sauber für Tag-, Klassen-, ID- und Attributziele, und jede Scraping-Bibliothek unterstützt sie. Lernen Sie XPath danach, speziell für die Dinge, die CSS nicht kann: Matchen auf Textinhalt und Navigieren nach oben oder seitwärts durch den Baum.

Werden XPath und CSS-Selektoren von allen Scraping-Bibliotheken unterstützt?

Die meisten unterstützen mindestens eine und viele unterstützen beide. parsel und Scrapy verarbeiten CSS und XPath auf demselben Objekt, lxml ist für XPath gebaut, und Selenium und Playwright akzeptieren beide. BeautifulSoup ist die bemerkenswerte Ausnahme: Es unterstützt CSS durch .select(), hat aber kein natives XPath. Überprüfen Sie die Dokumentation Ihrer Bibliothek, bevor Sie sich auf einen Selektorstil festlegen.

Kann ein CSS-Selektor ein Element anhand seines Texts matchen?

Nein. CSS hat keine Möglichkeit, ein Element anhand des enthaltenen Texts auszuwählen; es matcht nur auf Tags, Klassen, IDs, Attribute und Position. Wenn Sie "den Button, der 'In den Warenkorb' sagt" oder "die Zelle neben dem Label 'Gegründet'" benötigen, ist das genau der Fall für XPaths text() und contains(text(), ...), die keine CSS-Entsprechung haben.

Ist XPath schneller als CSS-Selektoren?

In den meisten Scraping-Arbeiten ist der Unterschied vernachlässigbar, da Bibliotheken CSS oft intern in XPath übersetzen, bevor sie es ausführen. Wählen Sie basierend auf Ausdrucksstärke und Lesbarkeit statt auf Rohgeschwindigkeit. Wenn ein CSS-Selektor klar sagt, was Sie benötigen, verwenden Sie ihn; greifen Sie auf XPath zurück, wenn Sie Text-Matching, Aufwärts-Navigation oder zusammengesetzte Bedingungen benötigen, die CSS nicht ausdrücken kann.

Wie schreibe ich Selektoren, die nicht brechen, wenn die Website sich ändert?

Verankern Sie an stabilen Haken wie id, data-testid, itemprop oder ARIA-Rollen statt an generierten visuellen Klassen. Halten Sie Selektoren kurz, indem Sie den nächsten bedeutsamen Container matchen, anstatt die vollständige Abstammung zu verfolgen, vermeiden Sie hart kodierte Positionsindizes, wo ein stabiles Label existiert, und verwenden Sie contains für mehrwertige Klassen. Dann scheitern Sie laut bei fehlenden Feldern, damit eine Markup-Änderung als klares Signal erscheint, nicht als stilles Leerzeichen.

Wann sollte ich Selektoren ganz überspringen?

Wenn Ihr Ziel ein häufiger Seitentyp ist, den ein Auto-Parsing-Dienst bereits versteht. Die Crawling API gibt strukturiertes JSON für unterstützte Ziele wie Produktseiten und Suchergebnisse zurück, sodass es kein HTML zu parsen und keinen Selektor zu pflegen gibt. Halten Sie handgeschriebenes XPath und CSS für benutzerdefinierte Seiten oder Felder, die der Auto-Parser nicht abdeckt.

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