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?


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


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.


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

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.


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)

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

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


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

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

à 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


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 .


0

Si vous en aurez besoin pour le HTML :

import lxml.html as html
root  = html.fromstring(string)
root.xpath('//meta')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.