【Python爬蟲基礎篇】--2.模塊解析

目錄

1.urllib庫

1.1.request模塊

1.1.1、urllib.request.urlopen() 函數

1.1.2.urllib.request.urlretrieve()?函數

1.2.?error模塊

1.3.?parse 模塊

2.?BeautifulSoup4庫

2.1.對象種類

2.2.對象屬性

2.2.1.子節點

2.2.2.父節點

2.2.3.兄弟節點

?2.2.4.回退和前進

2.3.對象方法

2.3.1.find_all()

2.3.2.find()

2.3.3.CSS選擇器查找

2.3.4.修改內容

2.4.輸出

2.4.1.格式化輸出

2.4.2.壓縮輸出

2.4.3.文本輸出

?3.re標準庫


大概會用到以下這些模塊

分類庫名主要用途
網絡請求requests同步HTTP請求
aiohttp異步HTTP請求
動態渲染selenium瀏覽器自動化
playwright高性能無頭瀏覽器控制
數據解析BeautifulSoup4HTML/XML解析
lxmlXPath/CSS選擇器解析
re字符串正則匹配(文本清洗/數據提取)
爬蟲框架scrapy全功能爬蟲框架
反反爬fake-useragent隨機生成請求頭

1.urllib庫

?? Python3 中將 Python2 中的 urllib 和 urllib2 兩個庫整合為一個 urllib 庫,所以現在一般說的都是 Python3 中的 urllib 庫,它是python3內置標準庫,不需要額外安裝。

1.1.request模塊

?request模塊提供了最基本的構造 HTTP 請求的方法,利用它可以模擬瀏覽器的一個請求發起過程,同時它還帶有處理authenticaton(授權驗證),redirections(重定向),cookies(瀏覽器Cookies)以及其它內容。

1.1.1、urllib.request.urlopen() 函數

語法:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)參數說明:
url:請求的 url,也可以是request對象
data:請求的 data,如果設置了這個值,那么將變成 post 請求,如果要傳遞一個字典,則應該用urllib.parse模塊的urlencode()函數編碼;
timeout:設置網站的訪問超時時間句柄對象; 
cafile和capath:用于 HTTPS 請求中,設置 CA 證書及其路徑;
cadefault:忽略*cadefault*參數;
context:如果指定了*context*,則它必須是一個ssl.SSLContext實例。urlopen() 返回對象HTTPResponse提供的方法和屬性:1)read()、readline()、readlines()、fileno()、close():對 HTTPResponse 類型數據進行操作;
2)info():返回 HTTPMessage 對象,表示遠程服務器 返回的頭信息 ;
3)getcode():返回 HTTP 狀態碼 geturl():返回請求的 url;
4)getheaders():響應的頭部信息;
5)status:返回狀態碼;
6)reason:返回狀態的詳細信息.

案例一:使用urlopen()函數抓取百度

import urllib.request
url = "http://www.baidu.com/"
res = urllib.request.urlopen(url)  # get方式請求
print(res)  # 返回HTTPResponse對象<http.client.HTTPResponse object at 0x00000000026D3D00>
# 讀取響應體
bys = res.read()  # 調用read()方法得到的是bytes對象。
print(bys)  # <!DOCTYPE html><!--STATUS OK-->\n\n\n    <html><head><meta...
print(bys.decode("utf-8"))  # 獲取字符串內容,需要指定解碼方式,這部分我們放到html文件中就是百度的主頁# 獲取HTTP協議版本號(10 是 HTTP/1.0, 11 是 HTTP/1.1)
print(res.version)  # 11# 獲取響應碼
print(res.getcode())  # 200
print(res.status)  # 200# 獲取響應描述字符串
print(res.reason)  # OK# 獲取實際請求的頁面url(防止重定向用)
print(res.geturl())  # http://www.baidu.com/# 獲取響應頭信息,返回字符串
print(res.info())  # Bdpagetype: 1 Bdqid: 0x803fb2b9000fdebb...
# 獲取響應頭信息,返回二元元組列表
print(res.getheaders())  # [('Bdpagetype', '1'), ('Bdqid', '0x803fb2b9000fdebb'),...]
print(res.getheaders()[0])  # ('Bdpagetype', '1')
# 獲取特定響應頭信息
print(res.getheader(name="Content-Type"))  # text/html;charset=utf-8

案例二:get請求

我們在http://httpbin.org/網站,發送一個get測試請求:

然后我們在使用python模擬瀏覽器發送一個get請求:

import urllib.request
# 請求的URL
url = "http://httpbin.org/get"
# 模擬瀏覽器打開網頁(get請求)
res = urllib.request.urlopen(url)
print(res.read().decode("utf-8"))

?

通過上面的案例,不難發現使用urllib發送的請求,比較不同的地方是:"User-Agent",使用urllib發送的會有一個默認的Headers:User-Agent: Python-urllib/3.8。所以遇到一些驗證User-Agent的網站時,有可能會直接拒絕爬蟲,因此我們需要自定義Headers把自己偽裝的像一個瀏覽器一樣。

?案例三:?偽裝Headers

我去爬取豆瓣網時:

import urllib.requesturl = "http://douban.com"
resp = urllib.request.urlopen(url)
print(resp.read().decode('utf-8'))返回錯誤:反爬蟲
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 418: 

HTTP 418? ? 客戶端錯誤響應代碼表示服務器拒絕。

?自定義Headers:

import urllib.requesturl = "http://douban.com"
# 自定義headers
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
}
req = urllib.request.Request(url, headers=headers)
# urlopen(也可以是request對象)
print(urllib.request.urlopen(req).read().decode('utf-8'))  # 獲取字符串內容,需要指定解碼方式

1.1.2.urllib.request.urlretrieve()?函數

??urlretrieve()函數的作用是直接將遠程的網頁數據htlm下載到本地

# 語法:
?
urlretrieve(url, filename=None, reporthook=None, data=None)
?
# 參數說明
?
url:傳入的網址
filename:指定了保存本地路徑(如果參數未指定,urllib會生成一個臨時文件保存數據)
reporthook:是一個回調函數,當連接上服務器、以及相應的數據塊傳輸完畢時會觸發該回調,我們可以利用這個回調函數來顯示當前的下載進度
data:指 post 到服務器的數據,該方法返回一個包含兩個元素的(filename, headers)元組,filename 表示保存到本地的路徑,header表示服務器的響應頭
?

import urllib.requesturl = "http://www.hao6v.com/"
filename = "C:\\pythonProject\\python爬蟲\\gyp.html"def callback(blocknum, blocksize, totalsize):"""@blocknum:目前為此傳遞的數據塊數量@blocksize:每個數據塊的大小,單位是byte,字節@totalsize:遠程文件的大小"""if totalsize == 0:percent = 0else:percent = blocknum * blocksize / totalsizeif percent > 1.0:percent = 1.0percent = percent * 100print("download : %.2f%%" % (percent))local_filename, headers = urllib.request.urlretrieve(url, filename, callback)


1.2.?error模塊

? ??urllib.error 模塊為 urllib.request 所引發的異常定義了異常類,基礎異常類是 URLError。

狀態碼分類定義
1xx信息響應
100Continue服務器已接收請求頭,客戶端應繼續發送請求體
101Switching Protocols協議切換(如HTTP→WebSocket)
2xx成功響應
200OK請求成功,響應內容取決于請求方法(GET/POST等)
201Created資源創建成功(常用于POST/PUT)
204No Content無返回內容,但響應頭可能含元信息
3xx重定向
301Moved Permanently資源永久重定向到新URI
302Found資源臨時重定向(早期規范語義不明確,建議用307/308替代)
304Not Modified資源未修改(緩存相關)
4xx客戶端錯誤
400Bad Request請求語法錯誤
403Forbidden服務器拒絕執行(無權限)
404Not Found資源不存在
408Request Timeout請求超時
5xx服務器錯誤
500Internal Server Error服務器內部錯誤(無具體信息)
503Service Unavailable服務不可用(臨時過載或維護)
504Gateway Timeout網關超時(上游服務器未響應)
import urllib.request,urllib.errortry:url = "http://www.baidus.com"resp = urllib.request.urlopen(url)print(resp.read().decode('utf-8'))
# except urllib.error.HTTPError as e:
#     print("請檢查url是否正確")
# URLError是urllib.request異常的超類
except urllib.error.URLError as e:if hasattr(e, "code"):print(e.code)if hasattr(e, "reason"):print(e.reason)

?

1.3.?parse 模塊

功能分類函數核心作用
URL解析urlparse(url)將URL拆分為6組件(協議/域名/路徑等),保留參數分隔符;&
urlsplit(url)類似urlparse但不拆分參數分隔符,返回5組件
urldefrag(url)分離URL中的片段標識(如#anchor
URL構建urlunparse(parts)urlparse的6組件重組為完整URL
urljoin(base, url)基于基URL合并相對路徑(智能處理./../
查詢參數處理urlencode(query_dict)將字典轉為URL查詢字符串(自動編碼特殊字符)
parse_qs(query_str)將查詢字符串解析為字典(值類型為list
parse_qsl(query_str)將查詢字符串解析為鍵值對列表(保留原始順序)

2.?BeautifulSoup4庫

????????學了urllib標準庫之后,我們已經能爬到些比較正常的網頁源碼(html文檔)了,但這離結果還差一步——就是如何篩選我們想要的數據,這時候BeautifulSoup庫就來了,BeautifulSoup目前最新版本為BeautifulSoup4。

用于解析HTML和XML文檔的流行庫,它能夠從網頁中提取數據并生成易于遍歷的解析樹

(官網文檔:Beautiful Soup 4.12.0 文檔 — Beautiful Soup 4.12.0 documentation)

soup = BeautifulSoup("<html>Hello</html>", "html.parser")

參數解析:?

(1)markup
需要解析的HTML/XML文檔內容(字符串或文件對象)。

(2)解析器選擇(features?或第二參數)

解析器安裝方式特點示例
"html.parser"Python內置速度中等,無依賴BeautifulSoup(html, "html.parser")
"lxml"pip install lxml最快,支持復雜文檔BeautifulSoup(html, "lxml")
"html5lib"pip install html5lib容錯性最強,速度慢BeautifulSoup(html, "html5lib")
from bs4 import BeautifulSoup  # 導入BeautifulSoup4庫# 未指定就使用html.parser這個python標準解析器 BeautifulSoup(markup, "html.parser") 未指定會產生警告 GuessedAtParserWarning: No parser was explicitly specified# BeautifulSoup 第一個參數接受:一個文件對象或字符串對象
soup1 = BeautifulSoup(markup=open("C:\\pythonProject\\python爬蟲\\gyp.html"), features="html.parser")
soup2 = BeautifulSoup("<html>hello python</html>")  # 得到文檔的對象
print(type(soup2))  # <class 'bs4.BeautifulSoup'>
print(soup1)  # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ....
print(soup2)  # <html><head></head><body>hello python</body></html>

2.1.對象種類

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

對象類型關鍵屬性/方法功能描述注意事項
Tag 標簽對象name(標簽名)
attributes(屬性字典)
表示HTML/XML文檔中的標簽節點,可獲取標簽名和屬性(如classid等)通過遍歷或搜索文檔樹獲取,支持嵌套操作(如tag.contents?)
NavigableStringtag.string提取標簽對內的純文本內容(僅限直接包含的字符串)若標簽內含注釋或其他子標簽,需用.strings.get_text()獲取完整文本
BeautifulSoup文檔根對象代表整個解析后的文檔,可視為特殊的Tag對象(包含<html>頂層標簽)初始化時需指定解析器(如lxml),支持全局搜索方法(如.find_all()
Comment 對象繼承自NavigableString處理HTML注釋內容(如<!-- comment -->),輸出時自動去掉注釋符號需用type(tag.string)==bs4.Comment?判斷,避免誤將注釋當作普通文本處理
from bs4 import BeautifulSoup# 導入BeautifulSoup4庫
# python 標準解析器 未指定就使用這個 BeautifulSoup(markup, "html.parser")
soup2 = BeautifulSoup("<html>""<p class='boldest'>我是p標簽<b>hello python</b></p>""<!--我是標簽外部的內容注釋-->""<p class='boldest2'><!--我p標簽內的注釋-->我是獨立的p標簽</p>""<a><!--我a標簽內的注釋-->我是鏈接</a>""<h1><!--這是一個h1標簽的注釋--></h1>""</html>","html5lib")  # 得到文檔的對象
# Tag 標簽對象
print(type(soup2.p))  # 輸出Tag對象<class 'bs4.element.Tag'>
print(soup2.p.name)  # 輸出Tag標簽對象的名稱
print(soup2.p.attrs)  # 輸出第一個p標簽的屬性信息:{'class': ['boldest']}
soup2.p['class'] = ['boldest', 'boldest1']
print(soup2.p.attrs)  # {'class': ['boldest', 'boldest1']}# NavigableString 可以遍歷的字符串對象
print(type(soup2.b.string))  # <class 'bs4.element.NavigableString'>
print(soup2.b.string)  # hello python
print(soup2.a.string)  # None 存在注釋或者其他標簽內容均無法獲取
print(soup2.b.string.replace_with("hello world"))  # replace_with()方法可替換標簽中的內容
print(soup2.b.string)  # hello world# BeautifulSoup 對象
print(type(soup2))  # <class 'bs4.BeautifulSoup'>
print(soup2)  # <html><head></head><body><p class="boldest">我是p標簽<b>hello python</b></p><!--我是標簽外部的內容注釋--><p><!--我p標簽內的注釋-->我是獨立的p標簽</p></body></html>
print(soup2.name)  # [document]# Comment 注釋及特殊字符串(是一個特殊類型的 NavigableString 對象)
print(type(soup2.h1.string))  # <class 'bs4.element.Comment'>
print(soup2.h1.string)  # 這是一個h1標簽的注釋 (利用 .string 來輸出它的內容,注釋符被去除了,不是我們想要的)
print(soup2.h1.prettify())  # 會以特殊格式輸出:<h1> <!--這是一個h1標簽的注釋--> </h1>

2.2.對象屬性

可以簡單理解爬取到的內容是樹狀圖:

2.2.1.子節點

BeautifulSoup 對象常用屬性總結

屬性/方法描述使用場景與注意事項
.tag獲取標簽名(如tag.name?返回'div'適用于快速識別標簽類型,但需注意某些標簽(如<br/>)可能無閉合標簽。
.contents返回標簽的直接子節點列表(包括文本和標簽節點)需注意列表可能包含換行符等空白文本節點,可通過過濾NavigableString類型處理。
.children生成器形式返回直接子節點(性能優于.contents適合遍歷大量子節點時節省內存,但不可索引(需轉為列表)。
.descendants遞歸生成所有子孫節點(深度優先遍歷)可用于爬取嵌套結構的完整內容(如表格內的所有文本),但需處理混合節點類型(注釋、字符串等)。
.string提取標簽內唯一字符串子節點(無嵌套標簽)若標簽含多個子節點(如<p>Text<b>bold</b></p>),返回None,需改用.get_text().strings
.strings生成器形式返回標簽內所有字符串(保留空白)需手動去除換行符和縮進(如' '.join(tag.strings).strip()?)。
.stripped_strings生成器形式返回標簽內字符串(自動去除空白)適用于清洗文本(如新聞正文提取),但可能合并相鄰空格(需根據需求調整)。
from bs4 import BeautifulSoupmarkup = '''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>I’m the title</title></head><body><h1>HelloWorld</h1><div><div><p><b>我是一個段落...</b>我是第一段我是第二段<b>我是另一個段落</b>我是第一段</p><a>我是一個鏈接</a></div><div><p>picture</p><img src="example.png"/></div></div></body>
</html>'''
soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象
print(soup.head.name)  # soup.head可以獲取標簽,獲取標簽名 - 輸出:head
print(soup.head.contents)  # 將tag的子節點以列表的方式輸出--輸出:['\n        ', <meta charset="utf-8"/>, '\n        ', <title>I’m the title</title>, '\n    ']
print(soup.head.contents[1])  # <meta charset="utf-8"/>
print(soup.head.children)  # list_iterator object
for child in soup.head.children:print(child)  # <meta charset="utf-8"/>  <title>I’m the title</title>
# 標簽中的內容其實也是一個節點 使用contents和children無法直接獲取間接節點中的內容,但是.descendants 屬性可以
for child in soup.head.descendants:print(child)  # <meta charset="utf-8"/> <title>I’m the title</title> I’m the title
print(soup.head.title.string)  # 輸出:I’m the title  注:title中有其他節點或者注釋都無法獲取print(soup.body.div.div.p.strings)  # 使用.string-None 使用.strings 獲得generator object
for string in soup.body.div.div.p.stripped_strings:    # stripped_strings 可以去除多余空白內容print(repr(string))    # '我是一個段落...'# '我是第一段\n                      我是第二段'# '我是另一個段落'# '我是第一段'

tag+contents:?

?

?children:

?深度優先遍歷:descendants

?獲取標簽字符:string

2.2.2.父節點

屬性描述
.parent獲取某個元素的父節點
.parents可以遞歸得到元素的所有父輩節點
from bs4 import BeautifulSoupmarkup = '''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>I’m the title</title></head><body><h1>HelloWorld</h1><div><div><p><b>我是一個段落...</b>我是第一段我是第二段<b>我是另一個段落</b>我是第一段</p><a>我是一個鏈接</a></div><div><p>picture</p><img src="example.png"/></div></div></body>
</html>'''
soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象title = soup.head.title
print(title.parent)  # 輸出父節點
#     <head>
#         <meta charset="utf-8"/>
#         <title>I’m the title</title>
#     </head>
print(title.parents)  # generator object PageElement.parents
for parent in title.parents:print(parent)  # 輸出head父節點 和 html父節點

2.2.3.兄弟節點

屬性描述
.next_sibling查詢兄弟節點,表示下一個兄弟節點
.previous_sibling查詢兄弟節點,表示上一個兄弟節點
.next_siblings對當前節點的兄弟節點迭代輸出(下)
.previous_siblings對當前節點的兄弟節點迭代輸出(上)
from bs4 import BeautifulSoupmarkup = '''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>I’m the title</title></head><body><div><p><b id=“b1”>我是第一個段落</b><b id=“b2”>我是第二個段落</b><b id=“b3”>我是第三個段落</b><b id=“b4”>我是第四個段落</b></p><a>我是一個鏈接</a></div></body>
</html>'''
soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象
p = soup.body.div.p.b
print(p)  # <b id="“b1”">我是第一個段落</b>
print(p.next_sibling)  # <b id="“b2”">我是第二個段落</b>
print(p.next_sibling.previous_sibling)  # <b id="“b1”">我是第一個段落</b>
print(p.next_siblings)  # generator object PageElement.next_siblings
for nsl in p.next_siblings:print(nsl)    # <b id="“b2”">我是第二個段落</b># <b id="“b3”">我是第三個段落</b># <b id="“b4”">我是第四個段落</b>

?2.2.4.回退和前進

屬性描述
.next_element解析下一個元素對象
.previous_element解析上一個元素對象
.next_elements迭代解析元素對象
.previous_elements迭代解析元素對象
from bs4 import BeautifulSoupmarkup = '''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>I’m the title</title></head><body><div><p><b id=“b1”>我是第一個段落</b><b id=“b2”>我是第二個段落</b><b id=“b3”>我是第三個段落</b><b id=“b4”>我是第四個段落</b></p><a>我是一個鏈接<h3>h3</h3></a></div></body>
</html>'''
soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象
p = soup.body.div.p.b
print(p)  # <b id="“b1”">我是第一個段落</b>
print(p.next_element)  # 我是第一個段落
print(p.next_element.next_element)  # <b id="“b2”">我是第二個段落</b>
print(p.next_element.next_element.next_element)  # 我是第二個段落
for element in soup.body.div.a.next_element:  # 對:我是一個鏈接  字符串的遍歷print(element)

2.3.對象方法

?這里的搜索文檔,其實就是按照某種條件去搜索過濾文檔,過濾的規則,往往會使用搜索的API,或者我們也可以自定義正則/過濾器,去搜索文檔

2.3.1.find_all()

find_all( name , attrs , recursive , string , **kwargs ) 
參數/屬性類型作用示例
name字符串/正則/列表/函數指定標簽名稱(如?'div'soup.find_all('p')?查找所有?<p>?標簽
attrs字典通過屬性篩選(如?classidsoup.find_all(attrs={'class': 'header'})?匹配?class="header"?的標簽
recursive布爾值(默認?True是否遞歸搜索子標簽。False?時僅搜索直接子節點soup.find_all('div', recursive=False)?僅查頂層?<div>
string字符串/正則/函數直接搜索標簽內的文本內容(非標簽本身)soup.find_all(string='Hello')?查找文本為 "Hello" 的節點
**kwargs關鍵字參數簡化屬性篩選語法(等效于?attrssoup.find_all(class_='header')?匹配?class="header"
返回值ResultSet(類列表)返回所有匹配的標簽或文本節點的集合,若無結果則返回空列表?[]results = soup.find_all('a')?獲取所有?<a>?標簽
from bs4 import BeautifulSoup
import remarkup = '''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title id="myTitle">I’m the title</title></head><body><div><p><b id=“b1” class="bcl1">我是第一個段落</b><b>我是第二個段落</b><b id=“b3”>我是第三個段落</b><b id=“b4”>我是第四個段落</b></p><a href="www.temp.com">我是一個鏈接<h3>h3</h3></a><div id="dv1">str</div></div></body>
</html>'''
# 語法:find_all( name , attrs , recursive , string , **kwargs )
soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象
# 第一個參數name,可以是一個標簽名也可以是列表
print(soup.findAll('b'))   # 返回包含b標簽的列表 [<b id="“b1”">我是第一個段落</b>, <b id="“b2”">我是第二個段落</b>, <b id="“b3”">我是第三個段落</b>, <b id="“b4”">我是第四個段落</b>]
print(soup.findAll(['a', 'h3']))  # 按列表匹配多個 [<a href="www.temp.com">我是一個鏈接<h3>h3</h3></a>, <h3>h3</h3>]# 第二個參數attrs,可以指定參數名字,也可以不指定
print(soup.findAll('b', 'bcl1'))  # 匹配class='bcl1'的b標簽[<b class="bcl1" id="“b1”">我是第一個段落</b>]
print(soup.findAll(id="myTitle"))  # 指定id [<title id="myTitle">I’m the title</title>]
print(soup.find_all("b", attrs={"class": "bcl1"}))  # [<b class="bcl1" id="“b1”">我是第一個段落</b>]
print(soup.findAll(id=True))  # 匹配所有有id屬性的標簽# 第三個參數recursive 默認True 如果只想搜索tag的直接子節點,可以使用參數 recursive=False
print(soup.html.find_all("title", recursive=False))  # [] recursive=False。找html的直接子節點,是head,所以找不到title# 第四個參數string
print(soup.findAll('div', string='str'))  # [<div id="dv1">str</div>]
print(soup.find(string=re.compile("我是第二個")))  # 搜索我是第二個段落# 其他參數 limit 參數
print(soup.findAll('b', limit=2))  # 當搜索到的結果數量達到 limit 的限制時,就停止搜索返回結果,[<b class="bcl1" id="“b1”">我是第一個段落</b>, <b>我是第二個段落</b>]

2.3.2.find()

? find()與find_all() 的區別是 find_all() 方法的返回結果是值包含一個元素的列表,而 find() 方法直接返回結果(即找到了就不再找,只返第一個匹配的),find_all() 方法沒有找到目標是返回空列表, find() 方法找不到目標時,返回 None。

soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象
# 第一個參數name,可以是一個標簽名也可以是列表
print(soup.find('b'))   # 返回<b class="bcl1" id="“b1”">我是第一個段落</b>,只要找到一個即返回# 第二個參數attrs,可以指定參數名字,也可以不指定
print(soup.find('b', 'bcl1'))  # <b class="bcl1" id="“b1”">我是第一個段落</b>
print(soup.find(id="myTitle"))  # <title id="myTitle">I’m the title</title>
print(soup.find("b", attrs={"class": "bcl1"}))  # <b class="bcl1" id="“b1”">我是第一個段落</b>
print(soup.find(id=True))  # 匹配到第一個<title id="myTitle">I’m the title</title># 第三個參數recursive 默認True 如果只想搜索tag的直接子節點,可以使用參數 recursive=False
print(soup.html.find("title", recursive=False))  # None recursive=False。找html的直接子節點,是head,所以找不到title# 第四個參數string
print(soup.find('div', string='str'))  # [<div id="dv1">str</div>]
print(soup.find(string=re.compile("我是第二個")))  # 我是第二個段落

find匯總

方法分類方法名功能描述
父節點搜索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()返回文檔中當前節點之前第一個符合條件的節點

2.3.3.CSS選擇器查找

soup.select()?方法概述

  • 作用:通過 CSS 選擇器語法快速定位 HTML/XML 文檔中的標簽或節點。
  • 返回值:返回一個?ResultSet(類似列表的對象),包含所有匹配的節點。若無匹配則返回空列表?[]
  • 優勢:語法簡潔,支持復雜層級選擇(比?find_all?更靈活)。

參數解析

select('selector')

  • 唯一參數:字符串類型的 CSS 選擇器表達式。
    • 支持的選擇器類型
      選擇器類型示例說明
      標簽選擇器'div'選擇所有?<div>?標簽
      類選擇器'.header'選擇?class="header"?的標簽
      ID 選擇器'#main'選擇?id="main"?的標簽
      層級選擇器'div > p'選擇?<div>?直接子級的?<p>
      屬性選擇器'[href]'?或?'[data-id="1"]'按屬性名或屬性值篩選
      組合選擇器'div.header, p#intro'多條件組合選擇(逗號分隔)
from bs4 import BeautifulSoup
import remarkup = '''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title id="myTitle">I’m the title</title></head><body><div><p><b id=“b1” class="bcl1">我是第一個段落</b><b>我是第二個段落</b><b id=“b3”>我是第三個段落</b><b id=“b4”>我是第四個段落</b></p><a href="www.temp.com">我是一個鏈接<h3>h3</h3></a><div id="dv1">str</div></div></body>
</html>'''
soup = BeautifulSoup(markup, "html5lib")  # BeautifulSoup 對象
print(soup.select("html head title"))  # [<title id="myTitle">I’m the title</title>]
print(soup.select("body a"))  # [<a href="www.temp.com">我是一個鏈接<h3>h3</h3></a>]
print(soup.select("#dv1"))  # [<div id="dv1">str</div>]

2.3.4.修改內容

?修改tag的名稱、屬性、內容

from bs4 import BeautifulSoupsoup = BeautifulSoup('<b class="boldest">Extremely bold</b>', "html5lib")
tag = soup.b
tag.name = "blockquote"
print(tag)  # <blockquote class="boldest">Extremely bold</blockquote>tag['class'] = 'veryBold'
tag['id'] = 1
tag.string = "replace"tag.append(" append")#添加內容del tag['id']  # 刪除屬性

添加非標簽內容:

from bs4 import BeautifulSoup, NavigableString, Commentsoup = BeautifulSoup('<div><b class="boldest">Extremely bold</b></div>', "html5lib")
tag = soup.div
new_string = NavigableString('NavigableString')
tag.append(new_string)
print(tag)  # <div><b class="boldest">Extremely bold</b>NavigableString</div>new_comment = soup.new_string("Nice to see you.", Comment)
tag.append(new_comment)
print(tag)  # <div><b class="boldest">Extremely bold</b>NavigableString<!--Nice to see you.--></div># 添加標簽,推薦使用工廠方法new_tag
new_tag = soup.new_tag("a", href="http://www.example.com")
tag.append(new_tag)
print(tag)  # <div><b class="boldest">Extremely bold</b>NavigableString<!--Nice to see you.--><a href="http://www.example.com"></a></div>

???把元素插入到指定的位置:

from bs4 import BeautifulSoupmarkup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup,"html5lib")
tag = soup.a
tag.insert(1, "but did not endorse ")  # 和append的區別就是.contents屬性獲取不一致
print(tag)  # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a>
print(tag.contents)  # ['I linked to ', 'but did not endorse ', <i>example.com</i>]

將當前tag移除文檔樹,并作為方法結果返回:?

from bs4 import BeautifulSoupmarkup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup, "html5lib")
a_tag = soup.a
print(a_tag)#<a href="http://example.com/">I linked to <i>example.com</i></a>
i_tag = soup.i.extract()print(a_tag)  # <a href="http://example.com/">I linked to </a>
print(i_tag)  # <i>example.com</i>  我們移除的內容
方法功能描述示例代碼輸出結果關鍵區別
decompose()完全移除并銷毀節點,不可恢復soup.i.decompose()
print(a_tag)
<a href="...">I linked to </a>永久性刪除,內存中不再存在
replace_with()用新節點/文本替換原節點,保留文檔結構new_tag = soup.new_tag("b")
new_tag.string = "example.net"
soup.a.i.replace_with(new_tag)
<a href="...">I linked to <b>example.net</b></a>可靈活替換為任意節點類型(標簽/文本/注釋等)
unwrap()移除當前標簽,但保留其內容(解包操作)a_tag.i.unwrap()
print(a_tag)
<a href="...">I linked to example.com</a>僅去除標簽外殼,內容提升到父層級
wrap()用新標簽包裹指定內容(反向操作)soup2.p.string.wrap(soup2.new_tag("b"))
print(soup2.p)
<p><b>I wish I was bold.</b></p>常用于添加格式化標簽(如加粗/高亮)

2.4.輸出

2.4.1.格式化輸出

prettify()?方法將Beautiful Soup的文檔樹格式化后以Unicode編碼輸出,每個XML/HTML標簽都獨占一行。

from bs4 import BeautifulSoupmarkup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup, "html5lib")
print(soup)  # <html><head></head><body><a href="http://example.com/">I linked to <i>example.com</i></a></body></html>
print(soup.prettify())   #<html>#  <head>#  </head>#  <body>#   <a href="http://example.com/">#    I linked to#    <i>#     example.com#    </i>#   </a>#  </body># </html>

2.4.2.壓縮輸出

果只想得到結果字符串,不重視格式,那么可以對一個?BeautifulSoup?對象或?Tag?對象使用Python的str()?方法。

2.4.3.文本輸出

如果只想得到tag中包含的文本內容,那么可以調用?get_text()?方法。

from bs4 import BeautifulSoupmarkup = '<a href="http://example.com/">I linked to <i>example.com</i>點我</a>'
soup = BeautifulSoup(markup, "html5lib")
print(soup)
print(str(soup))  
print(soup.get_text())

?

?3.re標準庫

? BeautifulSoup庫,重html文檔中篩選我們想要的數據,但這些數據可能還有很多更細致的內容,比如,我們取到的是不是我們想要的鏈接、是不是我們需要提取的郵箱數據等等,為了更細致精確的提取數據,那么正則來了。

? ? 正則表達式(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),是計算機科學的一個概念。正則表達式使用單個字符串來描述、匹配一系列匹配某個句法規則的字符串。在其他語言中,我們也經常會接觸到正則表達式。 ? ?

方法/概念代碼示例關鍵說明
re.compile()pat = re.compile('\d{2}')預編譯正則模式,匹配連續2位數字
search()pat.search("12abc")在任意位置搜索首次匹配,成功返回Match對象
match()pat.match('1224abc')僅從字符串起始位置匹配,成功返回Match對象
findall()re.findall(r'apple',s)
re.findall(r'apple',s,re.I)
默認區分大小寫,re.I標志忽略大小寫
sub()替換re.sub('a','A','abcdacdl')將所有小寫a替換為大寫A
import re# 創建正則對象
pat = re.compile('\d{2}')  #出現2次數字的
# search 在任意位置對給定的正則表達式模式搜索第一次出現的匹配情況
s = pat.search("12abc")
print(s.group())  # 12# match 從字符串起始部分對模式進行匹配
m = pat.match('1224abc')
print(m.group())  # 12# search 和 match 的區別 匹配的位置不也一樣
s1 = re.search('foo', 'bfoo').group()
print(s1)  # foo
try:m1 = re.match('foo','bfoo').group()  # AttributeError
except:print('匹配失敗')   # 匹配失敗# 原生字符串(\B 不是以py字母結尾的)
allList = ["py!", "py.", "python"]
for li in allList:# re.match(正則表達式,要匹配的字符串)if re.match(r'py\B', li):print(li)  # python# findall()
s = "apple Apple APPLE"
print(re.findall(r'apple', s))  # ['apple']
print(re.findall(r'apple', s, re.I))  # ['apple', 'Apple', 'APPLE']# sub()查找并替換
print(re.sub('a', 'A', 'abcdacdl'))  # AbcdAcdl

?

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

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

相關文章

Ubuntu-Linux從桌面到顯示的全流程:技術分析總結

引言 Ubuntu作為主流的Linux發行版&#xff0c;其顯示系統經歷了從傳統X11到現代Wayland的演進。本文將詳細分析從應用程序到屏幕顯示的完整技術流程&#xff0c;包括桌面環境、顯示服務器、圖形棧和硬件交互等核心環節。 1. 系統架構概覽 Ubuntu的顯示系統架構可分為四個主要…

在PyCharm中部署AI模型的完整指南

引言 隨著人工智能技術的快速發展,越來越多的開發者開始將AI模型集成到他們的應用程序中。PyCharm作為一款強大的Python IDE,為AI開發提供了出色的支持。本文將詳細介紹如何在PyCharm中部署AI模型,從環境配置到最終部署的完整流程。 第一部分:準備工作 1. 安裝PyCharm …

WHAT - 靜態資源緩存穿透

文章目錄 1. 動態哈希命名的基本思路2. 具體實現2.1 Vite/Webpack 配置動態哈希2.2 HTML 文件中動態引用手動引用使用 index.html 模板動態插入 2.3 結合 Cache-Control 避免緩存穿透2.4 適用于多環境的動態策略 總結 在多環境部署中&#xff0c;靜態資源緩存穿透是一個常見問題…

PoCL環境搭建

PoCL環境搭建 **一.關鍵功能與優勢****二.設計目的****三.測試步驟**1.創建容器2.安裝依賴3.編譯安裝pocl4.運行OpenCL測試程序 Portable Computing Language (PoCL) 簡介 Portable Computing Language (PoCL) 是一個開源的、符合標準的異構計算框架&#xff0c;旨在為 OpenCL…

【區塊鏈技術解析】從原理到實踐的全鏈路指南

目錄 前言&#xff1a;技術背景與價值當前技術痛點解決方案概述目標讀者說明 一、技術原理剖析核心概念圖解核心作用講解關鍵技術模塊技術選型對比 二、實戰演示環境配置要求核心代碼實現&#xff08;10個案例&#xff09;案例1&#xff1a;創建簡單區塊鏈案例2&#xff1a;工作…

在Windows上安裝Git

一、安裝 Git 下載 Git地址&#xff1a;Git - Downloads (git-scm.com) 1、在頁面中找到適用于 Windows 系統的最新版本安裝包&#xff08;通常為.exe 格式文件&#xff09;&#xff0c;點擊下載鏈接。 出于訪問Git官網需要科學上網&#xff0c;不會的可以私信我要軟件包&…

Golang interface總結(其一)

本篇是對golang 中的interface做一些淺層的、實用的總結 多態 常用場景 interface內僅包含函數類型&#xff0c;然后定義結構體去實現&#xff0c;如下 package mainimport "fmt"type Animal interface {Sound()Act() }type Cat struct{}func (c *Cat) Sound() {…

TVM計算圖分割--Collage

1 背景 為滿足高效部署的需要&#xff0c;整合大量優化的tensor代數庫和運行時做為后端成為必要之舉。現在的深度學習后端可以分為兩類&#xff1a;1&#xff09;算子庫(operator kernel libraries)&#xff0c;為每個DL算子單獨提供高效地低階kernel實現。這些庫一般也支持算…

Redis——內存策略

目錄 前言 1.過期策略 1.1過期策略——DB結構 1.2過期策略——惰性刪除 1.3過期策略——定期刪除 2.淘汰策略 2.1最少最近使用和使用頻率原理 2.2內存淘汰策略執行流程 總結&#xff1a; 前言 Redis之所以性能強&#xff0c;主要的原因就是基于內存存儲。然而單節點的R…

原型模式詳解及在自動駕駛場景代碼示例(c++代碼實現)

模式定義 原型模式&#xff08;Prototype Pattern&#xff09;是一種創建型設計模式&#xff0c;通過克隆已有對象來創建新對象&#xff0c;避免重復執行昂貴的初始化操作。該模式特別適用于需要高效創建相似對象的場景&#xff0c;是自動駕駛感知系統中處理大量重復數據結構的…

在kali中安裝AntSword(蟻劍)

步驟一、下載壓縮包 源碼&#xff1a;https://github.com/AntSwordProject/antSword&#xff0c;下載壓縮包。 加載器&#xff1a;https://github.com/AntSwordProject/AntSword-Loader&#xff0c;根據系統選擇壓縮包&#xff08;kali選擇AntSword-Loader-v4.0.3-linux-x64&…

華為倉頡編程語言基礎概述

第一章&#xff1a;技術演進與誕生背景 1.1 萬物智聯時代的編程挑戰 在5G、物聯網、邊緣計算等技術推動下&#xff0c;全球智能設備數量呈指數級增長。據IDC預測&#xff0c;2025年全球IoT設備將突破550億臺&#xff0c;這對系統級編程語言提出新要求&#xff1a; 異構硬件兼…

【Linux篇】探索進程間通信:如何使用匿名管道構建高效的進程池

從零開始&#xff1a;通過匿名管道實現進程池的基本原理 一. 進程間通信1.1 基本概念1.2 通信目的1.3 通信種類1.3.1 同步通信1.3.2 異步通信 1.4 如何通信 二. 管道2.1 什么是管道2.2 匿名管道2.2.1 pipe()2.2.2 示例代碼&#xff1a;使用 pipe() 進行父子進程通信2.2.3 管道容…

【LeetCode】嚼爛熱題100【持續更新】

2、字母異位詞分組 方法一&#xff1a;排序哈希表 思路&#xff1a;對每個字符串排序&#xff0c;排序后的字符串作為鍵插入到哈希表中&#xff0c;值為List<String>形式存儲單詞原型&#xff0c;鍵為排序后的字符串。 Map<String, List<String>> m new Ha…

2025年最新版 Git和Github的綁定方法,以及通過Git提交文件至Github的具體流程(詳細版)

文章目錄 Git和Github的綁定方法與如何上傳至代碼倉庫一. 注冊 GitHub 賬號二.如何創建自己的代碼倉庫&#xff1a;1.登入Github賬號&#xff0c;完成登入后會進入如下界面&#xff1a;2.點擊下圖中紅色框選的按鈕中的下拉列表3.選擇New repostitory4.進入創建界面后&#xff0…

FPGA開發板這樣做?(一)-像 Arduino 一樣玩 FPGA

這也是一個系列文章&#xff0c;來源之前和粉絲們在評論區討論的國外對于FPGA的開發或者入門所做的努力。 基本一篇文章會介紹一個FPGA開發板&#xff0c;重點在于為開發板準備的開發方式&#xff08;和國內大不相同&#xff09;。 今天的主角-PulseRain M10&#xff1a;像 Ard…

【C++游戲引擎開發】第21篇:基于物理渲染(PBR)——統計學解構材質與光影

引言 宏觀現象:人眼觀察到的材質表面特性(如金屬的高光銳利、石膏的漫反射柔和),本質上是微觀結構對光線的統計平均結果。 微觀真相:任何看似平整的表面在放大后都呈現崎嶇的微觀幾何。每個微表面(Microfacet)均為完美鏡面,但大量微表面以不同朝向分布時,宏觀上會表…

深入理解linux操作系統---第11講 bshell編程

11.1 正則表達式 11.1.1 字符集 正則表達式的字符集包含三類核心要素&#xff1a; 普通字符&#xff1a;直接匹配單個字符&#xff0c;如a匹配字母a范圍字符集&#xff1a;[a-z]匹配所有小寫字母&#xff0c;[0-9A-F]匹配十六進制數字預定義字符集&#xff1a;\d等價于[0-9]…

C++中的引用:深入理解與實用示例

文章目錄 C中的引用&#xff1a;深入理解與實用示例一、引用的基本概念二、引用作為別名的應用三、引用作為函數參數四、指針與引用的區別五、常量引用六、引用與返回值七、總結 C中的引用&#xff1a;深入理解與實用示例 在C編程中&#xff0c;“引用”是一個強大而重要的概念…

C#委托介紹

委托可以將方法作為參數傳遞&#xff0c;同時委托也可以自己作為參數傳遞 委托可分為自定義委托delegate 無返回值的Action 與有返回值的Func委托 也有匿名委托與Lamada 委托支持多播是事件的基礎 用處如在分線程調用主線程的UI invoke public delegate string Say(stri…