¿Cómo usar Xpath en Python?

224

¿Cuáles son las bibliotecas que admiten Xpath? ¿Hay una implementación completa? ¿Cómo se usa la biblioteca? ¿Dónde está su sitio web?

smci
fuente
44
Tengo esta sospecha disimulada de que las respuestas a esta pregunta están un poco rancias ahora.
Warren P
44
La respuesta de @ gringo-suave parece una buena actualización. stackoverflow.com/a/13504511/1450294
Michael Scheper
Scrapy ofrece selectores XPath .
cs95
Como dice @WarrenP, la mayoría de las respuestas aquí son Python-2.x extremadamente obsoletas, realmente desactualizadas. Tal vez esta pregunta debería etiquetarse python-2.x
smci

Respuestas:

129

libxml2 tiene una serie de ventajas:

  1. Cumplimiento de la especificación
  2. Desarrollo activo y participación comunitaria.
  3. Velocidad. Esto es realmente un contenedor de Python alrededor de una implementación en C.
  4. Ubicuidad. La biblioteca libxml2 es generalizada y, por lo tanto, está bien probada.

Los inconvenientes incluyen:

  1. Cumplimiento de la especificación . Es estricto Cosas como el manejo predeterminado del espacio de nombres son más fáciles en otras bibliotecas.
  2. Uso de código nativo. Esto puede ser un problema dependiendo de cómo se distribuya / implemente su aplicación. Hay RPM disponibles que alivian parte de este dolor.
  3. Manejo manual de recursos. Observe en el ejemplo a continuación las llamadas a freeDoc () y xpathFreeContext (). Esto no es muy pitónico.

Si está haciendo una selección de ruta simple, quédese con ElementTree (que se incluye en Python 2.5). Si necesita cumplimiento de especificaciones completas o velocidad sin procesar y puede hacer frente a la distribución del código nativo, vaya con libxml2.

Muestra de uso de libxml2 XPath


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()

Muestra de uso de ElementTree XPath


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

Ryan Cox
fuente
8
usando Python 2.7.10 en osx tuve que importar ElementTree comofrom xml.etree.ElementTree import ElementTree
Ben Page
debido a que es un contenedor C, es posible que tenga dificultades para implementarlo en AWS Lambda a menos que compile en una instancia EC2 o una imagen Docker de AWS Linux
CpILL
85

El paquete lxml admite xpath. Parece funcionar bastante bien, aunque he tenido algunos problemas con el self :: axis. También está Amara , pero no la he usado personalmente.

James Sulak
fuente
1
amara es bastante agradable, y uno no siempre necesita xpath.
gatoatigrado 05 de
Agregue algunos detalles básicos sobre cómo usar XPath con lxml.
jpmc26
56

Suena como un anuncio lxml aquí. ;) ElementTree está incluido en la biblioteca estándar. Por debajo de 2.6 y por debajo su xpath es bastante débil, pero en 2.7+ mejoró mucho :

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
Gringo Suave
fuente
39

Usa LXML. LXML usa todo el poder de libxml2 y libxslt, pero los envuelve en más enlaces "Pythonic" que los enlaces de Python que son nativos de esas bibliotecas. Como tal, obtiene la implementación completa de XPath 1.0. Native ElemenTree admite un subconjunto limitado de XPath, aunque puede ser lo suficientemente bueno para sus necesidades.

usuario210794
fuente
29

Otra opción es py-dom-xpath , funciona a la perfección con minidom y es Python puro, por lo que funciona en appengine.

import xpath
xpath.find('//item', doc)
Sam
fuente
2
Más fácil que lxml y libxml2 si ya está trabajando con minidom. Funciona muy bien y es más "pitón". El contexten la findfunción le permite usar otro resultado xpath como un nuevo contexto de búsqueda.
Ben
3
Yo también he estado usando py-dom-xpath mientras escribo un complemento, porque es Python puro. Pero ya no creo que se mantenga, y tenga en cuenta este error ("No se puede acceder a un elemento cuyo nombre es 'texto'"): code.google.com/p/py-dom-xpath/issues/detail?id = 8
Jon Coombs
py-dom-xpath parece haber sido rechazado hace años en 2010 , edite esto como mínimo en su respuesta.
smci
14

Puedes usar:

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
0xAX
fuente
cuando intento el código PyXML, llegué ImportError: No module named extafrom xml.dom.ext.reader import Sax2
Amina Nuraini
9

La última versión de elementtree es bastante compatible con XPath. Al no ser un experto en XPath, no puedo decir con certeza si la implementación está completa, pero ha satisfecho la mayoría de mis necesidades cuando trabajo en Python. También utilizo lxml y PyXML y encuentro etree agradable porque es un módulo estándar.

NOTA: Desde entonces encontré lxml y para mí es definitivamente la mejor biblioteca XML que existe para Python. También funciona bien XPath (aunque quizás no sea una implementación completa).

jkp
fuente
77
El soporte XPath de ElementTree es actualmente mínimo en el mejor de los casos. Hay enormes huecos en la funcionalidad, como la falta de selectores de atributos, sin ejes no predeterminados, sin indexación secundaria, etc. La versión 1.3 (en alfa) agrega algunas de estas características, pero sigue siendo una implementación parcial descaradamente.
James Brady el
8

Puedes usar el simple soupparserdelxml

Ejemplo:

from lxml.html.soupparser import fromstring

tree = fromstring("<a>Find me!</a>")
print tree.xpath("//a/text()")
Aminah Nuraini
fuente
¿Qué diferencia hace el uso de la sopa de sopa?
Padraic Cunningham
Es solo una alternativa
Aminah Nuraini el
7

Si desea tener el poder de XPATH combinado con la capacidad de usar también CSS en cualquier momento, puede usar 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!'
eLRuLL
fuente
¿Cómo debería ser mi Xpath si quiero obtener "Enlace 1" y "Enlace 2"?
weefwefwqg3
1
para obtener el texto, debería ser algo como//li/a/text()
eLRuLL
3

PyXML funciona bien.

No dijiste qué plataforma estás utilizando, sin embargo, si estás en Ubuntu, puedes hacerlo sudo apt-get install python-xml. Estoy seguro de que otras distribuciones de Linux también lo tienen.

Si está en una Mac, xpath ya está instalado pero no es accesible de inmediato. Puede configurarlo PY_USE_XMLPLUSen su entorno o hacerlo a la manera de Python antes de importar xml.xpath:

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

En el peor de los casos, puede que tenga que construirlo usted mismo. Este paquete ya no se mantiene, pero aún se construye bien y funciona con las modernas 2.x Pythons. Los documentos básicos están aquí .

David Joyner
fuente
0

Si lo va a necesitar para html :

import lxml.html as html
root  = html.fromstring(string)
root.xpath('//meta')
Thomas G.
fuente