¿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?


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


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.


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

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.


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)

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

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


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

¿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!'

¿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í .


0

Si lo va a necesitar para html :

import lxml.html as html
root  = html.fromstring(string)
root.xpath('//meta')
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.