python爬蟲經常使用庫之BeautifulSoup詳解

這是平常學python的第16篇原創文章
css

通過了前面幾篇文章的學習,估計你已經會爬很多中小型網站了。可是有人說,前面的正則很難唉,學很差。正則的確很難,有人說過:若是一個問題用正則解決,那麼就變成了兩個問題。因此說學不會是很正常的,不怕,除了正則,咱們還能夠用另一個強大的庫來解析html。因此,今天的主題就是來學習這個強大的庫--BeautifulSoup,不過正則仍是須要多多練習下的。html


由於是第三方庫因此咱們須要下載,在命令行敲下如下代碼進行下載
html5

pip install beautifulsoup4
python

安裝第三方解析庫
瀏覽器

pip install lxml
app

pip install html5lib
python爬蟲

若是不知道有什麼用請往下看ide

1.相關解析庫的介紹學習


這裏官方推薦解析庫爲lxml,由於它的效率高。下面都是用lxml解析庫來進行解析的。網站

2.詳細語法介紹

本文是進行解析豆瓣圖書首頁book.douban.com/

1)建立bs對象

from bs4 import BeautifulSoup
import requests
response = requests.get('https://book.douban.com/').text
# print(response)
# 建立bs對象
soup = BeautifulSoup(response, 'lxml')  # 使用到了lxml解析庫

2)獲取相關標籤

標籤:

<a data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>

上面的a就是一個標籤名字,最簡單的就是<a></a>這樣,能夠簡單理解爲<>裏面的第一個單詞就是標籤名


# 獲取標籤
print(soup.li)  # 這個只是獲取第一個li標籤
# 結果
<li class="">
<a data-moreurl-dict='{"from":
"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
</li>

3)獲取標籤的名字和內容

標籤的名字和內容:

<a >豆瓣</a>

如上面所說,a就是標籤名字,而兩個標籤之中所夾雜的內容就是咱們所說的內容,如上,豆瓣就是該標籤的內容

# 獲取標籤名字
print(soup.li.name)
# 獲取標籤內容
print(soup.li.string)  # 這個只能是這個標籤沒有子標籤才能正確獲取,不然會返回None
# 結果
li
None

因爲這個li標籤裏面還有個子標籤,因此它的文本內容爲None

下面這個就能夠獲取它的文本內容

# 獲取標籤內的標籤
print(soup.li.a)
print(soup.li.a.string)  # 這個標籤沒有子標籤因此能夠獲取到內容
# 結果
<a data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
豆瓣

4)獲取標籤屬性,有兩種方法

標籤屬性:

<a href="https://www.douban.com" target="_blank">豆瓣</a>

能夠簡單理解爲屬性就是在標籤名字旁邊並且在前一個<>符號裏面的,還有是有等號來進行體現的。因此上面的href就是標籤屬性名字,等號右邊的就是屬性的值,上面的值是個網址

# 獲取標籤屬性
print(soup.li.a['href'])  # 第一種
print(soup.li.a.attrs['href'])  # 第二種
# 結果
https://www.douban.com
https://www.douban.com

5)獲取標籤內的子標籤

子標籤:

<li><a>豆瓣</a></li>

好比咱們如今獲取的li標籤,因此a標籤就是li標籤子標籤

# 獲取標籤內的標籤
print(soup.li.a)
# 結果
<a data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>

6)獲取全部子節點

子節點:這個和子標籤是差很少的,只不過這裏是獲取一個標籤下的全部子標籤,上面的只是獲取最接近該標籤的子標籤

# 獲取子節點
print(soup.div.contents)  # 返回一個列表 第一種方法
for n, tag in enumerate(soup.div.contents):
   print(n, tag)
# 結果
['\n', <div class="bd">
<div class="top-nav-info">
<a class="nav-login" href="https:
//www.douban.com/accounts/login?source=book" rel="nofollow">登陸</a>
...
0

1 <div class="
bd">
<div class="
top-nav-info">
...

這個是獲取div下的全部子節點,.content就是獲取子節點的屬性

7)第二種方法獲取全部子節點

# 第二種方法
print(soup.div.children)  # 返回的是一個迭代器
for n, tag in enumerate(soup.div.children):
   print(n, tag)

這個是用.children獲取全部的子節點,這個方法返回的是一個迭代器

8)獲取標籤的子孫節點,就是全部後代

子孫節點:

<ul>
<li>
<a>豆瓣</a>
</li>
</ul>

從上面知道,li標籤ul標籤子標籤a標籤li標籤子標籤,若此時咱們獲取的是ul標籤,因此li標籤和a標籤都是ul標籤的子孫節點

# 獲取標籤的子孫節點
print(soup.div.descendants)  # 返回的是一個迭代器
for n, tag in enumerate(soup.div.descendants):
   print(n, tag)
# 結果
...
<generator object descendants at 0x00000212C1A1E308>
0

1 <div class="bd">
<div class="top-nav-info">
<a class="nav-login" href="https:
//www.douban.com/accounts/login?source=book" rel="nofollow">登陸</a>
...

這裏用到了.descendants屬性,獲取的是div標籤的子孫節點,並且返回結果是一個迭代器

9)獲取父節點和全部祖先節點

既然有了子節點和子孫節點,反過來也是有父節點和祖先節點的,因此都很容易理解的

# 獲取父節點
print(soup.li.parent)  # 返回整個父節點
# 獲取祖先節點
print(soup.li.parents)  # 返回的是一個生成器
for n, tag in enumerate(soup.li.parents):
   print(n, tag)

.parent屬性是獲取父節點,返回來的是整個父節點,裏面包含該子節點。.parents就是獲取全部的祖先節點,返回的是一個生成器

10)獲取兄弟節點

兄弟節點:

<ul>
<li>
<a>豆瓣1</a>
</li>
<li>
<a>豆瓣2</a>
</li>
<li>
<a>豆瓣3</a>
</li>
</ul>

好比上面的html代碼,裏面的li標籤都是ul標籤的子節點,而li標籤都是處於同級的,因此上面的li標籤都是各自的兄弟。這就是兄弟節點。

# 獲取兄弟節點
print(soup.li.next_siblings)  # 獲取該標籤的全部同級節點,不包括自己  返回的是一個生成器
for x in soup.li.next_siblings:
   print(x)
# 結果
<generator object next_siblings at 0x000002A04501F308>
<li class="on">
<a data-moreurl-dict='{"from":
"top-nav-click-book","uid":"0"}' href="https://book.douban.com">讀書</a>
</li>
...

.next_siblings屬性是獲取該標籤的全部在他後面的兄弟節點,不包括他自己。同時返回結果也是一個迭代器

同理,既然有獲取他的下一個全部兄弟標籤,也有獲取他前面的全部兄弟標籤

soup.li.previous_siblings

若是隻是獲取一個便可,能夠選擇把上面的屬性後面的s字母去掉便可,以下

soup.li.previous_sibling  # 獲取前一個兄弟節點
soup.li.next_sibling  # 獲取後一個兄弟節點

3.bs庫的更高級的用法

在前面咱們能夠獲取標籤的名字、屬性、內容和全部的祖孫標籤。可是當咱們須要獲取任意一個指定屬性的標籤仍是有點困難的,因此,此時有了下面這個方法:

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

  • name:須要獲取的標籤名

  • attrs:接收一個字典,爲屬性的鍵值,或者直接用關鍵字參數來替代也能夠,下面

  • recursive:設置是否搜索直接子節點

  • text:對應的字符串內容

  • limit:設置搜索的數量

1)先使用name參數來進行搜索

# 先使用name參數
print(soup.find_all('li'))  # 返回一個列表,全部的li標籤名字
# 結果
[<li class="">
<a data-moreurl-dict='{"from":
"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
</li>, <li class="on">
...

這裏獲取了全部標籤名字爲li的標籤

2)使用name和attrs參數

# 使用name和attrs參數
print(soup.find_all('div', {'class': 'more-meta'}))  # 這個對上個進行了篩選,屬性參數填的是一個字典類型的
# 結果
[<div class="more-meta">
<h4 class="title">
                 刺
               </h4>
...

這裏搜索了具備屬性爲class='more-meta'的div標籤

3)根據關鍵字參數來搜索

# 對相關屬性進行進行查找也能夠這樣
print(soup.find_all(class_='more-meta'))  # 使用關鍵字參數,由於class是python關鍵字,因此關鍵字參數時須要加多一個下劃線來進行區別
# 結果
和上面的結果同樣
...

這裏注意,咱們找的是class屬性爲more-meta的標籤,用了關鍵字參數,可是python裏面有class關鍵字,因此爲了避免使語法出錯,因此須要在class加個下劃線

其餘參數的就再也不介紹了,能夠自行去官網查看

4)find()方法

此方法與find_all()方法同樣,只不過這個方法只是查找一個標籤而已,後者是查找全部符合條件的標籤。

還有不少相似的方法,用法都差很少,就再也不一一演示了,須要的能夠去官網查看

5)select()方法

這個方法是使用css選擇器來進行篩選標籤的。

css選擇器:就是根據標籤的名字,id和class屬性來選擇標籤。

  • 經過標籤名:直接寫該標籤名,如 li a  ,這個就是找li標籤下的a標籤

  • 經過class屬性:用. 符號加class屬性值,如 .title .time 這個就是找class值爲title下的class值爲time的標籤

  • 經過id屬性:用# 加id屬性值來進行查找,如 #img #width 這個就是找id值爲img下的id值爲width的標籤

  • 上面三者能夠混合使用,如 ul .title #width

若是還不太會的話,能夠直接在瀏覽器上按下f12來查看

位置在箭頭所指的位置就是選擇器的表達

代碼以下

# 還能夠用標籤選擇器來進行篩選元素, 返回的都是一個列表
print(soup.select('ul li div'))  # 這個是根據標籤名進行篩選
print(soup.select('.info .title'))  # 這個是根據class來進行篩選
print(soup.select('#footer #icp'))  # 這個是根據id來進行篩選
# 上面的能夠進行混合使用
print(soup.select('ul li .cover a img'))

這裏的獲取屬性和文本內容

# 獲取屬性
for attr in soup.select('ul li .cover a img'):
   # print(attr.attrs['alt'])
   # 也能夠這樣
   print(attr['alt'])

# 獲取標籤的內容
for tag in soup.select('li'):
   print(tag.get_text())  # 裏面能夠包含子標籤,會將子標籤的內容連同輸出

.get_tex()方法和前面的.string屬性有點不同哈,這裏的他會獲取該標籤的全部文本內容,無論有沒有子標籤

寫在最後

以上的這些都是我的在學習過程當中作的一點筆記。還有點不足,若是有錯誤的話歡迎大佬指出哈。若是想要查看更多相關用法能夠去官方文檔查看:beautifulsoup.readthedocs.io/zh_CN/lates…

學習參考資料:https://edu.hellobi.com/course/157

若是這篇文章對你有用,點個贊,轉個發如何?

還有,祝你們今天愚人節快樂

MORE
延伸閱讀

◐◑爬取《The Hitchhiker’s Guide to Python!》python進階書並製成pdf

◐◑ python爬蟲經常使用庫之requests詳解

◐◑ 老司機帶你用python來爬取妹子圖



平常學python

代碼不止bug,還有美和樂趣

相關文章
相關標籤/搜索