Como usar o Xpath em Python?

224

Quais são as bibliotecas que suportam o Xpath? Existe uma implementação completa? Como a biblioteca é usada? Onde está o site dele?

smci
fonte
4
Eu tenho essa suspeita sorrateira de que as respostas a esta pergunta são um pouco obsoletas agora.
Warren P
4
A resposta do @ gringo-suave parece uma boa atualização. stackoverflow.com/a/13504511/1450294
Michael Scheper
Scrapy oferece seletores XPath .
cs95
Como o @WarrenP diz, a maioria das respostas aqui são extremamente antigas e obsoletas, o Python-2.x, realmente desatualizado. Talvez esta questão deve ser marcado python-2.x
SMCI

Respostas:

129

A libxml2 tem várias vantagens:

  1. Conformidade com as especificações
  2. Desenvolvimento ativo e participação da comunidade
  3. Rapidez. Este é realmente um wrapper python em torno de uma implementação em C.
  4. Onipresença. A biblioteca libxml2 é abrangente e, portanto, bem testada.

As desvantagens incluem:

  1. Conformidade com as especificações . É estrito. Coisas como o tratamento de namespace padrão são mais fáceis em outras bibliotecas.
  2. Uso de código nativo. Isso pode ser complicado, dependendo de como o aplicativo é distribuído / implantado. Estão disponíveis RPMs que aliviam um pouco dessa dor.
  3. Manipulação manual de recursos. Observe na amostra abaixo as chamadas para freeDoc () e xpathFreeContext (). Isso não é muito pitonico.

Se você estiver fazendo uma seleção simples de caminho, fique com o ElementTree (incluído no Python 2.5). Se você precisa de conformidade total com as especificações ou velocidade bruta e pode lidar com a distribuição do código nativo, acesse libxml2.

Amostra de uso XPath libxml2


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

Amostra de uso do 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
fonte
8
usando python 2.7.10 no OSX eu tinha que importar ElementTree comofrom xml.etree.ElementTree import ElementTree
Ben Page
porque é um C invólucro que você pode encontrar dificuldade de implantá-lo a AWS Lambda, a menos que você compilar em uma instância EC2 ou uma imagem Docker da AWS Linux
CpILL
85

O pacote lxml suporta xpath. Parece funcionar muito bem, embora eu tenha tido alguns problemas com o self :: axis. Há também Amara , mas não o usei pessoalmente.

James Sulak
fonte
1
A amara é muito legal e nem sempre é necessário o xpath.
gatoatigrado 5/12/2009
Adicione alguns detalhes básicos sobre como usar o XPath com lxml.
jpmc26
56

Parece um anúncio lxml aqui. ;) ElementTree está incluído na biblioteca std. Abaixo de 2.6 e abaixo, seu xpath é bastante fraco, mas em 2.7+ muito melhorado :

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
fonte
39

Use LXML. O LXML usa todo o poder do libxml2 e libxslt, mas os agrupa em mais ligações "Pythonic" do que nas ligações do Python que são nativas para essas bibliotecas. Como tal, obtém a implementação completa do XPath 1.0. O ElemenTree nativo suporta um subconjunto limitado do XPath, embora possa ser bom o suficiente para suas necessidades.

user210794
fonte
29

Outra opção é o py-dom-xpath , que funciona perfeitamente com o minidom e é puro Python, portanto, funciona no aplicativo.

import xpath
xpath.find('//item', doc)
Sam
fonte
2
Mais fácil que lxml e libxml2 se você já estiver trabalhando com o minidom. Funciona lindamente e é mais "pitonico". O contextna findfunção permitem que você use um outro resultado XPath como um novo contexto de busca.
Ben
3
Eu também tenho usado py-dom-xpath enquanto escrevo um plugin, porque é python puro. Mas acho que não é mais mantido e lembre-se desse bug ("Não é possível acessar um elemento cujo nome é 'texto'"): code.google.com/p/py-dom-xpath/issues/detail?id = 8
Jon Coombs
O py-dom-xpath parece ter sido destruído anos atrás em 2010 , por favor, no mínimo, edite-o em sua resposta.
smci 8/06
14

Você pode 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
fonte
quando tento o código PyXML, recebi ImportError: No module named extdefrom xml.dom.ext.reader import Sax2
Aminah Nuraini 30/11
9

A versão mais recente do elementtree suporta muito bem o XPath. Não sendo um especialista em XPath, não posso dizer com certeza se a implementação está completa, mas atendeu a maioria das minhas necessidades ao trabalhar em Python. Eu também uso lxml e PyXML e acho o etree agradável porque é um módulo padrão.

NOTA: Desde então, encontrei o lxml e, para mim, é definitivamente a melhor lib XML disponível no Python. Ele também funciona bem com o XPath (embora novamente talvez não seja uma implementação completa).

jkp
fonte
7
Atualmente, o suporte XPath do ElementTree é mínimo, na melhor das hipóteses. Existem enormes falhas na funcionalidade, como a falta de seletores de atributos, nenhum eixo não padrão, nenhuma indexação filho etc. A versão 1.3 (em alfa) adiciona alguns desses recursos, mas ainda é uma implementação sem vergonha parcial.
21411 James Brady
8

Você pode usar o simples soupparserdelxml

Exemplo:

from lxml.html.soupparser import fromstring

tree = fromstring("<a>Find me!</a>")
print tree.xpath("//a/text()")
Aminah Nuraini
fonte
Que diferença faz usando o analisador de sopa?
Padraic Cunningham
É apenas uma alternativa
Aminah Nuraini
7

Se você deseja ter o poder do XPATH combinado com a capacidade de também usar CSS a qualquer momento, você pode 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
fonte
como deve ser o meu Xpath se eu quiser obter "Link 1" e "Link 2"?
precisa saber é o seguinte
1
para obter o texto, deve ser algo como//li/a/text()
eLRuLL 17/04
4

Outra biblioteca é o 4Suite: http://sourceforge.net/projects/foursuite/

Não sei como é compatível com as especificações. Mas funcionou muito bem para o meu uso. Parece abandonado.

codeape
fonte
3

PyXML funciona bem.

Você não disse em qual plataforma está usando, no entanto, se estiver no Ubuntu, pode obtê-lo sudo apt-get install python-xml. Tenho certeza de que outras distribuições Linux também o têm.

Se você estiver em um Mac, o xpath já está instalado, mas não é acessível imediatamente. Você pode definir PY_USE_XMLPLUSem seu ambiente ou fazê-lo da maneira Python antes de importar o xml.xpath:

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

Na pior das hipóteses, você pode ter que construir você mesmo. Este pacote não é mais mantido, mas ainda é compilado e funciona com os modernos Python 2.x. Os documentos básicos estão aqui .

David Joyner
fonte
0

Se você vai precisar dele para html :

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