網絡爬蟲--16.BeautifulSoup4

文章目錄

  • 一. BeautifulSoup4
  • 二. 解析實例
  • 三. 四大對象種類
    • 1. Tag
    • 2. NavigableString
    • 3. BeautifulSoup
    • 4. Comment
  • 四. 遍歷文檔樹
    • 1.直接子節點 :.contents .children 屬性
      • 1). .contents
      • 2). .children
    • 2. 所有子孫節點: .descendants 屬性
    • 3. 節點內容: .string 屬性
  • 五. 搜索文檔樹
    • 1. find_all(name, attrs, recursive, text, **kwargs)
      • 1). name 參數
      • 2). keyword 參數
      • 3).text 參數
    • 2. CSS選擇器
      • 1). 通過標簽名查找
      • 2). 通過類名查找
      • 3).通過 id 名查找
      • 4).組合查找
      • 5). 屬性查找
      • 6). 獲取內容

一. BeautifulSoup4

官方文檔:http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0

和 lxml 一樣,Beautiful Soup 也是一個HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 數據。

lxml 只會局部遍歷,而Beautiful Soup 是基于HTML DOM的,會載入整個文檔,解析整個DOM樹,因此時間和內存開銷都會大很多,所以性能要低于lxml。

BeautifulSoup 用來解析 HTML 比較簡單,API非常人性化,支持CSS選擇器、Python標準庫中的HTML解析器,也支持 lxml 的 XML解析器。

Beautiful Soup 3 目前已經停止開發,推薦現在的項目使用Beautiful Soup 4。使用 pip 安裝即可:pip install beautifulsoup4

在這里插入圖片描述

二. 解析實例

首先必須要導入 bs4 庫

from bs4 import BeautifulSouphtml = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""#創建 Beautiful Soup 對象
soup = BeautifulSoup(html)#打開本地 HTML 文件的方式來創建對象
#soup = BeautifulSoup(open('index.html'))#格式化輸出 soup 對象的內容
print soup.prettify()

輸出結果:

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

運行后會看到這樣一段警告:

UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("lxml"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.The code that caused this warning is on line 18 of the file D:/PycharmProject/spider/spider24_BeautifulSoup1.py. To get rid of this warning, pass the additional argument 'features="lxml"' to the BeautifulSoup constructor.soup = BeautifulSoup(html)

在這里插入圖片描述
意思是,如果我們沒有顯式地指定解析器,所以默認使用這個系統的最佳可用HTML解析器(“lxml”)。如果你在另一個系統中運行這段代碼,或者在不同的虛擬環境中,使用不同的解析器造成行為不同。

但是我們可以通過soup = BeautifulSoup(html,“lxml”)方式指定lxml解析器

三. 四大對象種類

Beautiful Soup將復雜HTML文檔轉換成一個復雜的樹形結構,每個節點都是Python對象,所有對象可以歸納為4種:

  • Tag
  • NavigableString
  • BeautifulSoup
  • Comment

1. Tag

Tag 通俗點講就是 HTML 中的一個個標簽,例如:title head a p等等 HTML 標簽加上里面包括的內容就是 Tag,那么試著使用 Beautiful Soup 來獲取 Tags:

from bs4 import BeautifulSouphtml = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""#創建 Beautiful Soup 對象
soup = BeautifulSoup(html)print soup.title
# <title>The Dormouse's story</title>print soup.head
# <head><title>The Dormouse's story</title></head>print soup.a
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>print soup.p
# <p class="title" name="dromouse"><b>The Dormouse's story</b></p>print type(soup.p)
# <class 'bs4.element.Tag'>

我們可以利用 soup 加標簽名輕松地獲取這些標簽的內容,這些對象的類型是bs4.element.Tag。但是注意,它查找的是在所有內容中的第一個符合要求的標簽。如果要查詢所有的標簽,后面會進行介紹。

對于 Tag,它有兩個重要的屬性,是 name 和 attrs

print soup.name
# [document] #soup 對象本身比較特殊,它的 name 即為 [document]print soup.head.name
# head #對于其他內部標簽,輸出的值便為標簽本身的名稱print soup.p.attrs
# {'class': ['title'], 'name': 'dromouse'}
# 在這里,我們把 p 標簽的所有屬性打印輸出了出來,得到的類型是一個字典。print soup.p['class'] # soup.p.get('class')
# ['title'] #還可以利用get方法,傳入屬性的名稱,二者是等價的soup.p['class'] = "newClass"
print soup.p # 可以對這些屬性和內容等等進行修改
# <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>del soup.p['class'] # 還可以對這個屬性進行刪除
print soup.p
# <p name="dromouse"><b>The Dormouse's story</b></p>

2. NavigableString

既然我們已經得到了標簽的內容,那么問題來了,我們要想獲取標簽內部的文字怎么辦呢?很簡單,用 .string 即可,例如

print soup.p.string
# The Dormouse's storyprint type(soup.p.string)
# In [13]: <class 'bs4.element.NavigableString'>

3. BeautifulSoup

BeautifulSoup 對象表示的是一個文檔的內容。大部分時候,可以把它當作 Tag 對象,是一個特殊的 Tag,我們可以分別獲取它的類型,名稱,以及屬性來感受一下

print type(soup.name)
# <type 'unicode'>print soup.name 
# [document]print soup.attrs # 文檔本身的屬性為空
# {}

4. Comment

Comment 對象是一個特殊類型的 NavigableString 對象,其輸出的內容不包括注釋符號。

print soup.a
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>print soup.a.string
# Elsie print type(soup.a.string)
# <class 'bs4.element.Comment'>

a 標簽里的內容實際上是注釋,但是如果我們利用 .string 來輸出它的內容時,注釋符號已經去掉了。

四. 遍歷文檔樹

1.直接子節點 :.contents .children 屬性

1). .contents

tag 的 .content 屬性可以將tag的子節點以列表的方式輸出

print soup.head.contents 
#[<title>The Dormouse's story</title>]

輸出方式為列表,我們可以用列表索引來獲取它的某一個元素

print soup.head.contents[0]
#<title>The Dormouse's story</title>

2). .children

它返回的不是一個 list,不過我們可以通過遍歷獲取所有子節點。

我們打印輸出 .children 看一下,可以發現它是一個 list 生成器對象

print soup.head.children
#<listiterator object at 0x7f71457f5710>for child in  soup.body.children:print child

結果:

<p class="title" name="dromouse"><b>The Dormouse's story</b></p><p class="story">Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p><p class="story">...</p>

2. 所有子孫節點: .descendants 屬性

.contents 和 .children 屬性僅包含tag的直接子節點,.descendants 屬性可以對所有tag的子孫節點進行遞歸循環,和 children類似,我們也需要遍歷獲取其中的內容。

for child in soup.descendants:print child

運行結果:

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

3. 節點內容: .string 屬性

如果tag只有一個 NavigableString 類型子節點,那么這個tag可以使用 .string 得到子節點。如果一個tag僅有一個子節點,那么這個tag也可以使用 .string 方法,輸出結果與當前唯一子節點的 .string 結果相同。

通俗點說就是:如果一個標簽里面沒有標簽了,那么 .string 就會返回標簽里面的內容。如果標簽里面只有唯一的一個標簽了,那么 .string 也會返回最里面的內容。例如:

print soup.head.string
#The Dormouse's story
print soup.title.string
#The Dormouse's story

五. 搜索文檔樹

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

1). name 參數

name 參數可以查找所有名字為 name 的tag,字符串對象會被自動忽略掉

A.傳字符串
最簡單的過濾器是字符串.在搜索方法中傳入一個字符串參數,Beautiful Soup會查找與字符串完整匹配的內容,下面的例子用于查找文檔中所有的< b>標簽:

soup.find_all('b')
# [<b>The Dormouse's story</b>]print soup.find_all('a')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

B.傳正則表達式
如果傳入正則表達式作為參數,Beautiful Soup會通過正則表達式的 match() 來匹配內容.下面例子中找出所有以b開頭的標簽,這表示< body>和< b>標簽都應該被找到

import re
for tag in soup.find_all(re.compile("^b")):print(tag.name)
# body
# b

C.傳列表
如果傳入列表參數,Beautiful Soup會將與列表中任一元素匹配的內容返回.下面代碼找到文檔中所有< a>標簽和< b>標簽:

soup.find_all(["a", "b"])
# [<b>The Dormouse's story</b>,
#  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

2). keyword 參數

soup.find_all(id='link2')
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

3).text 參數

soup.find_all(text="Elsie")
# [u'Elsie']soup.find_all(text=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']soup.find_all(text=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]

2. CSS選擇器

這就是另一種與 find_all 方法有異曲同工之妙的查找方法.

  • 寫 CSS 時,標簽名不加任何修飾,類名前加.,id名前加#
  • 在這里我們也可以利用類似的方法來篩選元素,用到的方法是 soup.select(),返回類型是 list

1). 通過標簽名查找

print soup.select('title') 
#[<title>The Dormouse's story</title>]print soup.select('a')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]print soup.select('b')
#[<b>The Dormouse's story</b>]

2). 通過類名查找

print soup.select('.sister')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

3).通過 id 名查找

print soup.select('#link1')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

4).組合查找

組合查找即和寫 class 文件時,標簽名與類名、id名進行的組合原理是一樣的,例如查找 p 標簽中,id 等于 link1的內容,二者需要用空格分開

print soup.select('p #link1')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

直接子標簽查找,則使用 > 分隔

print soup.select("head > title")
#[<title>The Dormouse's story</title>]

5). 屬性查找

查找時還可以加入屬性元素,屬性需要用中括號括起來,注意屬性和標簽屬于同一節點,所以中間不能加空格,否則會無法匹配到。

print soup.select('a[class="sister"]')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]print soup.select('a[href="http://example.com/elsie"]')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

同樣,屬性仍然可以與上述查找方式組合,不在同一節點的空格隔開,同一節點的不加空格

print soup.select('p a[href="http://example.com/elsie"]')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

6). 獲取內容

以上的 select 方法返回的結果都是列表形式,可以遍歷形式輸出,然后用 get_text() 方法來獲取它的內容。

soup = BeautifulSoup(html, 'lxml')
print type(soup.select('title'))
print soup.select('title')[0].get_text()for title in soup.select('title'):print title.get_text()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/451990.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/451990.shtml
英文地址,請注明出處:http://en.pswp.cn/news/451990.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Intel MKL 多線程設置

對于多核程序&#xff0c;多線程對于程序的性能至關重要。 下面&#xff0c;我們將對Intel MKL 有關多線程方面的設置做一些介紹&#xff1a; 我們提到MKL 支持多線程&#xff0c;它包括的兩個概念&#xff1a; 1>MKL 是線程安全的&#xff1a; MKL在設計時&#xff0c;就保…

【LA3415 訓練指南】保守的老師 【二分圖最大獨立集,最小割】

題意 Frank是一個思想有些保守的高中老師。有一次&#xff0c;他需要帶一些學生出去旅行&#xff0c;但又怕其中一些學生在旅行中萌生愛意。為了降低這種事情發生的概率&#xff0c;他決定確保帶出去的任意兩個學生至少要滿足下面四條中的一條。 1.身高相差大于40厘米 2.性別相…

行車記錄儀穩定方案:TC358778XBG:RGB轉MIPI DSI芯片,M-Star標配IC

原廠&#xff1a;Toshiba型號&#xff1a;TC358778XBG功能&#xff1a;TC358778XBG是一顆將RGB信號轉換成MIPI DSI的芯片&#xff0c;最高分辨率支持到1920x1200&#xff0c;其應用圖如下&#xff1a;產品特征&#xff1a;MIPI接口&#xff1a;&#xff08;1&#xff09;、支持…

java.sql.SQLException: 無法轉換為內部表示之解決

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 這個錯是因為 數據庫中字段類型和程序中該字段類型不一致。 比如程序將某字段當做Integer類型&#xff0c; 而數據庫存儲又使用另外一…

網絡爬蟲--17.【BeautifuSoup4實戰】爬取騰訊社招

文章目錄一.要求二.代碼示例一.要求 以騰訊社招頁面來做演示&#xff1a;http://hr.tencent.com/position.php?&start10#a 使用BeautifuSoup4解析器&#xff0c;將招聘網頁上的職位名稱、職位類別、招聘人數、工作地點、發布時間&#xff0c;以及每個職位詳情的點擊鏈接…

public static void main(String[] args)的理解

public:權限修飾符&#xff0c;權限最大。static:隨著MianDemo類的加載而加載&#xff0c;消失而消失。void: 沒有返回值main: 函數名&#xff0c;jvm識別的特殊函數名(String[] args):定義了一個字符串數組參數。這個字符串數組是保存運行main函數時輸入的參數的

Miller-Rabin素數測試

Miller-Rabin素數測試 給出一個小于1e18的數&#xff0c;問它是否為質數&#xff1f;不超過50組詢問。hihocoder 我是真的菜&#xff0c;為了不誤導他人&#xff0c;本篇僅供個人使用。 首先&#xff0c;一個1e18的數&#xff0c;樸素\(O(\sqrt{n})\)素數判定肯定爆炸。怎么辦呢…

throws Exception的意思

在方法聲明部分使用&#xff0c;表示該方法可能產生此異常&#xff0c;如果在方法聲明處使用了throws聲明異常&#xff0c;則該方法產生異常也不必捕獲&#xff0c;會直接把異常拋出到調用該方法的地方。

java list按照元素對象的指定多個字段屬性進行排序

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 直接提取重點代碼&#xff1a; /*** 把結果集合按時間字段排序&#xff0c;內部類重寫排序規則&#xff1a;* param list* return*/priv…

網絡爬蟲--18.python中的GIL(全局解釋器鎖)、多線程、多進程、并發、并行

參考文獻&#xff1a; python的GIL、多線程、多進程 并發和并行的區別&#xff1f; GIL(全局解釋器鎖)一看就懂的解釋&#xff01; 多謝作者分享&#xff01;

Socket和ServerSocket

對于即時類應用或者即時類的游戲&#xff0c;HTTP協議很多時候無法滿足于我們的需求。這會&#xff0c;Socket對于我們來說就非常實用了。下面是本次學習的筆記。主要分異常類型、交互原理、Socket、ServerSocket、多線程這幾個方面闡述。異常類型在了解Socket的內容之前&#…

徹底搞清楚Android中的 Attr

版權聲明&#xff1a;本文為sydMobile原創文章&#xff0c;轉載請務必注明出處&#xff01; https://blog.csdn.net/sydMobile/article/details/79978187 相信這個詞對于Android開發者來說十分熟悉了&#xff0c;那么你對他到底有多了解呢&#xff1f; 回憶起我剛開始接觸Andr…

D. Relatively Prime Graph

Lets call an undirected graph G(V,E)G(V,E) relatively prime if and only if for each edge (v,u)∈E(v,u)∈E GCD(v,u)1GCD(v,u)1 (the greatest common divisor of vv and uu is 11). If there is no edge between some pair of vertices vv and uu then the value of GC…

解決 : org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 報錯&#xff1a; org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.tanj.mapper.SendDeta…

網絡爬蟲--19.【Scrapy-Redis實戰】分布式爬蟲爬取房天下--環境準備

文章目錄0. 思路一. 虛擬機Ubuntu0中安裝Redis二. 虛擬機Ubuntu1中安裝Redis三. Windows服務器上安裝Redis四. 安裝cmder五. 安裝RedisDesktopManager六. 修改Windows中的配置文件redis.windows.conf七. Ubuntu連接Windows上 的Redis服務器-----------------------------------…

開發人員,請愛護你的身體

最近一周身體極度不適&#xff0c;口腔潰瘍、嗓子痛、感冒咳嗽、發燒&#xff0c;統統來了一個遍&#xff0c;非常痛苦。所以最近一直關注有關于軟件開發人員的身體健康問題的網站、文章。 看了許多文章&#xff0c;在結合自己在這一周之內痛苦的感受&#xff0c;所以才寫這樣…

tkinter中scale拖拉改變值控件(十一)

scale拖拉改變值控件 使用戶通過拖拽改變值 簡單的實現&#xff1a; 1 import tkinter2 3 wuya tkinter.Tk() 4 wuya.title("wuya") 5 wuya.geometry("300x2001020") 6 7 8 # 創建對象 9 scale1 tkinter.Scale(wuya, from_0, to100) 10 scale1.pac…

vue+elementUI開發實踐問題總結

最近公司項目采用vue&#xff0c;實行前后端分離開發&#xff0c;采用element-ui框架&#xff0c;對于項目中遇到的問題進行記錄&#xff0c;便于日后查詢。 vueelementui怎樣點擊table中的單元格觸發事件&#xff1f;官方文檔是采用的cell-click方式。實際項目中需要在不同的t…

Socket的getInputStream()方法

Socket的getInputStream()方法可以獲得網絡連接輸入&#xff0c;同時返回一個InputStream實例 。

計算機圖形學理論(4):緩沖區

本系列根據國外一個圖形小哥的講解為本&#xff0c;整合互聯網的一些資料&#xff0c;結合自己的一些理解。 什么是緩沖區&#xff1f; 緩沖區是保存某些數據的臨時存儲空間。 為什么我們需要緩沖區&#xff1f;原因很簡單&#xff0c;當數據量很大時&#xff0c;因為計算機無…