首頁 >後端開發 >Python教學 >python爬蟲入門(4)--詳解HTML文字的解析庫BeautifulSoup

python爬蟲入門(4)--詳解HTML文字的解析庫BeautifulSoup

零下一度
零下一度原創
2017-05-27 11:55:392220瀏覽

Beautiful Soup是python的一個函式庫,最主要的功能是從網頁抓取資料。以下這篇文章主要給大家介紹了python爬蟲之HTML文本的解析庫BeautifulSoup的相關資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。

前言

python爬蟲系列文章的第3篇介紹了網路請求庫神器Requests ,請求把資料回傳後就要提取目標數據,不同的網站返回的內容通常有多種不同的格式,一種是json 格式,這類數據對開發者來說最友好。另一種XML 格式的,還有一種最常見格式的是HTML 文檔,今天就來講講如何從HTML 中提取出感興趣的數據

自己寫個HTML 解析器來解析嗎?還是用正規表示式?這些都不是最好的辦法,好在,Python 社群在這方便早就有了很成熟的方案,BeautifulSoup 就是這一類問題的剋星,它專注於HTML 文檔操作,名字來自Lewis Carroll 的一首同名詩歌。

BeautifulSoup 是一個用於解析HTML 文件的Python 庫,透過BeautifulSoup,你只需要用很少的程式碼就可以提取出HTML 中任何感興趣的內容,此外,它還有一定的HTML 容錯能力,對於一個格式不完整的HTML 文檔,它也可以正確處理。

安裝 BeautifulSoup

pip install beautifulsoup4

BeautifulSoup3 被官方放棄維護,你要下載最新的版本 BeautifulSoup4。

HTML 標籤

學習BeautifulSoup4 前有必要先對HTML 文件有一個基本認識,如下程式碼,HTML 是一個樹形組織結構。

<html> 
 <head>
  <title>hello, world</title>
 </head>
 <body>
  <h1>BeautifulSoup</h1>
  <p>如何使用BeautifulSoup</p>
 <body>
</html>
  • 它由許多標籤(Tag)組成,例如html、head、title等等都是標籤

  • 一個標籤對構成一個節點,例如... 是一個根節點

  • 節點之間存在某種關係,例如h1 和p 互為鄰居,他們是相鄰的兄弟(sibling)節點

  • h1 是body 的直接子(children)節點,還是html 的子孫(descendants)節點

  • body 是p 的父(parent)節點,html 是p 的祖輩(parents)節點

  • 嵌套在標籤之間的字串是該節點下的一個特殊子節點,例如“hello, world” 也是一個節點,只不過沒名字。

使用BeautifulSoup

#建構一個BeautifulSoup 物件需要兩個參數,第一個參數是將要解析的HTML文字字串,第二個參數告訴BeautifulSoup 使用哪個解析器來解析HTML。

解析器負責把 HTML 解析成相關的對象,而 BeautifulSoup 負責操作資料(增刪改查)。 ”html.parser” 是Python內建的解析器,”lxml” 則是基於c語言開發的解析器,它的執行速度更快,不過它需要額外安裝

透過BeautifulSoup 物件就可以定位到HTML 中的任何一個標籤節點。

from bs4 import BeautifulSoup 
text = """
<html> 
 <head>
  <title >hello, world</title>
 </head>
 <body>
  <h1>BeautifulSoup</h1>
  <p class="bold">如何使用BeautifulSoup</p>
  <p class="big" id="key1"> 第二个p标签</p>
  <a href="http://foofish.net" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >python</a>
 </body>
</html> 
"""
soup = BeautifulSoup(text, "html.parser")

# title 标签
>>> soup.title
<title>hello, world</title>

# p 标签
>>> soup.p
<p class="bold">\u5982\u4f55\u4f7f\u7528BeautifulSoup</p>

# p 标签的内容
>>> soup.p.string
u&#39;\u5982\u4f55\u4f7f\u7528BeautifulSoup&#39;

BeatifulSoup 將 HTML 抽象化為 4 類主要的資料類型,分別是Tag , NavigableString , BeautifulSoup,Comment 。每個標籤節點就是一個Tag對象,NavigableString 物件一般是包裹在Tag物件中的字串,BeautifulSoup 物件代表整個 HTML 文件。例如:

>>> type(soup)
<class &#39;bs4.BeautifulSoup&#39;>
>>> type(soup.h1)
<class &#39;bs4.element.Tag&#39;>
>>> type(soup.p.string)
<class &#39;bs4.element.NavigableString&#39;>

Tag

每個 Tag 都有一個名字,它對應 HTML 的標籤名稱。


>>> soup.h1.name
u&#39;h1&#39;
>>> soup.p.name
u&#39;p&#39;

標籤也可以有屬性,屬性的存取方式和字典是類似的,它會傳回一個清單物件

>>> soup.p[&#39;class&#39;]
[u&#39;bold&#39;]

NavigableString

取得標籤中的內容,直接使用.stirng 即可取得,它是一個NavigableString 對象,你可以明確地將它轉換為unicode 字串。

>>> soup.p.string
u&#39;\u5982\u4f55\u4f7f\u7528BeautifulSoup&#39;
>>> type(soup.p.string)
<class &#39;bs4.element.NavigableString&#39;>
>>> unicode_str = unicode(soup.p.string)
>>> unicode_str
u&#39;\u5982\u4f55\u4f7f\u7528BeautifulSoup&#39;

基本概念介紹完,現在可以正式進入主題了,如何從 HTML 找到我們關心的資料? BeautifulSoup 提供了兩種方式,一種是遍歷,另一種是搜索,通常兩者結合來完成查找任務。

遍歷文檔樹

遍歷文檔樹,顧名思義,就是從根節點html 標籤開始遍歷,直到找到目標元素為止,遍歷的一個缺陷是,如果你要找的內容在文件的末尾,那麼它要遍歷整個文件才能找到它,速度上就慢了。因此還需要配合第二種方法。

透過遍歷文件樹的方式取得標籤節點可以直接透過 .標籤名的方式獲取,例如:

取得 body 標籤:

#
>>> soup.body
<body>\n<h1>BeautifulSoup</h1>\n<p class="bold">\u5982\u4f55\u4f7f\u7528BeautifulSoup</p>\n</body>

获取 p 标签

>>> soup.body.p
<p class="bold">\u5982\u4f55\u4f7f\u7528BeautifulSoup</p>

获取 p 标签的内容

>>> soup.body.p.string
\u5982\u4f55\u4f7f\u7528BeautifulSoup

前面说了,内容也是一个节点,这里就可以用 .string 的方式得到。遍历文档树的另一个缺点是只能获取到与之匹配的第一个子节点,例如,如果有两个相邻的 p 标签时,第二个标签就没法通过 .p 的方式获取,这是需要借用 next_sibling 属性获取相邻且在后面的节点。此外,还有很多不怎么常用的属性,比如:.contents 获取所有子节点,.parent 获取父节点,更多的参考请查看官方文档。

搜索文档树

搜索文档树是通过指定标签名来搜索元素,另外还可以通过指定标签的属性值来精确定位某个节点元素,最常用的两个方法就是 find 和 find_all。这两个方法在 BeatifulSoup 和 Tag 对象上都可以被调用。

find_all()

find_all( name , attrs , recursive , text , **kwargs )

find_all 的返回值是一个 Tag 组成的列表,方法调用非常灵活,所有的参数都是可选的。

第一个参数 name 是标签节点的名字。

# 找到所有标签名为title的节点
>>> soup.find_all("title")
[<title>hello, world</title>]
>>> soup.find_all("p")
[<p class="bold">\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup</p>, 
<p class="big"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]

第二个参数是标签的class属性值

# 找到所有class属性为big的p标签
>>> soup.find_all("p", "big")
[<p class="big"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]

等效于

>>> soup.find_all("p", class_="big")
[<p class="big"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]

因为 class 是 Python 关键字,所以这里指定为 class_。

kwargs 是标签的属性名值对,例如:查找有href属性值为 "http://foofish.net" 的标签

>>> soup.find_all(href="foofish.net" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" )
[<a href="foofish.net" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >python</a>]

当然,它还支持正则表达式

>>> import re
>>> soup.find_all(href=re.compile("^http"))
[<a href="http://foofish.net" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >python</a>]

属性除了可以是具体的值、正则表达式之外,它还可以是一个布尔值(True/Flase),表示有属性或者没有该属性。

>>> soup.find_all(id="key1")
[<p class="big" id="key1"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]
>>> soup.find_all(id=True)
[<p class="big" id="key1"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]

遍历和搜索相结合查找,先定位到 body 标签,缩小搜索范围,再从 body 中找 a 标签。

>>> body_tag = soup.body
>>> body_tag.find_all("a")
[<a href="http://foofish.net" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >python</a>]

find()

find 方法跟 find_all 类似,唯一不同的地方是,它返回的单个 Tag 对象而非列表,如果没找到匹配的节点则返回 None。如果匹配多个 Tag,只返回第0个。

>>> body_tag.find("a")
<a href="foofish.net" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >python</a>
>>> body_tag.find("p")
<p class="bold">\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup</p>

get_text()

获取标签里面内容,除了可以使用 .string 之外,还可以使用 get_text 方法,不同的地方在于前者返回的一个 NavigableString 对象,后者返回的是 unicode 类型的字符串。

>>> p1 = body_tag.find(&#39;p&#39;).get_text()
>>> type(p1)
<type &#39;unicode&#39;>
>>> p1
u&#39;\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup&#39;

>>> p2 = body_tag.find("p").string
>>> type(p2)
<class &#39;bs4.element.NavigableString&#39;>
>>> p2
u&#39;\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup&#39;
>>>

实际场景中我们一般使用 get_text 方法获取标签中的内容。

总结

BeatifulSoup 是一个用于操作 HTML 文档的 Python 库,初始化 BeatifulSoup 时,需要指定 HTML 文档字符串和具体的解析器。BeatifulSoup 有3类常用的数据类型,分别是 Tag、NavigableString、和 BeautifulSoup。查找 HTML元素有两种方式,分别是遍历文档树和搜索文档树,通常快速获取数据需要二者结合。

【相关推荐】

1. python爬虫入门(5)--正则表达式实例教程

2. python爬虫入门(3)--利用requests构建知乎API

3. python爬虫入门(2)--HTTP库requests

4.  总结Python的逻辑运算符and

5. python爬虫入门(1)--快速理解HTTP协议

以上是python爬蟲入門(4)--詳解HTML文字的解析庫BeautifulSoup的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn