Beautiful Soup - Điều hướng theo thẻ
Trong chương này, chúng ta sẽ thảo luận về Điều hướng bằng Thẻ.
Dưới đây là tài liệu html của chúng tôi -
>>> html_doc = """
<html><head><title>Tutorials Point</title></head>
<body>
<p class="title"><b>The Biggest Online Tutorials Library, It's all Free</b></p>
<p class="prog">Top 5 most used Programming Languages are:
<a href="https://www.tutorialspoint.com/java/java_overview.htm" class="prog" id="link1">Java</a>,
<a href="https://www.tutorialspoint.com/cprogramming/index.htm" class="prog" id="link2">C</a>,
<a href="https://www.tutorialspoint.com/python/index.htm" class="prog" id="link3">Python</a>,
<a href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" class="prog" id="link4">JavaScript</a> and
<a href="https://www.tutorialspoint.com/ruby/index.htm" class="prog" id="link5">C</a>;
as per online survey.</p>
<p class="prog">Programming Languages</p>
"""
>>>
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(html_doc, 'html.parser')
>>>
Dựa trên tài liệu trên, chúng tôi sẽ cố gắng chuyển từ phần này sang phần khác.
Đi xuống
Một trong những thành phần quan trọng trong bất kỳ phần nào của tài liệu HTML là các thẻ, có thể chứa các thẻ / chuỗi khác (con của thẻ). Beautiful Soup cung cấp các cách khác nhau để điều hướng và lặp lại các thẻ con của thẻ.
Điều hướng bằng tên thẻ
Cách dễ nhất để tìm kiếm cây phân tích cú pháp là tìm kiếm thẻ theo tên của nó. Nếu bạn muốn thẻ <head>, hãy sử dụng soup.head -
>>> soup.head
<head>&t;title>Tutorials Point</title></head>
>>> soup.title
<title>Tutorials Point</title>
Để nhận thẻ cụ thể (như thẻ <b> đầu tiên) trong thẻ <body>.
>>> soup.body.b
<b>The Biggest Online Tutorials Library, It's all Free</b>
Sử dụng tên thẻ làm thuộc tính sẽ chỉ cung cấp cho bạn thẻ đầu tiên có tên đó -
>>> soup.a
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
Để lấy tất cả thuộc tính của thẻ, bạn có thể sử dụng phương thức find_all () -
>>> soup.find_all("a")
[<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>, <a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>, <a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>, <a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>, <a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>]>>> soup.find_all("a")
[<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>, <a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>, <a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>, <a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>, <a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>]
.contents và .children
Chúng tôi có thể tìm kiếm thẻ con của thẻ trong danh sách theo .contents -
>>> head_tag = soup.head
>>> head_tag
<head><title>Tutorials Point</title></head>
>>> Htag = soup.head
>>> Htag
<head><title>Tutorials Point</title></head>
>>>
>>> Htag.contents
[<title>Tutorials Point</title>
>>>
>>> Ttag = head_tag.contents[0]
>>> Ttag
<title>Tutorials Point</title>
>>> Ttag.contents
['Tutorials Point']
Bản thân đối tượng BeautifulSoup có con. Trong trường hợp này, thẻ <html> là con của đối tượng BeautifulSoup -
>>> len(soup.contents)
2
>>> soup.contents[1].name
'html'
Một chuỗi không có .contents, vì nó không thể chứa bất cứ thứ gì -
>>> text = Ttag.contents[0]
>>> text.contents
self.__class__.__name__, attr))
AttributeError: 'NavigableString' object has no attribute 'contents'
Thay vì lấy chúng dưới dạng danh sách, hãy sử dụng trình tạo .children để truy cập vào thẻ con của thẻ -
>>> for child in Ttag.children:
print(child)
Tutorials Point
.hậu duệ
Thuộc tính .descendants cho phép bạn lặp lại trên tất cả các thẻ con của thẻ, một cách đệ quy -
con trực hệ của nó và con của những đứa con trực hệ của nó, v.v. -
>>> for child in Htag.descendants:
print(child)
<title>Tutorials Point</title>
Tutorials Point
Thẻ <head> chỉ có một con, nhưng nó có hai con: thẻ <title> và con của thẻ <title>. Đối tượng beautifulsoup chỉ có một con trực tiếp (thẻ <html>), nhưng nó có rất nhiều con -
>>> len(list(soup.children))
2
>>> len(list(soup.descendants))
33
.chuỗi
Nếu thẻ chỉ có một con và con đó là một Chuỗi điều hướng, thì con đó sẽ có sẵn dưới dạng .string -
>>> Ttag.string
'Tutorials Point'
Nếu thẻ con duy nhất của thẻ là một thẻ khác và thẻ đó có .string, thì thẻ mẹ được coi là có cùng .string với thẻ con của nó -
>>> Htag.contents
[<title>Tutorials Point</title>]
>>>
>>> Htag.string
'Tutorials Point'
Tuy nhiên, nếu thẻ chứa nhiều hơn một thứ, thì không rõ .string nên tham chiếu đến cái gì, vì vậy .string được định nghĩa là Không có -
>>> print(soup.html.string)
None
.strings và stripe_strings
Nếu có nhiều thứ bên trong thẻ, bạn vẫn có thể chỉ xem các chuỗi. Sử dụng trình tạo .strings -
>>> for string in soup.strings:
print(repr(string))
'\n'
'Tutorials Point'
'\n'
'\n'
"The Biggest Online Tutorials Library, It's all Free"
'\n'
'Top 5 most used Programming Languages are: \n'
'Java'
',\n'
'C'
',\n'
'Python'
',\n'
'JavaScript'
' and\n'
'C'
';\n \nas per online survey.'
'\n'
'Programming Languages'
'\n'
Để loại bỏ khoảng trắng thừa, hãy sử dụng trình tạo .stripped_strings -
>>> for string in soup.stripped_strings:
print(repr(string))
'Tutorials Point'
"The Biggest Online Tutorials Library, It's all Free"
'Top 5 most used Programming Languages are:'
'Java'
','
'C'
','
'Python'
','
'JavaScript'
'and'
'C'
';\n \nas per online survey.'
'Programming Languages'
Đi lên
Trong phép tương tự "cây gia đình", mọi thẻ và mọi chuỗi đều có cha mẹ: thẻ chứa nó:
.cha mẹ
Để truy cập phần tử mẹ của phần tử, hãy sử dụng thuộc tính .parent.
>>> Ttag = soup.title
>>> Ttag
<title>Tutorials Point</title>
>>> Ttag.parent
<head>title>Tutorials Point</title></head>
Trong html_doc của chúng tôi, bản thân chuỗi tiêu đề có cha mẹ: thẻ <title> chứa nó−
>>> Ttag.string.parent
<title>Tutorials Point</title>
Cấp độ gốc của thẻ cấp cao nhất như <html> là chính đối tượng Beautifulsoup -
>>> htmltag = soup.html
>>> type(htmltag.parent)
<class 'bs4.BeautifulSoup'>
.Parent của một đối tượng Beautifulsoup được định nghĩa là Không có -
>>> print(soup.parent)
None
.cha mẹ
Để lặp lại tất cả các phần tử cha mẹ, hãy sử dụng thuộc tính .arent.
>>> link = soup.a
>>> link
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
>>>
>>> for parent in link.parents:
if parent is None:
print(parent)
else:
print(parent.name)
p
body
html
[document]
Đi ngang
Dưới đây là một tài liệu đơn giản -
>>> sibling_soup = BeautifulSoup("<a><b>TutorialsPoint</b><c><strong>The Biggest Online Tutorials Library, It's all Free</strong></b></a>")
>>> print(sibling_soup.prettify())
<html>
<body>
<a>
<b>
TutorialsPoint
</b>
<c>
<strong>
The Biggest Online Tutorials Library, It's all Free
</strong>
</c>
</a>
</body>
</html>
Trong tài liệu trên, thẻ <b> và <c> ở cùng cấp và cả hai đều là con của cùng một thẻ. Cả thẻ <b> và <c> đều là anh em ruột.
.next_sibling và .previous_sibling
Sử dụng .next_sibling và .previous_sibling để điều hướng giữa các phần tử trang ở cùng cấp của cây phân tích cú pháp:
>>> sibling_soup.b.next_sibling
<c><strong>The Biggest Online Tutorials Library, It's all Free</strong></c>
>>>
>>> sibling_soup.c.previous_sibling
<b>TutorialsPoint</b>
Thẻ <b> có .next_sibling nhưng không có .previous_sibling, vì không có gì trước thẻ <b> ở cùng cấp của cây, trường hợp tương tự với thẻ <c>.
>>> print(sibling_soup.b.previous_sibling)
None
>>> print(sibling_soup.c.next_sibling)
None
Hai chuỗi không phải là anh em ruột, vì chúng không có cùng cha mẹ.
>>> sibling_soup.b.string
'TutorialsPoint'
>>>
>>> print(sibling_soup.b.string.next_sibling)
None
.next_siblings và .previous_siblings
Để lặp lại các thẻ anh chị em của thẻ, hãy sử dụng .next_siblings và .previous_siblings.
>>> for sibling in soup.a.next_siblings:
print(repr(sibling))
',\n'
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>
',\n'
>a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>
',\n'
<a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>
' and\n'
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm"
id="link5">C</a>
';\n \nas per online survey.'
>>> for sibling in soup.find(id="link3").previous_siblings:
print(repr(sibling))
',\n'
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>
',\n'
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
'Top 5 most used Programming Languages are: \n'
Quay đi quay lại
Bây giờ chúng ta hãy quay lại hai dòng đầu tiên trong ví dụ “html_doc” trước đây của chúng tôi -
&t;html><head><title>Tutorials Point</title></head>
<body>
<h4 class="tagLine"><b>The Biggest Online Tutorials Library, It's all Free</b></h4>
Trình phân tích cú pháp HTML lấy chuỗi ký tự phía trên và biến nó thành một chuỗi sự kiện như “mở thẻ <html>”, “mở thẻ <head>”, “mở thẻ <title>”, “thêm chuỗi”, “Đóng thẻ </title>”, “đóng thẻ </head>”, “mở thẻ <h4>”, v.v. BeautifulSoup cung cấp các phương pháp khác nhau để tạo lại phân tích cú pháp ban đầu của tài liệu.
.next_element và .previous_element
Thuộc tính .next_element của thẻ hoặc chuỗi trỏ đến bất kỳ thứ gì được phân tích cú pháp ngay sau đó. Đôi khi nó trông giống với .next_sibling, tuy nhiên nó không giống hoàn toàn. Dưới đây là thẻ <a> cuối cùng trong tài liệu mẫu “html_doc” của chúng tôi.
>>> last_a_tag = soup.find("a", id="link5")
>>> last_a_tag
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>
>>> last_a_tag.next_sibling
';\n \nas per online survey.'
Tuy nhiên, .next_element của thẻ <a> đó, thứ được phân tích cú pháp ngay sau thẻ <a>, không phải là phần còn lại của câu đó: nó là từ “C”:
>>> last_a_tag.next_element
'C'
Hành vi trên là do trong đánh dấu ban đầu, chữ “C” đã xuất hiện trước dấu chấm phẩy đó. Trình phân tích cú pháp gặp thẻ <a>, sau đó là chữ cái “C”, sau đó là thẻ đóng </a>, sau đó là dấu chấm phẩy và phần còn lại của câu. Dấu chấm phẩy ở cùng cấp với thẻ <a>, nhưng chữ “C” đã xuất hiện đầu tiên.
Thuộc tính .previous_element hoàn toàn ngược lại với .next_element. Nó trỏ đến bất kỳ phần tử nào đã được phân tích cú pháp ngay trước phần tử này.
>>> last_a_tag.previous_element
' and\n'
>>>
>>> last_a_tag.previous_element.next_element
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>
.next_elements và .previous_elements
Chúng tôi sử dụng các trình vòng lặp này để di chuyển tới và lùi tới một phần tử.
>>> for element in last_a_tag.next_e lements:
print(repr(element))
'C'
';\n \nas per online survey.'
'\n'
<p class="prog">Programming Languages</p>
'Programming Languages'
'\n'