Làm thế nào để sử dụng Xpath trong Python?


224

Các thư viện hỗ trợ Xpath là gì? Có thực hiện đầy đủ? Thư viện được sử dụng như thế nào? Trang web của nó ở đâu?


4
Tôi có nghi ngờ lén lút này rằng các câu trả lời cho câu hỏi này bây giờ hơi cũ.
Warren P

4
Câu trả lời của @ gringo-suave trông giống như một bản cập nhật tốt. stackoverflow.com/a/13504511/1450294
Michael Scheper

Scrapy cung cấp bộ chọn XPath .
cs95

Như @WarrenP nói, hầu hết các câu trả lời ở đây là Python-2.x cũ cực kỳ cũ, thực sự đã lỗi thời. Có lẽ câu hỏi này nên được gắn thẻ python-2.x
smci

Câu trả lời:


129

libxml2 có một số lợi thế:

  1. Tuân thủ thông số kỹ thuật
  2. Phát triển tích cực và sự tham gia của cộng đồng
  3. Tốc độ. Đây thực sự là một trình bao bọc python xung quanh việc thực hiện C.
  4. Sự phổ biến. Thư viện libxml2 có sức lan tỏa và do đó được kiểm tra tốt.

Nhược điểm bao gồm:

  1. Tuân thủ thông số kỹ thuật . Đó là nghiêm ngặt. Những thứ như xử lý không gian tên mặc định dễ dàng hơn trong các thư viện khác.
  2. Sử dụng mã gốc. Điều này có thể là một nỗi đau tùy thuộc vào cách ứng dụng của bạn được phân phối / triển khai. RPM có sẵn mà giảm bớt một số nỗi đau này.
  3. Xử lý tài nguyên thủ công. Lưu ý trong mẫu bên dưới các lệnh gọi freeDoc () và xpathFreeContext (). Đây không phải là rất Pythonic.

Nếu bạn đang thực hiện lựa chọn đường dẫn đơn giản, hãy gắn bó với ElementTree (được bao gồm trong Python 2.5). Nếu bạn cần tuân thủ đầy đủ thông số kỹ thuật hoặc tốc độ thô và có thể đối phó với việc phân phối mã gốc, hãy đi với libxml2.

Mẫu sử dụng 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()

Mẫu sử dụng 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
sử dụng python 2.7.10 trên osx Tôi đã phải nhập ElementTree nhưfrom xml.etree.ElementTree import ElementTree
Ben Trang

bởi vì nó là trình bao bọc C mà bạn có thể gặp khó khăn khi triển khai nó lên AWS Lambda trừ khi bạn biên dịch trên phiên bản EC2 hoặc hình ảnh Docker của AWS Linux
CpILL

85

Các gói lxml hỗ trợ XPath. Nó có vẻ hoạt động khá tốt, mặc dù tôi đã gặp một số rắc rối với trục self ::. Có cả Amara , nhưng tôi chưa từng sử dụng nó.


1
amara khá đẹp và không phải lúc nào cũng cần xpath.
gatoatigrado

Vui lòng thêm một số chi tiết cơ bản về cách sử dụng XPath với lxml.
jpmc26

56

Âm thanh như một quảng cáo lxml ở đây. ;) ElementTree được bao gồm trong thư viện tiêu chuẩn. Dưới 2,6 và thấp hơn xpath của nó khá yếu, nhưng trong 2,7+ được cải thiện nhiều :

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

Sử dụng LXML. LXML sử dụng toàn bộ sức mạnh của libxml2 và libxslt, nhưng bao bọc chúng trong các ràng buộc "Pythonic" hơn các ràng buộc Python có nguồn gốc từ các thư viện đó. Như vậy, nó được triển khai XPath 1.0 đầy đủ. Bản gốc ElemenTree hỗ trợ một tập hợp con XPath giới hạn, mặc dù nó có thể đủ tốt cho nhu cầu của bạn.


29

Một tùy chọn khác là py-dom-xpath , nó hoạt động trơn tru với minidom và là Python thuần túy nên hoạt động trên appengine.

import xpath
xpath.find('//item', doc)

2
Dễ dàng hơn lxml và libxml2 nếu bạn đã làm việc với minidom. Hoạt động rất đẹp và "Pythonic" hơn. Hàm contexttrong findcho phép bạn sử dụng kết quả xpath khác làm bối cảnh tìm kiếm mới.
Ben

3
Tôi cũng đã sử dụng py-dom-xpath khi tôi viết một plugin, vì đó là python thuần. Nhưng tôi không nghĩ rằng nó được duy trì nữa và nhận thức được lỗi này ("Không thể truy cập một phần tử có tên là 'văn bản'"): code.google.com/p/py-dom-xpath/issues/detail?id = 8
Jon Coombs

py-dom-xpath dường như đã bị nhầm lẫn từ nhiều năm trước vào năm 2010 , xin vui lòng chỉnh sửa tối thiểu điều này thành câu trả lời của bạn.
smci

14

Bạn có thể dùng:

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

khi tôi cố gắng mã PyXML, tôi đã ImportError: No module named exttừfrom xml.dom.ext.reader import Sax2
Aminah Nuraini

9

Phiên bản mới nhất của Elementtree hỗ trợ XPath khá tốt. Không phải là một chuyên gia XPath, tôi không thể chắc chắn rằng việc triển khai đã đầy đủ hay chưa nhưng nó đã đáp ứng hầu hết các nhu cầu của tôi khi làm việc với Python. Tôi cũng đã sử dụng lxml và PyXML và tôi thấy etree rất hay vì đây là mô-đun chuẩn.

LƯU Ý: Tôi đã tìm thấy lxml và đối với tôi, đó chắc chắn là lib XML tốt nhất hiện có cho Python. Nó cũng làm XPath độc đáo (mặc dù một lần nữa có lẽ không phải là một triển khai đầy đủ).


7
Hỗ trợ XPath của ElementTree hiện tại là tối thiểu. Có nhiều lỗ hổng lớn về chức năng, chẳng hạn như thiếu bộ chọn thuộc tính, không có trục không mặc định, không lập chỉ mục con, v.v. Phiên bản 1.3 (trong bản alpha) bổ sung một số tính năng này, nhưng nó vẫn là một triển khai một phần không đáng ngạc nhiên.
James Brady

8

Bạn có thể sử dụng đơn giản soupparsertừlxml

Thí dụ:

from lxml.html.soupparser import fromstring

tree = fromstring("<a>Find me!</a>")
print tree.xpath("//a/text()")

Sử dụng soupparser có gì khác biệt?
Padraic Cickyham

Nó chỉ là một sự thay thế
Aminah Nuraini

7

Nếu bạn muốn có sức mạnh của XPATH kết hợp với khả năng sử dụng CSS tại bất kỳ thời điểm nào bạn có thể sử dụng 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!'

Xpath của tôi sẽ trông như thế nào nếu tôi muốn nhận "Liên kết 1" và "Liên kết 2"?
Sydfwefwqg3

1
để nhận được văn bản, nó phải giống như//li/a/text()
eLRuLL


3

PyXML hoạt động tốt.

Bạn không nói bạn đang sử dụng nền tảng nào, tuy nhiên nếu bạn sử dụng Ubuntu, bạn có thể sử dụng nền tảng đó sudo apt-get install python-xml. Tôi chắc chắn các bản phân phối Linux khác cũng có nó.

Nếu bạn đang sử dụng máy Mac, xpath đã được cài đặt nhưng không thể truy cập ngay lập tức. Bạn có thể đặt PY_USE_XMLPLUStrong môi trường của mình hoặc thực hiện theo cách Python trước khi nhập xml.xpath:

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

Trong trường hợp xấu nhất bạn có thể phải tự xây dựng nó. Gói này không còn được duy trì nhưng vẫn xây dựng tốt và hoạt động với Pythons 2.x hiện đại. Tài liệu cơ bản ở đây .


0

Nếu bạn cần nó cho html :

import lxml.html as html
root  = html.fromstring(string)
root.xpath('//meta')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.