Come usare Xpath in Python?


224

Quali sono le librerie che supportano Xpath? C'è una piena attuazione? Come viene utilizzata la libreria? Dov'è il suo sito Web?


4
Ho questo subdolo sospetto che le risposte a questa domanda siano un po 'stantie adesso.
Warren P,

4
La risposta di @ gringo-suave sembra un buon aggiornamento. stackoverflow.com/a/13504511/1450294
Michael Scheper,

Scrapy offre selettori XPath .
cs95,

Come dice @WarrenP, la maggior parte delle risposte qui sono Python-2.x estremamente vecchio, davvero obsoleto. Forse questa domanda dovrebbe essere taggata python-2.x
smci

Risposte:


129

libxml2 ha una serie di vantaggi:

  1. Conformità alle specifiche
  2. Sviluppo attivo e partecipazione della comunità
  3. Velocità. Questo è davvero un wrapper Python attorno a un'implementazione C.
  4. Ubiquità. La libreria libxml2 è pervasiva e quindi ben testata.

Gli aspetti negativi includono:

  1. Conformità alle specifiche . È severo. Cose come la gestione predefinita dello spazio dei nomi sono più facili in altre librerie.
  2. Uso del codice nativo. Questo può essere un problema a seconda di come viene distribuita / distribuita l'applicazione. Sono disponibili RPM che alleviano parte di questo dolore.
  3. Gestione manuale delle risorse. Nota nell'esempio sotto le chiamate a freeDoc () e xpathFreeContext (). Questo non è molto Pythonic.

Se stai facendo una semplice selezione del percorso, mantieni l'elemento ElementTree (che è incluso in Python 2.5). Se hai bisogno della piena conformità alle specifiche o della velocità pura e riesci a far fronte alla distribuzione del codice nativo, vai con libxml2.

Esempio di libxml2 XPath Use


import libxml2

doc = libxml2.parseFile("tst.xml")
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//*")
if len(res) != 2:
    print "xpath query: wrong node set size"
    sys.exit(1)
if res[0].name != "doc" or res[1].name != "foo":
    print "xpath query: wrong node set value"
    sys.exit(1)
doc.freeDoc()
ctxt.xpathFreeContext()

Esempio di utilizzo di ElementTree XPath


from elementtree.ElementTree import ElementTree
mydoc = ElementTree(file='tst.xml')
for e in mydoc.findall('/foo/bar'):
    print e.get('title').text


8
usando python 2.7.10 su osx ho dovuto importare ElementTree comefrom xml.etree.ElementTree import ElementTree
Ben Pagina

poiché si tratta di un wrapper C, potresti riscontrare difficoltà nella distribuzione su AWS Lambda a meno che non si compili su un'istanza EC2 o un'immagine Docker di AWS Linux
CpILL

85

Il pacchetto lxml supporta xpath. Sembra funzionare abbastanza bene, anche se ho avuto qualche problema con il self :: axis. C'è anche Amara , ma non l'ho usato personalmente.


1
Amara è carina, e non sempre è necessario Xpath.
Gatoatigrado,

Aggiungi alcuni dettagli di base su come utilizzare XPath con lxml.
jpmc26,

56

Sembra una pubblicità lxml qui. ;) ElementTree è incluso nella libreria std. Sotto 2.6 e sotto il suo xpath è piuttosto debole, ma in 2.7+ è molto migliorato :

import xml.etree.ElementTree as ET
root = ET.parse(filename)
result = ''

for elem in root.findall('.//child/grandchild'):
    # How to make decisions based on attributes even in 2.6:
    if elem.attrib.get('name') == 'foo':
        result = elem.text
        break

39

Usa LXML. LXML utilizza tutta la potenza di libxml2 e libxslt, ma li avvolge in più collegamenti "Pythonic" rispetto ai collegamenti Python che sono nativi di quelle librerie. Come tale, ottiene l'implementazione completa di XPath 1.0. ElemenTree nativo supporta un sottoinsieme limitato di XPath, sebbene possa essere abbastanza buono per le tue esigenze.


29

Un'altra opzione è py-dom-xpath , funziona perfettamente con minidom ed è puro Python, quindi funziona su appengine.

import xpath
xpath.find('//item', doc)

2
Più facile di lxml e libxml2 se stai già lavorando con minidom. Funziona magnificamente ed è più "Pythonic". Il contextnella findfunzione consente di utilizzare un altro risultato xpath come nuovo contesto di ricerca.
Ben

3
Anch'io ho usato py-dom-xpath mentre scrivo un plugin, perché è puro Python. Ma non credo che sia più mantenuto, e sii consapevole di questo bug ("Impossibile accedere a un elemento il cui nome è 'testo'"): code.google.com/p/py-dom-xpath/issues/detail?id = 8
Jon Coombs,

py-dom-xpath sembra essere stato imbrattato anni fa nel 2010 , per favore modifica almeno questo nella tua risposta.
smci

14

Puoi usare:

PyXML :

from xml.dom.ext.reader import Sax2
from xml import xpath
doc = Sax2.FromXmlFile('foo.xml').documentElement
for url in xpath.Evaluate('//@Url', doc):
  print url.value

libxml2 :

import libxml2
doc = libxml2.parseFile('foo.xml')
for url in doc.xpathEval('//@Url'):
  print url.content

quando provo il codice PyXML, ho ricevuto ImportError: No module named extdafrom xml.dom.ext.reader import Sax2
Aminah Nuraini il

9

L'ultima versione di elementtree supporta abbastanza bene XPath. Non essendo un esperto XPath non posso dire con certezza se l'implementazione è completa ma ha soddisfatto la maggior parte delle mie esigenze quando lavoro in Python. Ho anche usato lxml e PyXML e trovo etree bello perché è un modulo standard.

NOTA: da allora ho trovato lxml e per me è sicuramente la migliore libreria XML disponibile per Python. Funziona bene anche con XPath (anche se forse non è un'implementazione completa).


7
Il supporto XPath di ElementTree è attualmente minimo nel migliore dei casi. Esistono enormi buchi nella funzionalità, come la mancanza di selettori di attributi, nessun asse non predefinito, nessuna indicizzazione figlio, ecc. La versione 1.3 (in alfa) aggiunge alcune di queste funzionalità, ma è ancora un'implementazione spudoratamente parziale.
James Brady,


7

Se vuoi avere la potenza di XPATH unita alla possibilità di usare anche CSS in qualsiasi momento puoi usare parsel:

>>> from parsel import Selector
>>> sel = Selector(text=u"""<html>
        <body>
            <h1>Hello, Parsel!</h1>
            <ul>
                <li><a href="http://example.com">Link 1</a></li>
                <li><a href="http://scrapy.org">Link 2</a></li>
            </ul
        </body>
        </html>""")
>>>
>>> sel.css('h1::text').extract_first()
'Hello, Parsel!'
>>> sel.xpath('//h1/text()').extract_first()
'Hello, Parsel!'

come dovrebbe essere il mio Xpath se voglio ottenere "Link 1" e "Link 2"?
weefwefwqg3,

1
per ottenere il testo, dovrebbe essere qualcosa del genere//li/a/text()
eLRuLL


3

PyXML funziona bene.

Non hai detto quale piattaforma stai usando, tuttavia se sei su Ubuntu puoi ottenerlo sudo apt-get install python-xml. Sono sicuro che anche altre distribuzioni Linux ce l'hanno.

Se sei su un Mac, xpath è già installato ma non immediatamente accessibile. Puoi impostare PY_USE_XMLPLUSnel tuo ambiente o farlo in modo Python prima di importare xml.xpath:

if sys.platform.startswith('darwin'):
    os.environ['PY_USE_XMLPLUS'] = '1'

Nel peggiore dei casi potresti doverlo costruire da solo. Questo pacchetto non è più gestito ma funziona ancora bene e funziona con i moderni 2.x Pythons. I documenti di base sono qui .


0

Se ne avrai bisogno per html :

import lxml.html as html
root  = html.fromstring(string)
root.xpath('//meta')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.