Geonode logo
Geonode Team

Geonode Team

Aktualisiert: 7. Oktober 2026

Veröffentlicht: 02.09.2026

XPath-Spickzettel: Leitfaden mit Beispielen

XPath ist eine Abfragesprache zum Durchsuchen von XML- und HTML-Dokumenten. Sie verfügt über einen kleinen Kern und eine Vielzahl von Möglichkeiten, sie falsch anzuwenden. Dies ist eine Referenz, die so aufgebaut ist, wie Sie sie tatsächlich benötigen: zuerst die Syntax, dann die Funktionen, die man kennen sollte, anschließend die Muster, die immer wieder vorkommen, und schließlich die Fallstricke. Alles hier bezieht sich auf XPath 1.0, das von Browsern, Selenium und den meisten Parsing-Bibliotheken implementiert wird.

Ein kurzer Hinweis dazu, wer diesen Beitrag verfasst hat: Wir sind Geonode und verkaufen Proxys an Personen, die Daten extrahieren; daher ist XPath eher ein angrenzendes Thema als Teil unseres Geschäfts. Der wichtige Hinweis lautet: Ein Selektorproblem und ein Proxy-Problem sehen völlig unterschiedlich aus, und sie zu verwechseln kostet Stunden an Zeit – eine blockierte Anfrage führt zu einer Challenge-Seite oder einem Fehlerstatus, während ein fehlerhafter Ausdruck eine einwandfreie Seite und ein leeres Ergebnis liefert. Wenn der HTML-Code vorhanden ist und Ihr XPath nichts findet, ist das Netzwerk in Ordnung und diese Seite ist die richtige Anlaufstelle.

Die grundlegende Syntax

AusdruckWählt aus
/html/body/divAbsoluter Pfad vom Stammverzeichnis
//divBeliebige „div“-Elemente an beliebiger Stelle im Dokument
//div/p„p“-Elemente, die direkte Kinder eines „div“-Elements sind
//div//p„p“-Elemente in beliebiger Tiefe innerhalb eines „div“-Elements
.Der aktuelle Kontextknoten
..Der übergeordnete Knoten des Kontextknotens
*Beliebiges Element
@hrefDas Attribut „href“
//@hrefJedes Attribut „href“ im Dokument
text()Textknoten-Kinder des Kontextknotens
node()Beliebiger Knoten, einschließlich Text und Kommentare
//a | //linkVereinigung – alles, was mit einem der beiden Ausdrücke übereinstimmt

Der Unterschied zwischen / und // muss verinnerlicht werden. Ein einzelner Schrägstrich bedeutet „direktes Kind“; ein doppelter Schrägstrich bedeutet „Nachkomme in beliebiger Tiefe“. //div/p übersieht einen in ein section eingeschlossenen Absatz; //div//p findet ihn.

Absolute Pfade – /html/body/div[2]/div[1]/span – sind das, was die Browserfunktion „XPath kopieren“ erzeugt und was bei der nächsten Neugestaltung nicht mehr funktioniert. Beginnen Sie lieber mit etwas Identifizierbarem und navigieren Sie relativ.

Prädikate

Eckige Klammern filtern eine Knotenmenge. Hier findet der Großteil der nützlichen Arbeit statt.

AusdruckWählt aus
//div[1]Den ersten „div“ unter seinen Geschwistern pro übergeordnetem Knoten
(//div)[1]Den ersten „div“ im gesamten Dokument
//div[last()]Den letzten „div“ unter seinen Geschwistern
//div[position() < 4]Die ersten drei
//a[@href]Links, die ein „href“-Attribut haben
//a[@href='/about']Links mit genau diesem „href“
//div[@class and @id]Elemente mit beiden Attributen
//p[text()]Absätze mit mindestens einem untergeordneten Textknoten
//div[p]„div“-Elemente, die mindestens ein untergeordnetes „p“-Element enthalten
//div[not(@hidden)]„div“-Elemente ohne ein „hidden“-Attribut
//td[.='42'][@class='qty']Zwei Prädikate, die nacheinander angewendet werden

** „//div[1]“ im Vergleich zu „(//div)[1]“ ist die häufigste Verwechslungsquelle bei XPath.** Das erste Prädikat wird pro übergeordnetem Element angewendet, wählt also den ersten „div“ unter jedem übergeordneten Element aus, das einen solchen Knoten enthält – potenziell viele Knoten. Das zweite sammelt alle div-Elemente in einer Knotenmenge in Dokumentreihenfolge und wählt den ersten aus, was genau einem Knoten entspricht. Beide sind nützlich; sie sind jedoch nicht austauschbar.

Prädikate werden verkettet, und jedes wird auf das Ergebnis des vorherigen angewendet. „//td[@class='price'][1]“ bedeutet „der erste unter den Zellen mit der Klasse price“, von links nach rechts gelesen.

Achsen

Achsen dienen der Navigation relativ zum Kontextknoten. Die meisten Benutzer verwenden drei Achsen und benötigen gelegentlich auch die anderen.

AchseAuswahl
child::Direkte Kinder – die Standardeinstellung, wird meist weggelassen
descendant::Alle Nachkommen in beliebiger Tiefe
parent::Der übergeordnete Knoten
ancestor::Alle Vorfahren bis zur Wurzel
ancestor-or-self::Vorfahren plus der Knoten selbst
following-sibling::Spätere Geschwister
preceding-sibling::Frühere Geschwister
following::Alles, was in der Dokumentreihenfolge danach kommt, ausgenommen Nachkommen
preceding::Alles davor, ohne Vorfahren
attribute::Attribute – abgekürzt als „@“
self::Der Knoten selbst

Vier davon sind umgekehrte Achsen – „ancestor“, „ancestor-or-self“, „preceding“ und „preceding-sibling“ – und auf diesen verläuft die Positionsnummerierung rückwärts. „preceding-sibling::p[1]“ ist der nächstgelegene vorhergehende Absatz, nicht der erste im Dokument. Setzen Sie die Ausdrücke in Klammern, um stattdessen die Reihenfolge im Dokument zu erhalten. Wir haben dies ausführlich unter XPath preceding-sibling behandelt.

following und preceding sind viel umfassender und viel langsamer als ihre Entsprechungen für Geschwisterelemente und schließen jeweils Vorfahren bzw. Nachkommen aus. Greifen Sie nur dann darauf zurück, wenn die Beziehung wirklich locker ist.

String-Funktionen

Die Arbeitspferde.

FunktionFunktion
contains(a, b)True, wenn a die Teilzeichenfolge b enthält
starts-with(a, b)True, wenn a mit b beginnt
normalize-space(s)Entfernt und komprimiert interne Leerzeichen
string-length(s)Zeichenanzahl
substring(s, start, len)Teilzeichenfolge, 1-indiziert
substring-before(a, b)Alles vor dem ersten Vorkommen von b
substring-after(a, b)Alles nach dem ersten Vorkommen von b
translate(s, from, to)Zeichenweise Ersetzung
concat(a, b, ...)Verknüpft Zeichenfolgen
string(node-set)Zeichenfolgenwert nur des ersten Knotens

Drei Hinweise, die echte Fehler verhindern.

** „substring()“ ist 1-indiziert.** „substring('hello', 1, 3)“ gibt „hel“ zurück. Das geht jedem einmal schief.

** „normalize-space()“ sollte Ihr Standard-Wrapper für jeden Textvergleich sein.** Echtes HTML wird „pretty-printed“, daher ist der Zeichenfolgenwert einer Zelle häufig „"\n In stock\n"“ statt „"In stock"“. Ohne Argument wirkt sich die Funktion auf den Kontextknoten aus.

Es gibt in XPath 1.0 weder „ends-with()“ noch „lower-case()“ noch reguläre Ausdrücke. Für die Groß-/Kleinschreibung ist „translate()“ mit expliziten Buchstaben die Standard-Umgehungslösung. Serverseitige Bibliotheken wie lxml unterstützen EXSLT-Erweiterungen einschließlich „re:test()“; Browser und Selenium tun dies nicht.

Numerische und boolesche Funktionen

FunktionFunktion
count(node-set)Anzahl der Knoten
position()Position des Kontextknotens
last()Größe der Kontextknotenmenge
number(s)Konvertiert in eine Zahl
sum(node-set)Summiert die numerischen Werte
round(), floor(), ceiling()Wie bezeichnet
not(expr)Boolesche Negation
boolean(expr)Konvertiert in einen Booleschen Wert
true(), false()Literale Boolesche Werte

Vergleichsoperatoren sind =, !=, <, >, <=, >=, mit and und or zur Kombination. Beachten Sie, dass in XML-Kontexten < als &lt; maskiert werden muss, weshalb Sie manchmal Ausdrücke sehen, die mit position() &lt; 4 geschrieben sind.

Eine Feinheit, die man kennen sollte: Der Vergleich einer Knotenmenge mit einem Wert ist ein existentieller Test. „//p = 'Price'“ ist wahr, wenn irgendein Absatz dem Wert „Price“ entspricht. Das ist oft genau das, was man innerhalb eines Prädikats möchte, aber fast nie auf der obersten Ebene.

Häufig vorkommende Muster

Die Ausdrücke, die wirklich funktionieren.

Eine Klasse korrekt abgleichen — „contains(@class, 'btn')

“ passt auch auf „btn-primary

“ und „unbtn

“:

//div[contains(concat(' ', normalize-space(@class), ' '), ' btn ')]

Einen Wert anhand seiner Bezeichnung finden — die häufigste Anforderung bei der Extraktion:

//dt[normalize-space()='Price']/following-sibling::dd[1]
//th[normalize-space()='Weight']/following-sibling::td[1]
//td[preceding-sibling::td[1]='SKU']

Eine Zeile anhand einer Zelle finden und dann eine andere Spalte auswählen:

//tr[td[normalize-space()='SKU-1234']]/td[3]

**Einen Container anhand seines Inhalts finden:

//div[contains(@class,'card')][.//span[contains(., 'Sold out')]]

Das erste Element nach einer Überschrift finden:

//h2[normalize-space()='Specifications']/following-sibling::table[1]

Textabgleich ohne Berücksichtigung der Groß-/Kleinschreibung:

//p[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                          'abcdefghijklmnopqrstuvwxyz'), 'price')]

Ausschließen statt einbeziehen – oft übersichtlicher:

//tr[not(contains(@class,'header'))]
//li[not(contains(normalize-space(),'Advertisement'))]

Eines von zwei Elementtypen abgleichen:

//*[self::button or self::a][normalize-space()='Continue']

Leere Werte überspringen:

//td[string-length(normalize-space()) > 0]

Ein Attribut aus einem gefundenen Element extrahieren:

//a[normalize-space()='Download']/@href

Die Fallstricke

Geordnet nach der Häufigkeit, mit der sie den Anwendern Zeit kosten.

Bei der Konvertierung von Knotensätzen in Zeichenketten wird nur der erste Knoten berücksichtigt. contains(//p, 'Price') konvertiert den gesamten Knotensatz //p in eine Zeichenkette, indem der erste Absatz übernommen und der Rest ignoriert wird. Wenden Sie stattdessen das Prädikat pro Knoten an: //p[contains(., 'Price')]. Dies ist der mit Abstand häufigste XPath-Fehler.

** „.“ und „text()“ sind nicht dasselbe.** Der String-Wert eines Elements ist die Verkettung aller seiner untergeordneten Textknoten; „text()“ gibt nur direkte Textknoten-Kinder zurück, und bei der String-Konvertierung wird der erste davon berücksichtigt. Verwenden Sie „.“, es sei denn, Sie möchten verschachtelte Inhalte gezielt ausschließen.

Nummerierung mit umgekehrter Achse. „preceding-sibling::td[1]“ ist das nächstgelegene, nicht das erste.

Leerzeichen. „//td[.='In stock']“ schlägt bei formattiertem HTML fehl. „normalize-space()“ behebt das Problem.

Groß-/Kleinschreibung. Bei XPath 1.0 wird bei allem zwischen Groß- und Kleinschreibung unterschieden, einschließlich der Elementnamen in XML-Dokumenten.

Standard-Namespaces. In XML mit einem Standard-Namespace liefert //item keine Treffer – Sie müssen ein Präfix registrieren und dieses verwenden. HTML-Parser ersparen Ihnen dies in der Regel; XML-Parser hingegen nicht.

Absolute Pfade aus Browser-Entwicklertools. Sie kodieren die exakte Struktur zu einem bestimmten Zeitpunkt und funktionieren bei jeder Änderung nicht mehr.

Übermäßige Übereinstimmung mit „contains()“. Die Übereinstimmung mit „Price“ führt auch zu einer Übereinstimmung mit „Historic Price“. Verwenden Sie „normalize-space() = 'Price'“, wenn Sie Gleichheit meinen.

Einfügen nicht vertrauenswürdiger Zeichenfolgen. Das Einfügen von Benutzereingaben in einen Ausdruck ist eine XPath-Injektion. Verwenden Sie Variablenbindung, sofern Ihre Bibliothek diese bietet. XPath 1.0 kennt keine Escape-Zeichen für Anführungszeichen innerhalb eines String-Literals, daher erfordert ein Wert, der beide Anführungszeichen enthält, die Verwendung von concat().

XPath 1.0 im Vergleich zu späteren Versionen

Das sollten Sie wissen, da ein Code-Schnipsel, den Sie online finden, möglicherweise nicht dort funktioniert, wo Sie ihn benötigen.

XPath 1.0 ist das, was Browser über „document.evaluate“ implementieren, was Selenium verwendet und was die allgemeine API von lxml bereitstellt. Es verfügt über die oben aufgeführten Funktionen und keine weiteren.

XPath 2.0 und 3.1 fügen reguläre Ausdrücke (matches(), replace()), Fallfunktionen (upper-case(), lower-case()), ends-with(), Sequenztypen, for-Ausdrücke und vieles mehr hinzu. Sie sind in XSLT 2.0+-Prozessoren und einigen XML-Tools verfügbar, in Browsern jedoch nicht.

Die praktische Regel: Wenn ein Ausdruck eine Funktion verwendet, die nicht in den obigen Tabellen aufgeführt ist, prüfen Sie, ob Ihre Umgebung diese unterstützt, bevor Sie untersuchen, warum der Ausdruck fehlschlägt. „Funktioniert in einem Online-XPath-Tester, aber nicht in Selenium“ ist fast immer darauf zurückzuführen.

Für die Lücken, die XPath 1.0 hinterlässt, ist die Antwort in der Regel Ihre Host-Sprache. Extrahieren Sie die Daten mit XPath und wenden Sie anschließend einen regulären Ausdruck in Python oder JavaScript an, wo Sie auch überprüfen können, was übereinstimmt.

Selektoren schreiben, die eine Neugestaltung überstehen

Ein Spickzettel zeigt Ihnen, was möglich ist; in diesem Abschnitt geht es darum, welche dieser Optionen Sie wählen sollten, denn der Unterschied zwischen einem Selektor, der ein Jahr lang funktioniert, und einem, der schon nächsten Dienstag nicht mehr funktioniert, hängt ausschließlich davon ab, worauf Sie ihn verankern.

Verankere dich an der Bedeutung, nicht an der Position. (//table)[3]/tr[2]/td[4] kodiert die exakte Form der Seite zu einem bestimmten Zeitpunkt. Fügt jemand oben eine Tabelle ein, sind alle Zahlen falsch – ohne dass dies auffällt, da der Ausdruck immer noch auf etwas passt. //th[normalize-space()='Weight']/following-sibling::td[1] kodiert eine Beziehung, die eine Neuanordnung übersteht, da sich die Beschriftung mit dem Wert mitbewegt.

Bevorzuge stabile Attribute gegenüber generierten. Von einem Entwickler gewählte IDs und „data-*“-Attribute sind weitaus beständiger als Klassennamen, die sich ändern, sobald jemand das Styling anpasst. Viele moderne Frontend-Frameworks generieren gehashtete Klassennamen – css-1x9dj2k –, die sich bei jedem Build ändern; sich an diesen zu orientieren, garantiert Fehler.

Prüfen Sie vor dem Schreiben eines Selektors auf eingebettete strukturierte Daten. Sehr viele Seiten enthalten JSON-LD in einem <script type="application/ld+json">-Block, da dies Suchfunktionen steuert. Das Parsen dieser Daten ist deutlich stabiler als das Parsen von gerendertem HTML, da es maschinenlesbar konzipiert ist und visuelle Neugestaltungen vollständig übersteht. Dreißig Sekunden, um dies zu überprüfen, können einen ganzen Nachmittag an Selektor-Wartung ersparen.

Überprüfen Sie die Struktur der extrahierten Daten. Diese Gewohnheit unterscheidet eine Pipeline, die lautstark versagt, von einer, die stillschweigend versagt. Wenn ein Preis einem Währungsmuster entsprechen soll, überprüfen Sie dies. Wenn eine Kategorieseite noch nie weniger als zwanzig Artikel enthalten hat, behandeln Sie weniger als zwanzig als Fehler statt als Ergebnis. Ein Selektor, der anfängt, das falsche Element abzugleichen, erzeugt plausible, wohlgeformte, aber falsche Daten – und es wird zu keinem Zeitpunkt eine Ausnahme ausgelöst.

Bewahre Selektoren an einem Ort auf. Über den gesamten Code verstreut sind vierzig XPath-Strings vierzig separate Wartungsprobleme. In einem einzigen Modul mit Namen zusammengefasst, bilden sie eine Übersicht über das, worauf du dich stützt, und die Aktualisierung nach einer Neugestaltung dauert eine Stunde statt eines Tages.

Und testen Sie anhand des gespeicherten HTML-Codes. Wenn Sie eine Kopie jeder Seite speichern, die Sie parsen, können Sie bei einem Fehler im Selektor das alte Markup mit dem neuen vergleichen und genau erkennen, was sich geändert hat. Ein erneutes Abrufen zur Fehlersuche ist langsamer, kostet Bandbreite und liefert möglicherweise eine andere Seite als die, bei der der Fehler aufgetreten ist.

Wann man stattdessen CSS verwenden sollte

XPath ist leistungsfähiger, aber weniger gut lesbar. CSS ist für einen Großteil der Auswahlaufgaben die richtige Standardwahl.

Verwenden Sie CSS, wenn: Sie nach Klasse, ID, Attribut oder Abstammungsverhältnis auswählen. div.card > p.price ist übersichtlicher als das entsprechende XPath-Äquivalent, wird von Tools besser unterstützt und ist in der Regel schneller.

Verwenden Sie XPath, wenn: Sie nach Textinhalten suchen müssen, was mit CSS überhaupt nicht möglich ist; Sie zu einem übergeordneten Element oder Vorfahren navigieren müssen; Sie eine Positionslogik relativ zu Geschwistern benötigen, die sich mit :nth-child nicht ausdrücken lässt; oder Sie XML statt HTML abfragen.

Beachten Sie, dass CSS einen Teil dieser Lücke geschlossen hat. „:has()“ ermöglicht in modernen Browsern die Auswahl nach Geschwistern und Nachkommen, sodass „dt:has(+ dd)“ nun ausdrückbar ist. Was CSS nach wie vor nicht leisten kann, ist die Auswahl nach Text, und genau diese Textübereinstimmung ist für das Label-Wert-Muster erforderlich.

Beides in einer Codebasis zu mischen, ist in Ordnung und sinnvoll: CSS für die unkomplizierten 90 %, XPath für die schwierigen 10 %.

Häufig gestellte Fragen

Wozu wird XPath verwendet?

Zur Navigation und Auswahl von Knoten in XML- und HTML-Dokumenten. In der Praxis wird es für Web-Scraping, die Automatisierung von Browsertests und die Abfrage von XML-Konfigurations- und Datendateien verwendet. Es drückt Beziehungen aus – über- und gleichrangige Elemente, Textinhalte –, die mit CSS-Selektoren nicht dargestellt werden können.

Was ist der Unterschied zwischen „/“ und „//“ in XPath?

Ein einzelner Schrägstrich wählt direkte Kinder aus; ein doppelter Schrägstrich wählt Nachkommen in beliebiger Tiefe aus. „//div/p“ findet Absätze, deren unmittelbares übergeordnetes Element ein div ist, während „//div//p“ Absätze an beliebiger Stelle innerhalb eines div-Elements findet.

Warum liefert mein XPath-contains()-Ausdruck keine Ergebnisse?

Meistens liegt es daran, dass Sie ihm eine Knotenmenge übergeben haben. XPath wandelt eine Knotenmenge in eine Zeichenkette um, indem es den ersten Knoten in der Dokumentreihenfolge berücksichtigt und den Rest verworfen wird. Daher untersucht contains(//p, 'x') immer nur den ersten Absatz. Schreiben Sie stattdessen //p[contains(., 'x')].

Wie wähle ich in XPath nach Klassen aus?

Verwenden Sie „//div[contains(concat(' ', normalize-space(@class), ' '), ' name ')]“, wodurch das Attribut aufgefüllt wird, sodass nur ganze Token übereinstimmen. Ein einfacher „contains(@class, 'btn')“ passt auch auf „btn-primary“. Wenn Sie ausschließlich nach Klassen auswählen, ist ein CSS-Selektor übersichtlicher und standardmäßig korrekt.

Unterstützt XPath reguläre Ausdrücke?

Nicht in XPath 1.0, das von Browsern und Selenium implementiert wird. XPath 2.0 und spätere Versionen fügen matches() und replace() hinzu, und serverseitige Bibliotheken wie lxml unterstützen EXSLTs re:test(). Für die Browser-Automatisierung extrahieren Sie die Daten mit XPath und wenden Sie den regulären Ausdruck in Ihrer Host-Sprache an.

Was ist der Unterschied zwischen „//div[1]“ und „(//div)[1]“? „

//div[1]“ wendet das Prädikat pro übergeordnetem Element an und wählt das erste div unter jedem übergeordneten Element aus, das ein – möglicherweise mehrere – Knoten enthält. „(//div)[1]“ sammelt alle div-Elemente in der Reihenfolge des Dokuments und wählt das erste aus, was genau einem Knoten entspricht.

Ist XPath groß-/kleinschreibungsabhängig?

Ja, durchgehend – bei Elementnamen, Attributnamen und Zeichenfolgenvergleichen. XPath 1.0 verfügt über keine „lower-case()“-Funktion, daher erfordert die groß-/kleinschreibungsunabhängige Übereinstimmung die Verwendung von „translate()“ mit expliziter Angabe von Groß- und Kleinbuchstaben.

Sollte ich XPath- oder CSS-Selektoren verwenden?

CSS für Klassen, IDs, Attribute und Nachkommenbeziehungen – es ist übersichtlicher und wird besser unterstützt. XPath, wenn Sie nach Textinhalten suchen, zu Vorfahren navigieren oder Positionslogik ausdrücken müssen, die CSS nicht bieten kann. Es ist üblich, beides in einer Codebasis zu verwenden.

Zusammenfassung

Der nützliche Kern von XPath ist klein: „//“, um überall zu suchen, Prädikate in eckigen Klammern zum Filtern, „@“ für Attribute, eine Handvoll String-Funktionen und die „sibling“-Achsen zur Navigation relativ zu etwas, das Sie identifizieren können.

Drei Gewohnheiten ersparen Ihnen den größten Teil der Probleme. Schließen Sie Textvergleiche in „normalize-space()“ ein, da echtes HTML formatiert ist und eine exakte Übereinstimmung fehlschlagen würde. Wenden Sie „contains()“ innerhalb eines Prädikats an, damit es pro Knoten ausgewertet wird, da die Zeichenfolgenkonvertierung einer Knotenmenge stillschweigend nur den ersten Knoten berücksichtigt. Und ziehe die Verankerung anhand von Text oder Bezeichnern der Verankerung anhand der Position vor, da sich die Struktur ändert, der Text jedoch in der Regel nicht.

Denke dann daran, für welche Version du schreibst. Browser und Selenium bieten dir XPath 1.0 – keine regulären Ausdrücke, kein „lower-case()“, kein „ends-with()“ – und ein Ausdruck, der in einem Online-Tester funktioniert, verwendet möglicherweise keines dieser Elemente und schlägt dennoch aus einem weiter unten in der Liste genannten Grund fehl. Wenn du Funktionen benötigst, die in 1.0 fehlen, extrahiere die Daten mit XPath und erledige den Rest in deiner Host-Sprache.