2010-04-01 35 views
15

Tôi đang cố gắng sử dụng html5lib để phân tích cú pháp trang html vào một thứ mà tôi có thể truy vấn bằng xpath. html5lib đã gần bằng không tài liệu và tôi đã dành quá nhiều thời gian cố gắng để tìm ra vấn đề này. Mục tiêu cuối cùng là phải rút ra khỏi hàng thứ hai của một bảng:Làm cách nào để phân tích cú pháp HTML bằng html5lib và truy vấn HTML được phân tích cú pháp bằng XPath?

<html> 
    <table> 
     <tr><td>Header</td></tr> 
     <tr><td>Want This</td></tr> 
    </table> 
</html> 

bây giờ bạn hãy nó:

>>> doc = html5lib.parse('<html><table><tr><td>Header</td></tr><tr><td>Want This</td> </tr></table></html>', treebuilder='lxml') 
>>> doc 
<lxml.etree._ElementTree object at 0x1a1c290> 

rằng có vẻ tốt, cho phép xem những gì khác chúng ta có:

>>> root = doc.getroot() 
>>> print(lxml.etree.tostring(root)) 
<html:html xmlns:html="http://www.w3.org/1999/xhtml"><html:head/><html:body><html:table><html:tbody><html:tr><html:td>Header</html:td></html:tr><html:tr><html:td>Want This</html:td></html:tr></html:tbody></html:table></html:body></html:html> 

LOL WUT?

nghiêm túc. Tôi đã lên kế hoạch sử dụng một số xpath để lấy dữ liệu tôi muốn, nhưng điều đó dường như không hoạt động. Vậy tôi có thể làm gì? Tôi sẵn sàng thử các thư viện và cách tiếp cận khác nhau.

Trả lời

19

Thiếu tài liệu là một lý do chính đáng để tránh một thư viện IMO, bất kể như thế nào mát nó là . Bạn có muốn sử dụng html5lib không? Bạn đã xem lxml.html chưa?

Dưới đây là một cách để làm điều này với lxml:

from lxml import html 
tree = html.fromstring(text) 
[td.text for td in tree.xpath("//td")] 

Kết quả:

['Header', 'Want This'] 
-3

thử sử dụng jquery. và bạn có thể truy xuất tất cả các phần tử. luân phiên, bạn có thể đặt một id trên hàng của bạn và kéo nó ra.

1) ... ...

$ ("td") [1] .innerHTML sẽ là những gì bạn muốn

2) ... ...

$ ("#blah"). text() sẽ là những gì bạn muốn

+0

Tôi nghĩ rằng yêu cầu là một giải pháp Python. –

1

tôi tin rằng bạn có thể làm tìm kiếm css trên các đối tượng lxml .. như vậy

elements = root.cssselect('div.content') 
data = elements[0].text 
2

Với BeautifulSoup, bạn có thể làm điều đó với

>>> soup = BeautifulSoup.BeautifulSoup('<html><table><tr><td>Header</td></tr><tr><td>Want This</td></tr></table></html>') 
>>> soup.findAll('td')[1].string 
u'Want This' 
>>> soup.findAll('tr')[1].td.string 
u'Want This' 

(Rõ ràng đó là một ví dụ thực sự thô, nhưng ya.)

3

Tôi luôn luôn khuyên bạn nên thử lxml thư viện. Nó rất nhanh và có nhiều tính năng.

Nó cũng đã hỗ trợ cho phân tích cú pháp html5lib nếu bạn cần có: html5parser

>>> from lxml.html import fromstring, tostring 

>>> html = """ 
... <html> 
...  <table> 
...   <tr><td>Header</td></tr> 
...   <tr><td>Want This</td></tr> 
...  </table> 
... </html> 
... """ 
>>> doc = fromstring(html) 
>>> tr = doc.cssselect('table tr')[1] 
>>> print tostring(tr) 
<tr><td>Want This</td></tr> 
+1

Đây là cách tôi làm điều đó, ngoại trừ tôi muốn sử dụng "print doc.cssselect ('tr') [1] .text_content()" để lấy nội dung của hàng thứ hai, thay vì có lxml hiển thị HTML . –

15

gì bạn muốn sử dụng là namespaceHTMLElements cãi nhau, mà đối với một số giá trị mặc định lý do để True.

doc = html5lib.parse('''<html> 
    <table> 
     <tr><td>Header</td></tr> 
     <tr><td>Want This</td></tr> 
    </table> 
</html> 
''', treebuilder='lxml', namespaceHTMLElements=False) 

print lxml.html.tostring(doc) 

Có lẽ vẫn dễ sử dụng lxml.html hơn.

+0

Câu trả lời phù hợp nhất. Cảm ơn thời gian lớn! – gorlum0

+2

Giá trị mặc định là 'True' vì đặc tả HTML xác định các phần tử đó nằm trong không gian tên HTML - rằng công cụ Python hiện có yêu cầu chúng không phải là lý do tùy chọn tồn tại. – gsnedders

0

Vì html5lib (theo mặc định) tạo cây có chứa thông tin không gian tên (chính xác) bạn đã chỉ định (đúng) không gian tên trong truy vấn của bạn.

Ví dụ với một truy vấn XPath:

import html5lib 
inp='''<html> 
    <table> 
     <tr><td>Header</td></tr> 
     <tr><td>Want This</td></tr> 
    </table> 
</html>''' 
xns = '{http://www.w3.org/1999/xhtml}' 
d = html5lib.parse(inp) 
s = d.findall('.//{}td'.format(xns))[-1].text 
print(s) 

Output:

Want This

Các kết quả tương tự mà không XPath:

s = d.find(xns+'body').find(xns+'table').find(xns+'tbody') \ 
    .findall(xns+'tr')[-1].find(xns+'td').text 

Ngoài ra, bạn cũng có thể cho html5lib để tránh thêm bất kỳ thông tin không gian tên trong khi phân tích cú pháp:

d = html5lib.parse(inp, namespaceHTMLElements=False) 
s = d.findall('.//td')[-1].text 
print(s) 

Output:

Want This
Các vấn đề liên quan