小白學 Python 爬蟲(21):解析庫 Beautiful Soup(上)

小白學 Python 爬蟲(21):解析庫 Beautiful Soup(上)

人生苦短,我用 Pythonhtml

前文傳送門:html5

小白學 Python 爬蟲(1):開篇python

小白學 Python 爬蟲(2):前置準備(一)基本類庫的安裝git

小白學 Python 爬蟲(3):前置準備(二)Linux基礎入門github

小白學 Python 爬蟲(4):前置準備(三)Docker基礎入門數據庫

小白學 Python 爬蟲(5):前置準備(四)數據庫基礎瀏覽器

小白學 Python 爬蟲(6):前置準備(五)爬蟲框架的安裝框架

小白學 Python 爬蟲(7):HTTP 基礎ide

小白學 Python 爬蟲(8):網頁基礎函數

小白學 Python 爬蟲(9):爬蟲基礎

小白學 Python 爬蟲(10):Session 和 Cookies

小白學 Python 爬蟲(11):urllib 基礎使用(一)

小白學 Python 爬蟲(12):urllib 基礎使用(二)

小白學 Python 爬蟲(13):urllib 基礎使用(三)

小白學 Python 爬蟲(14):urllib 基礎使用(四)

小白學 Python 爬蟲(15):urllib 基礎使用(五)

小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖

小白學 Python 爬蟲(17):Requests 基礎使用

小白學 Python 爬蟲(18):Requests 進階操做

小白學 Python 爬蟲(19):Xpath 基操

小白學 Python 爬蟲(20):Xpath 進階

引言

首先固然是各類資料地址敬上:

先看下官方對本身的介紹:

Beautiful Soup 提供一些簡單的、 Python 式的函數來處理導航、搜索、修改分析樹等功能。它是一個工具箱,經過解析文檔爲用戶提供須要抓取的數據,由於簡單,因此不須要多少代碼就能夠寫出一個完整的應用程序。

Beautiful Soup 自動將輸入文檔轉換爲 Unicode 編碼,輸出文檔轉換爲 UTF-8 編碼。你不須要考慮編碼方式,除非文檔沒有指定一個編碼方式,這時你僅僅須要說明一下原始編碼方式就能夠了。

Beautiful Soup 已成爲和 lxml 、 html6lib 同樣出色的 Python 解釋器,爲用戶靈活地提供不一樣的解析策略或強勁的速度。

講人話就是 Beautiful Soup 是一個很是好用、速度又快的 HTML 或 XML 的解析庫。

Beautiful Soup 在解析時實際上依賴解析器,它除了支持Python標準庫中的HTML解析器外,還支持一些第三方解析器。下表列出了主要的解析器,以及它們的優缺點(如下內容來自:https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/# ):

解析器 使用方法 優點 劣勢
Python 標準庫 BeautifulSoup(markup, "html.parser") Python的內置標準庫、執行速度適中、文檔容錯能力強 Python 2.7.3 or 3.2.2)前 的版本中文檔容錯能力差
lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快、文檔容錯能力強 須要安裝C語言庫
lxml XML 解析器 BeautifulSoup(markup, ["lxml-xml"])BeautifulSoup(markup, "xml") 速度快、惟一支持XML的解析器 須要安裝C語言庫
html5lib BeautifulSoup(markup, "html5lib") 最好的容錯性、以瀏覽器的方式解析文檔、生成HTML5格式的文檔 速度慢、不依賴外部擴展

推薦使用 lxml 做爲解析器,由於效率更高。在 Python2.7.3 以前的版本和 Python3 中 3.2.2 以前的版本,必須安裝 lxml 或 html5lib ,由於那些 Python 版本的標準庫中內置的 HTML 解析方法不夠穩定。

提示: 若是一段 HTML 或 XML 文檔格式不正確的話,那麼在不一樣的解析器中返回的結果多是不同的,查看 解析器之間的區別 瞭解更多細節。

基本操做

爬取對象仍是小編的我的博客(小編看着博客的流量在暗暗心痛)。最基本的,仍是先打印首頁的 HTML 源碼,使用的類庫爲 Requests + bs4。

import requests
from bs4 import BeautifulSoup

response = requests.get('https://www.geekdigging.com/')
soup = BeautifulSoup(response.content, "html5lib")
print(soup.prettify())

結果就不貼了,太長,浪費你們翻頁的時間。

首先先解釋一下這裏爲何選擇了 html5lib 的解析器而不是 lxml 的解析器,由於通過小編測試 lxml 的解析器沒法解析某些 HTML 標籤,通過小編的測試,使用 Python 標準庫或者 html5lib 解析器都無此問題,因此這裏選擇使用 Python 標準庫。

上面這段代碼主要是調用了 prettify() ,這個方法的主要做用是把要解析的字符串以標準的縮進格式輸出。值得注意的是,這裏的輸出會自動更正 HTML 的格式,可是這一步並非由 prettify() 這個方法來作的,而是在初始化 BeautifulSoup 時就完成了。

節點選擇

咱們使用 Beautiful Soup 的目的是什麼?固然是要選擇咱們須要的節點,並從節點中提取出咱們須要的數據。

Beautiful Soup 將複雜 HTML 文檔轉換成一個複雜的樹形結構,每一個節點都是 Python 對象,全部對象能夠概括爲4種: Tag , NavigableString , BeautifulSoup , Comment

咱們直接調用節點的名稱就能夠選擇節點元素,再調用 string 屬性就能夠獲得節點內的文本了,這種選擇方式速度很是快。

print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.a)

結果以下:

<title>極客挖掘機</title>
<class 'bs4.element.Tag'>
極客挖掘機
<a class="logo" href="/">
<img src="/favicon.jpg" style="margin-right: 10px;"/>極客挖掘機
</a>

能夠看到,咱們這裏直接輸出的 title 節點,它的類型是 bs4.element.Tag ,而且使用 string 屬性,直接獲得了該節點的內容。

這裏咱們打印了 a 節點,能夠看到,只打印出來了第一個 a 節點,後面的節點並未打印,說明當有多個節點時,這種方式只能得到第一個節點。

獲取名稱

每一個 tag 都有本身的名字,經過 .name 來獲取:

tag = soup.section
print(tag.name)

結果以下:

section

獲取屬性

一個 tag 可能有不少個屬性, tag 的屬性的操做方法與字典相同:

print(tag['class'])

結果以下:

['content-wrap']

也能夠直接」點」取屬性, 好比: .attrs

print(tag.attrs)

結果以下:

{'class': ['content-wrap']}

獲取內容

能夠利用 string 屬性獲取節點元素包含的文本內容,好比要獲取 title 標籤的內容:

print(soup.title.string)

結果以下:

極客挖掘機

嵌套選擇

在上面的示例中,咱們的信息都是從經過 tag 的屬性得到的,固然 tag 是能夠繼續嵌套的選擇下去,好比咱們剛纔獲取了第一個 a 標籤,咱們能夠繼續獲取其中的 img 標籤:

print(soup.a.img)
print(type(soup.a.img))
print(soup.a.img.attrs)

結果以下:

<img src="/favicon.jpg" style="margin-right: 10px;"/>
<class 'bs4.element.Tag'>
{'src': '/favicon.jpg', 'style': 'margin-right: 10px;'}

能夠看到咱們在 a 標籤上繼續選擇的 img 標籤,它的類型依然是 bs4.element.Tag ,而且咱們成功的獲取了 img 標籤的屬性值,也就是說,咱們在 Tag 類型的基礎上再次選擇獲得的依然仍是 Tag 類型,因此這樣就能夠作嵌套選擇了。

關聯選擇

在選擇節點的時候,咱們不多能夠一步到位,直接選到所須要的節點,這就須要咱們先選中其中的某一個節點,再已它爲基準,再選擇它的子節點、父節點或者兄弟節點。

子節點

獲取子節點,咱們能夠選擇使用 contents 屬性,示例以下:

print(soup.article.contents)

結果太長了,小編就不貼了,這裏輸出了第一個 article 的全部節點,而且返回結果是列表形式。 article 節點裏既包含文本,又包含節點,最後會將它們以列表形式統一返回。

這裏須要注意的是,列表中的每一個元素都是 article 的直接子節點,並無將再下一級的元素列出來。而使用 children 也能夠獲得相同的效果。

for child in enumerate(soup.article.children):
    print(child)

結果獲得的仍是相同的的 HTML 文本,這裏調用了 children 屬性來選擇,返回結果是生成器類型。

想要獲得全部的孫子節點的話,可使用 descendants

for i, child in enumerate(soup.article.descendants):
    print(i, child)

父節點

獲取父節點可使用 parent 屬性,示例以下:

print(soup.title.parent)

結果有些長,就不貼了,各位同窗能夠自行嘗試一下。

兄弟節點

想要獲取兄弟節點可使用屬性 next_siblingprevious_sibling

print('next_sibling:', soup.title.next_sibling)
print('previous_sibling:', soup.title.previous_sibling)
print('next_siblings:', soup.title.next_siblings)
print('previous_siblings:', soup.title.previous_siblings)

結果以下:

next_sibling: 


    
previous_sibling: 



next_siblings: <generator object PageElement.next_siblings at 0x00000183342C5D48>
previous_siblings: <generator object PageElement.previous_siblings at 0x00000183342C5D48>

能夠看到, next_sibling 和 previous_sibling 分別獲取節點的下一個和上一個兄弟元素,在這裏並無獲取到值,而是獲取了不少的空行,這個是在初始化 BeautifulSoup 的時候初始化出來的,而 next_siblings 和 previous_siblings 則分別返回全部前面和後面的兄弟節點的生成器。

示例代碼

本系列的全部代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便你們取用。

示例代碼-Github

示例代碼-Gitee

參考

https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/#

相關文章
相關標籤/搜索