2013-05-30 59 views
19

tôi cố gắng trích xuất "THIS IS TEXT CỦA TÔI" từ HTML sau:Python BeautifulSoup trích văn bản giữa các yếu tố

<html> 
<body> 
<table> 
    <td class="MYCLASS"> 
     <!-- a comment --> 
     <a hef="xy">Text</a> 
     <p>something</p> 
     THIS IS MY TEXT 
     <p>something else</p> 
     </br> 
    </td> 
</table> 
</body> 
</html> 

Tôi đã thử nó theo cách này:

soup = BeautifulSoup(html) 

for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
    print hit.text 

Nhưng tôi nhận được tất cả văn bản giữa tất cả các thẻ lồng nhau cộng với nhận xét.

Có ai có thể giúp tôi chỉ nhận được "NÀY LÀ VĂN BẢN CỦA TÔI" không?

Trả lời

9

Sử dụng .children thay vì:

from bs4 import NavigableString, Comment 
print ''.join(unicode(child) for child in hit.children 
    if isinstance(child, NavigableString) and not isinstance(child, Comment)) 

Vâng, đây là một chút của một điệu nhảy.

Output:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
...  print ''.join(unicode(child) for child in hit.children 
...   if isinstance(child, NavigableString) and not isinstance(child, Comment)) 
... 




     THIS IS MY TEXT 
+0

Điều đó sẽ trả lại 'u '\ n một bình luận \ nĐịa chỉ \ ncái gì đó \ n ĐÂY LÀ TEXT CỦA TÔI \ n điều gì khác \ n'' hoặc' u'a bình luậnTextsomethingTHIS LÀ TEXTs something else'' của tôi có nhiều văn bản hơn yêu cầu. –

+0

@CristianCiupitu: Tất nhiên, bạn đúng, không chú ý ở đây. Đang cập nhật. –

+0

Đây là giải pháp duy nhất không phụ thuộc vào văn bản nằm trong chuỗi hoặc mối quan hệ vị trí với một phần tử cụ thể khác, mà kéo tất cả văn bản từ thẻ/phần tử được chỉ định trong khi bỏ qua văn bản (hoặc nội dung khác) của thẻ/phần tử con. Cảm ơn! Nó là khó xử, nhưng nó hoạt động và giải quyết vấn đề của tôi (tôi không phải là OP, nhưng có một nhu cầu tương tự). – geewiz

11

Bạn có thể sử dụng .contents:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
...  print hit.contents[6].strip() 
... 
THIS IS MY TEXT 
+3

Cảm ơn, nhưng văn bản không phải lúc nào cũng ở cùng một nơi. Nó có hoạt động không? –

+0

@ ɥɔǝnqɹǝƃloɥ Alas not. Có lẽ sử dụng câu trả lời của người khác – TerryA

+0

Số '6' có nghĩa là gì? – User

24

Tìm hiểu thêm về cách điều hướng through the parse tree in BeautifulSoup. Cây phân tích cú pháp đã có tagsNavigableStrings (vì đây là một văn bản). Ví dụ:

from BeautifulSoup import BeautifulSoup 
doc = ['<html><head><title>Page title</title></head>', 
     '<body><p id="firstpara" align="center">This is paragraph <b>one</b>.', 
     '<p id="secondpara" align="blah">This is paragraph <b>two</b>.', 
     '</html>'] 
soup = BeautifulSoup(''.join(doc)) 

print soup.prettify() 
# <html> 
# <head> 
# <title> 
# Page title 
# </title> 
# </head> 
# <body> 
# <p id="firstpara" align="center"> 
# This is paragraph 
# <b> 
#  one 
# </b> 
# . 
# </p> 
# <p id="secondpara" align="blah"> 
# This is paragraph 
# <b> 
#  two 
# </b> 
# . 
# </p> 
# </body> 
# </html> 

Để di chuyển cây phân tích bạn có contentsstring.

  • nội dung là một danh sách có thứ tự các Tag và NavigableString đối tượng chứa trong một yếu tố trang

  • nếu thẻ có chỉ có một nút con, và đó là nút con là một chuỗi, nút con được cung cấp dưới dạng tag.string, cũng như tag.contents [0]

Đối với ở trên, đó là để nói rằng bạn có thể nhận được

soup.b.string 
# u'one' 
soup.b.contents[0] 
# u'one' 

Đối với nhiều trẻ em nút, bạn có thể có ví dụ

pTag = soup.p 
pTag.contents 
# [u'This is paragraph ', <b>one</b>, u'.'] 

vì vậy đây bạn có thể chơi với contents và nhận nội dung tại chỉ mục bạn muốn.

Bạn cũng có thể lặp qua Thẻ, đây là lối tắt. Ví dụ:

for i in soup.body: 
    print i 
# <p id="firstpara" align="center">This is paragraph <b>one</b>.</p> 
# <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p> 
+0

' hit.string' là 'None' và' hit.contents [0] 'là' u '\ n'', vì vậy vui lòng cung cấp câu trả lời cho ví dụ từ câu hỏi. –

+0

vì vậy ở đây bạn có thể chơi với nội dung và nhận nội dung tại chỉ mục bạn muốn. – octoback

+0

là câu trả lời cho câu hỏi – octoback

0

BeautifulSoup documentation cung cấp ví dụ về cách xóa đối tượng khỏi tài liệu bằng phương pháp trích xuất.Trong ví dụ sau mục đích là để loại bỏ tất cả các ý kiến ​​từ các tài liệu:

Loại bỏ yếu tố

Một khi bạn có một tham chiếu đến một phần tử, bạn có thể rip nó ra khỏi cây với chiết xuất phương pháp. Đây đang loại bỏ tất cả các ý kiến ​​ từ một tài liệu:

from BeautifulSoup import BeautifulSoup, Comment 
soup = BeautifulSoup("""1<!--The loneliest number--> 
        <a>2<!--Can be as bad as one--><b>3""") 
comments = soup.findAll(text=lambda text:isinstance(text, Comment)) 
[comment.extract() for comment in comments] 
print soup 
# 1 
# <a>2<b>3</b></a> 
6

Câu trả lời ngắn: soup.findAll('p')[0].next

Bất trả lời: Bạn cần một điểm tham chiếu bất biến mà từ đó bạn có thể tới mục tiêu của bạn.

Bạn đề cập đến trong nhận xét của bạn về câu trả lời của Haidro rằng văn bản bạn muốn không phải lúc nào cũng ở cùng một nơi. Tìm một cảm giác trong đó nó ở cùng một vị trí liên quan đến một phần tử nào đó. Sau đó, tìm hiểu cách làm cho BeautifulSoup điều hướng cây phân tích theo sau đường dẫn bất biến đó.

Ví dụ: trong HTML bạn cung cấp trong bài đăng gốc, chuỗi đích xuất hiện ngay sau phần tử đoạn đầu tiên và đoạn đó không trống. Vì findAll('p') sẽ tìm các phần tử đoạn, soup.find('p')[0] sẽ là phần tử đoạn đầu tiên.

Trong trường hợp này, bạn có thể sử dụng soup.find('p') nhưng soup.findAll('p')[n] là tổng quát hơn vì có thể kịch bản thực tế của bạn cần đoạn thứ 5 hoặc thứ gì đó tương tự.

Thuộc tính trường next sẽ là phần tử được phân tích tiếp theo trong cây, bao gồm cả trẻ em. Vì vậy, soup.findAll('p')[0].next chứa văn bản của đoạn văn và soup.findAll('p')[0].next.next sẽ trả lại mục tiêu của bạn trong HTML được cung cấp.

9

với đối tượng súp của riêng bạn:

soup.p.next_sibling.strip() 
  1. bạn lấy <p> trực tiếp với soup.p * (điều này xoay quanh nó là người đầu tiên <p> trong cây phân tích cú pháp)
  2. sau đó sử dụng next_sibling trên đối tượng thẻ mà soup.p trả về vì văn bản mong muốn được lồng ở cùng một cấp độ của cây phân tích cú pháp là <p>
  3. .strip() chỉ là một phương pháp Python str để loại bỏ hàng đầu và dấu khoảng trắng

* nếu không chỉ cần find các yếu tố sử dụng lựa chọn của bạn filter (s)

trong thông dịch viên này trông giống như sau:

In [4]: soup.p 
Out[4]: <p>something</p> 

In [5]: type(soup.p) 
Out[5]: bs4.element.Tag 

In [6]: soup.p.next_sibling 
Out[6]: u'\n  THIS IS MY TEXT\n  ' 

In [7]: type(soup.p.next_sibling) 
Out[7]: bs4.element.NavigableString 

In [8]: soup.p.next_sibling.strip() 
Out[8]: u'THIS IS MY TEXT' 

In [9]: type(soup.p.next_sibling.strip()) 
Out[9]: unicode 
+0

Bạn có thể thêm một chút văn bản giải thích khác về cách câu trả lời cho câu hỏi này không? –

+0

vui mừng! (xem ở trên) –

0
soup = BeautifulSoup(html) 
for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
    hit = hit.text.strip() 
    print hit 

Điều này sẽ in: Đây là văn bản của tôi Hãy thử điều này ..

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