Python網絡爬蟲-BeautifulSoup使用

BeautifulSoup是一個強大的網頁解析工具,它藉助網頁的結構和屬性等特性來解析網頁。有了它就不用再去寫一些複雜的正則表達式來匹配我們想要的信息,只需要簡單的幾條語句就能完成網頁中某個元素的提取。

一、簡介

簡單來說,BeautifulSoup就是Python的一個HTML或XML的解析庫,可以用它來方便地從網頁中提取數據。官網的介紹如下:

  1. Beautiful Soup提供了一些簡單的方法和Pythonic習語,用於導航,搜索和修改解析樹:用於剖析文檔和提取所需內容的工具包。編寫應用程序不需要太多代碼。
  2. Beautiful Soup會自動將傳入的文檔轉換爲Unicode,將傳出的文檔轉換爲UTF-8。您不必考慮編碼,除非文檔未指定編碼且Beautiful Soup無法檢測到編碼。然後你只需要指定原始編碼。
  3. Beautiful Soup位於流行的Python解析器之上,如lxmlhtml5lib,允許您嘗試不同的解析策略或強勁速度以獲得靈活性。

所以說,使用它能夠省去很多繁瑣的提取工作,提高了解析效率。

在使用BeautifulSoup前,需要安裝BeautifulSoup,一般anaconda會包含這個庫不需要安裝,優先安裝anaconda3版本,省去很多安裝庫的麻煩。

二、基本用法

from bs4 import BeautifulSoup

html =  """
<html><head><title>The Dormouse’ s story</title></head>
<body >
<p class="story" name="dormouse">Once upon a time there were three little sisters; and their names were 
<a href="http://example.com/elsie" class="sister" id="linkl">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister1" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html, 'lxml')
print(soup.prettify())
print(soup.title.string)

運行上面程序可以看出,html變量是一個HTML字符串,但是它並不是標準的HTML文件比如缺失很多的節點body和html,但是調用prettify方法可以把需要解析的字符串以標準的HTML縮進格式輸出。soup.title.string實際上是輸出HTML中title節點的文本內容,所以soup.title可以選出HTML中的title節點,再調用string屬性就可以得到裏面的文本了,所以我們可以通過簡單的調用幾個屬性完成文本提取,十分方便。

三、節點選擇器

直接調用節點的名稱就可以選擇節點元素,再調用string屬性就能得到節點的內容,這種選擇方式速度非常快。如果單個節點結構層次非常清晰,可以選用這種方式來解析。

1.選擇元素

還是以剛剛的代碼爲例,下面新增幾行語句:

print(type(soup.title))
print(soup.head)
print(soup.p)

根據運行結果發現,soup.title是一個bs4.element.Tag類型,這是BeautifulSoup中一個重要的數據結構。經過選擇器選擇後,選擇結果都是這種Tag類型。Tag類型具有一些屬性,比如string,調用string屬性可以獲取節點的文本內容。

然後又選擇了head節點和p節點,結果是節點加其內部的所有內容。但是這裏值得注意的是只有第一個p節點被選擇出來,後面的p節點並沒有被選擇出來,因此這裏的節點選擇只會選擇到第一個匹配到的節點。

2.提取信息

2.1 獲取名稱

可以利用name屬性來獲取節點的名稱。這裏還是以上面的代碼爲例,新增如下代碼:

print(soup.title.name)

# 結果是title

2.2 獲取屬性

每個節點都有很多個屬性,比如id和class等,選擇某個節點後,可以調用attrs來獲取所有的屬性:?

print(soup.p.attrs)
print(soup.p.attrs['name'])
print(soup.p.attrs['class'])

#
{'class': ['story'], 'name': 'dromouse'}
dromouse
['story']

可以看到,attrs的返回結果是字典形式,它把選擇的節點的所有屬性和屬性之組合成一個字典,接下來如果想要獲取name屬性就相當與從字典中獲取某個健值,只需要用中括號加屬性名就可以了。比如獲取name屬性就可以通過attrs['name']來得到。

這樣的獲取步驟有點繁瑣,還可以通過更簡單的方式,跳過attrs,直接在節點元素後面加中括號,傳入屬性名就可以獲取屬性值了。

print(soup.p['name'])
print(soup.p['class'])

這裏需要注意的是,有的返回結果是字符串,有的返回是字符串列表。比如name屬性的值是唯一的,返回的就是單個字符串。而對於class,一個節點元素可能會有多個class,所以返回的是列表。在實際的處理過程中,需要注意判斷類型。

2.3 獲取內容

可以利用string屬性來獲取節點元素包含的文本內容,比如要獲取第一個p節點的文本:

<p class="title" name="xudong">ahahahahah</p>
print(soup.p.string)

3.嵌套選擇

在上面的例子中,我們知道每個節點選擇的返回結果都是bs4.element.Tag類型,它同樣可以繼續調用節點進行下一步的選擇。比如下面獲取了head節點,接着獲取head節點內部的其他節點元素:

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

#
<title>The Dormouse’ s story</title>
<class 'bs4.element.Tag'>
The Dormouse’ s story

4.其他選擇

當然除了上面的選擇外,還有選擇當前節點的子節點,父節點,兄弟節點等。這裏不作詳細介紹,後面用來再具體去查找使用方式。

print(soup.p.children)
print(soup.p.parent)
print(soup.a.next_sibling)
print(soup.a.previous_sibling)

四、方法選擇器

前面所講的選擇方法都是通過屬性來選擇的,這種方法非常快,但是如果進行比較複雜的選擇話,它的使用就比較的繁瑣,不夠靈活了。而BeautifulSoup爲我們提供了一些查詢方法,比如find_all()和find()等,調用它們,然後傳入相應的參數,就可以靈活查詢了。

1.find_all()方法

find_all,顧名思義,就是查詢所有符合條件的元素。給它傳入一些屬性或文本,就可以得到符合條件的元素,它的功能十分強大。其api如下:

find_all(name , attrs , recursive , text , **kwargs)
  • name:我麼可以根據節點名來查詢元素
  • attrs:根據屬性來查詢元素
  • text:根據文本參數來匹配,可以是字符串也可以是正則表達式
from bs4 import BeautifulSoup
import re


html =  """
<html><head><title>The Dormouse’ s story</title></head>
<body >
<p class="title" name="xudong">ahahahahah</p>
<p class="story", name="dromouse">Once upon a time there were three little sisters; and their names were 
<a href="http://example.com/elsie" class="sister" id="linkl">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister1" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html, 'lxml')

# 按照name來查詢
print(soup.find_all(name='a'))
# 按照attrs來查詢
print(soup.find_all(attrs={'class':'sister'}))
# 按照text來查詢
print(soup.find_all(text=re.compile('ie')))

# 結果返回
[<a class="sister" href="http://example.com/elsie" id="linkl">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
[<a class="sister" href="http://example.com/elsie" id="linkl">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
['Elsie', 'Lacie', 'Tillie']

2.find()方法

除了find_all()方法,還有find()方法,只不過後者返回的是單個元素,也就是第一個匹配的元素,而前者返回的是所有匹配的元素組成的列表。但是其類型依舊是Tag類型。這裏不再示例說明。

另外還有其他的查詢方法,如下:

  • find_parents()和find_parent():前者返回所有的祖先節點,後者返回直接父類節點。
  • find_next_siblings()和find_next_sibling():前者返回後面所有的兄弟節點,後者返回後面第一個兄弟節點。
  • find_previous_siblings()和find_previous_sibling():前者返回前面所有的兄弟節點,後者返回前面第一個兄弟節點。
  • find_all_next()和find_next():前者返回節點後所有符合條件的節點,後者類比。
  • find_all_previous()和find_previous():前者返回節點前所有符合條件的節點,後者類比。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章