Comment utiliser Xpath en Python?

224

Quelles sont les bibliothèques qui prennent en charge Xpath? Y a-t-il une mise en œuvre complète? Comment la bibliothèque est-elle utilisée? Où est son site Internet?

smci
la source
4
J'ai cette suspicion sournoise que les réponses à cette question sont un peu périmées maintenant.
Warren P
4
La réponse de @ gringo-suave ressemble à une bonne mise à jour. stackoverflow.com/a/13504511/1450294
Michael Scheper
Scrapy propose des sélecteurs XPath .
cs95
Comme le dit @WarrenP, la plupart des réponses ici sont d'anciens Python-2.x extrêmement périmés, vraiment obsolètes. Peut-être que cette question devrait être étiquetée python-2.x
smci

Réponses:

129

libxml2 présente un certain nombre d'avantages:

  1. Conformité aux spécifications
  2. Développement actif et participation communautaire
  3. La vitesse. C'est vraiment un wrapper python autour d'une implémentation C.
  4. Ubiquité. La bibliothèque libxml2 est omniprésente et donc bien testée.

Les inconvénients comprennent:

  1. Conformité aux spécifications . C'est strict. Des choses comme la gestion des espaces de noms par défaut sont plus faciles dans d'autres bibliothèques.
  2. Utilisation de code natif. Cela peut être pénible selon la façon dont votre application est distribuée / déployée. Des RPM sont disponibles pour soulager une partie de cette douleur.
  3. Manipulation manuelle des ressources. Notez dans l'exemple ci-dessous les appels à freeDoc () et xpathFreeContext (). Ce n'est pas très Pythonic.

Si vous faites une sélection de chemin simple, restez avec ElementTree (qui est inclus dans Python 2.5). Si vous avez besoin d'une conformité complète aux spécifications ou d'une vitesse brute et que vous pouvez gérer la distribution de code natif, optez pour libxml2.

Exemple d'utilisation 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()

Exemple d'utilisation d'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
la source
8
en utilisant python 2.7.10 sur osx, j'ai dû importer ElementTree en tant quefrom xml.etree.ElementTree import ElementTree
Ben Page
car il s'agit d'un wrapper C, vous pouvez rencontrer des difficultés à le déployer sur AWS Lambda, sauf si vous compilez sur une instance EC2 ou une image Docker d'AWS Linux
CpILL
85

Le package lxml prend en charge xpath. Cela semble assez bien fonctionner, même si j'ai eu quelques problèmes avec l'axe self ::. Il y a aussi Amara , mais je ne l'ai pas utilisé personnellement.

James Sulak
la source
1
amara est plutôt sympa, et on n'a pas toujours besoin de xpath.
gatoatigrado
Veuillez ajouter quelques détails de base sur la façon d'utiliser XPath avec lxml.
jpmc26
56

Cela ressemble à une publicité lxml ici. ;) ElementTree est inclus dans la bibliothèque std. Sous 2.6 et en dessous, son xpath est assez faible, mais dans 2.7+, il s'est beaucoup amélioré :

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
la source
39

Utilisez LXML. LXML utilise toute la puissance de libxml2 et libxslt, mais les encapsule dans plus de liaisons "Pythonic" que les liaisons Python natives de ces bibliothèques. En tant que tel, il obtient l'implémentation complète de XPath 1.0. Native ElemenTree prend en charge un sous-ensemble limité de XPath, bien qu'il puisse être suffisant pour vos besoins.

user210794
la source
29

Une autre option est py-dom-xpath , il fonctionne de manière transparente avec minidom et est pur Python, donc fonctionne sur appengine.

import xpath
xpath.find('//item', doc)
Sam
la source
2
Plus facile que lxml et libxml2 si vous travaillez déjà avec minidom. Fonctionne magnifiquement et est plus "Pythonic". Dans contextla findfonction, vous pouvez utiliser un autre résultat xpath comme nouveau contexte de recherche.
Ben
3
Moi aussi, j'utilise py-dom-xpath lorsque j'écris un plugin, car c'est du pur python. Mais je ne pense plus qu'il soit maintenu, et soyez conscient de ce bogue ("Impossible d'accéder à un élément dont le nom est 'text'"): code.google.com/p/py-dom-xpath/issues/detail?id = 8
Jon Coombs
py-dom-xpath semble avoir été mis en veilleuse il y a des années en 2010 , veuillez au moins le modifier dans votre réponse.
smci
14

Vous pouvez utiliser:

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
la source
quand j'essaie le code PyXML, je suis arrivé ImportError: No module named extdefrom xml.dom.ext.reader import Sax2
Aminah Nuraini
9

La dernière version de elementtree prend assez bien en charge XPath. N'étant pas un expert XPath, je ne peux pas dire avec certitude si la mise en œuvre est complète, mais elle a satisfait la plupart de mes besoins lorsque je travaillais en Python. J'ai également utilisé lxml et PyXML et je trouve etree sympa car c'est un module standard.

REMARQUE: j'ai depuis trouvé lxml et pour moi, c'est certainement la meilleure bibliothèque XML pour Python. Il fait aussi bien XPath (mais encore une fois peut-être pas une implémentation complète).

jkp
la source
7
Le support XPath d'ElementTree est actuellement au mieux minimal. Il y a d'énormes trous béants dans la fonctionnalité, tels que le manque de sélecteurs d'attributs, pas d'axes non par défaut, pas d'indexation enfant, etc. La version 1.3 (en alpha) ajoute certaines de ces fonctionnalités, mais c'est toujours une implémentation partielle sans vergogne.
James Brady
8

Vous pouvez utiliser le simple soupparserdelxml

Exemple:

from lxml.html.soupparser import fromstring

tree = fromstring("<a>Find me!</a>")
print tree.xpath("//a/text()")
Aminah Nuraini
la source
Quelle différence fait l'utilisation de soupparser?
Padraic Cunningham
C'est juste une alternative
Aminah Nuraini
7

Si vous souhaitez combiner la puissance de XPATH avec la possibilité d'utiliser également CSS à tout moment, vous pouvez utiliser 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
la source
à quoi devrait ressembler mon Xpath si je veux obtenir "Link 1" et "Link 2"?
weefwefwqg3
1
pour obtenir le texte, cela devrait être quelque chose comme//li/a/text()
eLRuLL
4

Une autre bibliothèque est 4Suite: http://sourceforge.net/projects/foursuite/

Je ne sais pas à quel point c'est conforme aux spécifications. Mais cela a très bien fonctionné pour mon usage. Il a l'air abandonné.

codeape
la source
3

PyXML fonctionne bien.

Vous n'avez pas dit avec quelle plateforme vous utilisez, mais si vous êtes sur Ubuntu, vous pouvez l'obtenir sudo apt-get install python-xml. Je suis sûr que d'autres distributions Linux l'ont également.

Si vous êtes sur un Mac, xpath est déjà installé mais pas immédiatement accessible. Vous pouvez définir PY_USE_XMLPLUSdans votre environnement ou le faire de la manière Python avant d'importer xml.xpath:

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

Dans le pire des cas, vous devrez peut-être le construire vous-même. Ce paquet n'est plus maintenu mais continue de fonctionner correctement et fonctionne avec les Pythons 2.x modernes. Les documents de base sont ici .

David Joyner
la source
0

Si vous en aurez besoin pour le HTML :

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