文鏈接:Optimize resource loading, from web.dev。翻譯時(shí)有刪改。
在上一篇文章中,我們討論了關(guān)鍵渲染路徑,了解了影響頁(yè)面初始渲染效率的阻塞渲染 CSS 和 阻塞解析 JavaScript。
頁(yè)面加載時(shí),會(huì)伴隨很多資源的引用。這些資源可能是為頁(yè)面提供外觀和布局的 CSS,也可能是提交頁(yè)面交互效果的 JavaScript。
本文,我們將深入了解這 2 類(lèi)資源的阻塞原理并具體學(xué)習(xí)一些優(yōu)化手段。
從之前的學(xué)習(xí),我們知道 CSS 屬于阻塞渲染的資源,在瀏覽器完成下載和解析 CSS 成為 CSSOM 之前,會(huì)停止渲染工作。
之所以將 CSS 作為阻塞渲染的資源,是為了避免頁(yè)面出現(xiàn)短暫的無(wú)樣式閃現(xiàn)。類(lèi)似下面這樣:
有一個(gè)術(shù)語(yǔ)專門(mén)用于描述這個(gè)場(chǎng)景,叫 FOUC,全稱是“Flash of Unstyled Content”。
因?yàn)?CSS 會(huì)作為阻塞渲染的資源處理,F(xiàn)OUC 現(xiàn)象你通常是看不到的,但要理解這個(gè)概念,就能明白瀏覽器為什么要這么做了。
從之前的學(xué)習(xí),我們知道瀏覽器在遇到 <script> 元素時(shí),會(huì)阻塞瀏覽器進(jìn)一步的解析 ,優(yōu)先下載、處理和執(zhí)行 JavaScript,在處于其余部分的 HTML。
JavaScript 的阻塞解析,也是瀏覽器刻意為之的策略。這是因?yàn)?JavaScript 代碼中可能會(huì)包含對(duì) DOM 結(jié)構(gòu)的訪問(wèn)和修改。
html復(fù)制代碼<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>
當(dāng) <script> 元素沒(méi)有注明是 async/defer 的情況下,瀏覽器會(huì)先終止后續(xù)解析,優(yōu)先下載(可選,適應(yīng)于引用外部資源)、解析、執(zhí)行 JavaScript 文件。直到這一過(guò)程結(jié)束,瀏覽器才繼續(xù)后續(xù)內(nèi)容的解析。
值得注意的是,JavaScript 的執(zhí)行也有一個(gè)前提,就是當(dāng)前沒(méi)有正在處理的 CSS 資源,這也是刻意為之。
因?yàn)?CSS 解析時(shí),并不會(huì)阻止瀏覽器解析 JavaScript,如果 JavaScript 中有類(lèi)似 element.getComputedStyle() 代碼調(diào)用,那么必然要等到樣式解析完成才行,否則是不準(zhǔn)確的。因此,JavaScript 的執(zhí)行要等待 CSS 解析徹底完成。
預(yù)加載掃描器(preload scanner) 是瀏覽器的一個(gè)優(yōu)化手段,它是主 HTML 解析器(primary HTML parser)之外的另一個(gè) HTML 解析器,叫輔助 HTML 解析器(secondary HTML parser)。
預(yù)加載掃描器會(huì)在主 HTML 解析器發(fā)現(xiàn)資源之前查找并獲取資源。比如:提前下載 <img> 元素中指定的資源。這個(gè)操作即便在 HTML 解析器被 JavaScript 和 CSS 阻塞也是如此。
不過(guò)預(yù)加載掃描器也有一些處理盲區(qū)。盲區(qū)之內(nèi)引用的資源無(wú)法被識(shí)別,也就無(wú)法優(yōu)化了。這些處理盲區(qū)包括:
以上場(chǎng)景都有一個(gè)共同特點(diǎn),就是資源加載都是滯后的,自然就無(wú)法被預(yù)加載掃描器知道。
當(dāng)然,針對(duì)這類(lèi)場(chǎng)景我們還能使用 preload hint 手動(dòng)提示來(lái)支持。不過(guò)這是下一篇的內(nèi)容了,這里先不贅述。
CSS 影響頁(yè)面的外觀和布局效果,它是一種阻塞渲染的資源。本小節(jié),我們就來(lái)看看如果優(yōu)化 CSS,來(lái)改善頁(yè)面加時(shí)間。
通過(guò)壓縮 CSS 減少文件大小,從而加快下載速度。
demo:壓縮前
css復(fù)制代碼/* Unminified CSS: */
/* Heading 1 */
h1 {
font-size: 2em;
color: #000000;
}
/* Heading 2 */
h2 {
font-size: 1.5em;
color: #000000;
}
demo:壓縮后
css復(fù)制代碼/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}
壓縮是 CSS 最基本而且有效的一個(gè)優(yōu)化手段,可以提高網(wǎng)站 FCP 甚至 LCP 指標(biāo)。一般前端工程中是配置的打包工具(bundler)都內(nèi)置了這個(gè)功能。
在瀏覽器渲染網(wǎng)頁(yè)內(nèi)容前,需要下載并解析所有樣式。當(dāng)然,這里花費(fèi)的時(shí)間還包括當(dāng)前頁(yè)面未使用的樣式。如果你使用的打包工具將所有 CSS 資源組合到一個(gè)文件中,那么你的用戶可能會(huì)下載比實(shí)際當(dāng)前渲染頁(yè)面所需要的更多 CSS。
要發(fā)現(xiàn)當(dāng)前頁(yè)面未使用的 CSS,可以使用 Chrome DevTools 中的 Coverage 工具。
刪除未使用的 CSS 會(huì)帶來(lái) 2 個(gè)好處:
雖然看起來(lái)很方便,但您應(yīng)該避免在 CSS 中使用 @import 聲明:
css復(fù)制代碼/* Don't do this: */
@import url('style.css');
與 HTML 中 <link> 元素的工作方式類(lèi)似,CSS 中的 @import 聲明能讓你從樣式表中導(dǎo)入外部 CSS 資源。
這兩種方法之間的主要區(qū)別在于 HTML <link> 元素是 HTML 響應(yīng)的一部分,因此比通過(guò) @import 聲明下載的 CSS 文件能更快比發(fā)現(xiàn)。
原因在于 @import 聲明必須先下載包含 CSS 文件。這會(huì)產(chǎn)生所謂的請(qǐng)求鏈(request chain),它會(huì)延遲頁(yè)面初始渲染所需的時(shí)間。另一個(gè)缺點(diǎn),是使用 @import 聲明加載的樣式表無(wú)法被預(yù)加載掃描器發(fā)現(xiàn),也會(huì)成為后期發(fā)現(xiàn)的渲染阻塞資源。
html復(fù)制代碼<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">
在大多數(shù)情況下,你可以使用 <link rel="stylesheet"> 元素替換 @import。<link> 元素是同時(shí)下載樣式表的,這樣能減少總體加載時(shí)間,這與 @import 聲明連續(xù)下載樣式表的策略也是不一樣的。
所謂“關(guān)鍵 CSS”是指“首屏”頁(yè)面內(nèi)容所需要的樣式。
下載 CSS 文件需要時(shí)間,這會(huì)增加頁(yè)面的 FCP 指標(biāo)。如果在文檔 <head> 中內(nèi)聯(lián)關(guān)鍵樣式可以消除對(duì) CSS 資源的網(wǎng)絡(luò)請(qǐng)求。剩余的 CSS 可以異步加載,或者附加在 <body> 元素的末尾。
html復(fù)制代碼<head>
<title>Page Title</title>
<!-- ... -->
<style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
<!-- Other page markup... -->
<link rel="stylesheet" href="non-critical.css">
</body>
另一方面,內(nèi)聯(lián)大量 CSS 會(huì)向初始 HTML 響應(yīng)增加更多字節(jié)。而通過(guò) HTML 資源通常無(wú)法緩存很長(zhǎng)時(shí)間(或根本不緩存),因此這個(gè)也需要我們基于自身情況做選擇。
JavaScript 驅(qū)動(dòng)了網(wǎng)絡(luò)上的大部分交互,但也付出了代價(jià)。
傳送太多的 JavaScript 可能會(huì)讓頁(yè)面加載時(shí)間太長(zhǎng)、響應(yīng)緩慢,交互也變慢了,這兩種情況都會(huì)讓用戶抓狂。
當(dāng)網(wǎng)頁(yè)中使用的 <script> 元素不帶 defer 或 async 時(shí),當(dāng)前代碼的解析會(huì)阻止瀏覽器后續(xù)工作的進(jìn)行,直到當(dāng)前代碼處理完成。同樣的,內(nèi)聯(lián)腳本也會(huì)阻塞解析,直到腳本代碼處理完成。
<script> 的 async 和 defer attribute 可以讓你在加載外部腳本同時(shí)不阻塞 HTML 解析器的工作。不過(guò),async 和 defer 策略上還是有一些不同。
來(lái)源自 html.spec.whatwg.org/multipage/s…
使用 async 加載的腳本在下載后立即解析并執(zhí)行;而使用 defer 加載的腳本在 HTML 文檔解析完成時(shí)執(zhí)行——跟 DOMContentLoaded 事件一個(gè)時(shí)機(jī)。
另外,當(dāng)網(wǎng)頁(yè)中同時(shí)存在多個(gè)腳本時(shí)。 async 腳本可能無(wú)法保證執(zhí)行執(zhí)行,而 defer 腳本則會(huì)始終按照它們?cè)谠创a中出現(xiàn)的順序執(zhí)行。
值得注意的是:帶有 type="module" 的腳本(包括內(nèi)聯(lián)腳本)效果跟 defer 一樣;而通過(guò)腳本動(dòng)態(tài)注入的 <script> 標(biāo)簽效果類(lèi)似 async。
一般來(lái)說(shuō),你應(yīng)該避免使用 JavaScript 來(lái)呈現(xiàn)任何關(guān)鍵內(nèi)容或頁(yè)面的 LCP 元素。這種做法稱為“客戶端渲染”,是單頁(yè)應(yīng)用程序 (SPA) 中廣泛使用的一種技術(shù)。
通過(guò) JavaScript 渲染的 HTML 標(biāo)簽是無(wú)法被預(yù)加載掃描器觀察到的。這可能會(huì)延遲關(guān)鍵資源的下載,例如 LCP 圖片。瀏覽器只會(huì)在腳本執(zhí)行后才開(kāi)始下載 LCP 圖片,并添加到 DOM 中,這應(yīng)該被避免。
此外,與直接在服務(wù)器響應(yīng)請(qǐng)求返回相比,使用 JavaScript 渲染標(biāo)簽更有可能產(chǎn)生較長(zhǎng)的任務(wù)。廣泛使用 HTML 客戶端渲染也會(huì)延遲交互,在頁(yè)面 DOM 非常大的情況下尤其如此。
與 CSS 類(lèi)似,壓縮 JavaScript 可以減少腳本文件大小,加快下載速度,讓瀏覽器更快解析和編譯 JavaScript。
此外,JavaScript 的壓縮可以比 CSS 等其他資源更好。當(dāng)壓縮 JavaScript 時(shí),它不僅能刪除空格、制表符和注釋等內(nèi)容,而且 JavaScript 中標(biāo)識(shí)符也能被縮短,這個(gè)過(guò)程有時(shí)被稱為丑化(uglification)。
js復(fù)制代碼// Unuglified JavaScript source code:
export function injectScript () {
const scriptElement = document.createElement('script');
scriptElement.src = '/js/scripts.js';
scriptElement.type = 'module';
document.body.appendChild(scriptElement);
}
js復(fù)制代碼// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}
觀察可以發(fā)現(xiàn),你可以看到源代碼中變量 scriptElement 被縮短成 t 了。當(dāng)你腳本代碼很多時(shí),這種做法可以節(jié)省的體積相當(dāng)可觀,而且也不會(huì)影響網(wǎng)站的生產(chǎn)環(huán)境功能。
如果你有在用打包工具處理網(wǎng)站源碼,JavaScript 的生產(chǎn)壓縮默認(rèn)就有。這類(lèi)丑化工具——例如 Terser——也是高度可配置的,你可以調(diào)整丑化算法的激進(jìn)程度來(lái)實(shí)現(xiàn)最大程度的壓縮。然而,任何丑化工具的默認(rèn)設(shè)置通常就足夠使用的了。
本文在上一篇關(guān)鍵渲染路徑的基礎(chǔ)上,進(jìn)一步討論了瀏覽器針對(duì) JavaScript/CSS 采用的不同阻塞策略的原因,繼而給出優(yōu)化 JavaScript、CSS 的不同手段。希望對(duì)各位正在閱讀的朋友日后的工作帶來(lái)一些幫助。
下一篇里,我們會(huì)繼續(xù)探討另一種在網(wǎng)頁(yè)中進(jìn)行手工優(yōu)化的方式——資源提示(resource hints),敬請(qǐng)期待。
再見(jiàn)。
網(wǎng)絡(luò)爬蟲(chóng)開(kāi)發(fā)中,使用強(qiáng)大的庫(kù)是至關(guān)重要的,而requests-html就是其中一顆璀璨的明星。本文將深度探討requests-html的各個(gè)方面,包括基本的HTTP請(qǐng)求、HTML解析、JavaScript渲染、選擇器的使用以及高級(jí)特性的應(yīng)用。
首先,需要安裝requests-html:
pip install requests-html
然后,進(jìn)行簡(jiǎn)單的HTTP請(qǐng)求:
from requests_html import HTMLSession
session = HTMLSession()
response = session.get('https://example.com')
print(response.html.text)
requests-html內(nèi)置了強(qiáng)大的HTML解析器和類(lèi)似jQuery的選擇器,使得數(shù)據(jù)提取變得非常便捷:
# 使用選擇器提取標(biāo)題
titles = response.html.find('h2')
for title in titles:
print(title.text)
對(duì)于需要JavaScript渲染的頁(yè)面,requests-html也能輕松應(yīng)對(duì):
# JavaScript渲染
r = session.get('https://example.com', params={'q': 'python'})
r.html.render()
print(r.html.text)
1 異步JavaScript渲染
對(duì)于異步加載的JavaScript內(nèi)容,requests-html提供了pyppeteer的支持:
# 異步JavaScript渲染
r = session.get('https://example.com')
r.html.render(sleep=1, keep_page=True)
print(r.html.text)
2 自定義Headers和Cookies
在請(qǐng)求中自定義Headers和Cookies是常見(jiàn)需求,requests-html為此提供了簡(jiǎn)單易用的方法:
# 自定義Headers和Cookies
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
cookies = {'example_cookie': 'value'}
r = session.get('https://example.com', headers=headers, cookies=cookies)
print(r.html.text)
1 抓取動(dòng)態(tài)頁(yè)面
通過(guò)requests-html,可以輕松抓取動(dòng)態(tài)頁(yè)面的數(shù)據(jù):
# 抓取動(dòng)態(tài)頁(yè)面
r = session.get('https://example.com/dynamic-page')
r.html.render()
print(r.html.text)
2 表單提交
模擬用戶行為,實(shí)現(xiàn)表單提交:
# 表單提交
payload = {'username': 'user', 'password': 'pass'}
r = session.post('https://example.com/login', data=payload)
print(r.html.text)
requests-html內(nèi)置了類(lèi)似于jQuery的選擇器,讓數(shù)據(jù)提取變得輕松:
# 使用選擇器提取鏈接
links = response.html.find('a')
for link in links:
print(link.attrs['href'])
此外,通過(guò)更復(fù)雜的選擇器和過(guò)濾器,可以更精準(zhǔn)地定位和提取所需數(shù)據(jù):
# 使用更復(fù)雜的選擇器和過(guò)濾器
articles = response.html.find('article')
for article in articles:
title = article.find('h2', first=True).text
author = article.find('.author', first=True).text
print(f"Title: {title}, Author: {author}")
對(duì)于需要等待頁(yè)面加載完成的情況,requests-html提供了wait參數(shù):
# 等待頁(yè)面加載完成
r = session.get('https://example.com/dynamic-content')
r.html.render(wait=2)
print(r.html.text)
此外,還可以利用render函數(shù)生成頁(yè)面截圖:
# 生成頁(yè)面截圖
r = session.get('https://example.com')
r.html.render(screenshot='screenshot.png')
在爬蟲(chóng)過(guò)程中,異常處理是不可或缺的一部分。requests-html提供了捕獲異常和錯(cuò)誤頁(yè)面重試的選項(xiàng):
# 異常處理和錯(cuò)誤頁(yè)面重試
try:
r = session.get('https://example.com/unstable-page')
r.html.render(retries=3, wait=2)
print(r.html.text)
except Exception as e:
print(f"Error: {e}")
在爬蟲(chóng)開(kāi)發(fā)中,性能優(yōu)化和并發(fā)請(qǐng)求是至關(guān)重要的。requests-html提供了一些功能和選項(xiàng),能夠更好地處理這些方面的問(wèn)題。
1. 并發(fā)請(qǐng)求
并發(fā)請(qǐng)求是同時(shí)向多個(gè)目標(biāo)發(fā)送請(qǐng)求,以提高效率。requests-html使用asyncio庫(kù)支持異步請(qǐng)求,從而實(shí)現(xiàn)并發(fā)。以下是一個(gè)簡(jiǎn)單的例子:
from requests_html import AsyncHTMLSession
async def fetch(url):
async with AsyncHTMLSession() as session:
response = await session.get(url)
return response.html.text
urls = ['https://example.com/page1', 'https://example.com/page2', 'https://example.com/page3']
# 利用asyncio.gather實(shí)現(xiàn)并發(fā)請(qǐng)求
results = AsyncHTMLSession().run(lambda: [fetch(url) for url in urls])
for result in results:
print(result)
在這個(gè)例子中,asyncio.gather被用于同時(shí)運(yùn)行多個(gè)異步請(qǐng)求。這種方式在大量頁(yè)面需要抓取時(shí)可以顯著提高效率。
2. 鏈接池
requests-html的Session對(duì)象內(nèi)置了連接池,它能夠維護(hù)多個(gè)持久化連接,減少請(qǐng)求時(shí)的連接建立開(kāi)銷(xiāo)。這對(duì)于頻繁請(qǐng)求同一域名下的多個(gè)頁(yè)面時(shí)尤為有用。以下是一個(gè)簡(jiǎn)單的使用示例:
from requests_html import HTMLSession
session = HTMLSession()
# 利用連接池發(fā)送多個(gè)請(qǐng)求
responses = session.get(['https://example.com/page1', 'https://example.com/page2', 'https://example.com/page3'])
for response in responses:
print(response.html.text)
這里,session.get()接受一個(gè)包含多個(gè)URL的列表,使用連接池維護(hù)這些請(qǐng)求的連接。
3. 緩存
requests-html允許使用緩存,以避免重復(fù)下載相同的內(nèi)容。這對(duì)于頻繁訪問(wèn)不經(jīng)常更新的網(wǎng)頁(yè)時(shí)很有用。以下是一個(gè)使用緩存的例子:
from requests_html import HTMLSession
session = HTMLSession()
# 使用緩存
response = session.get('https://example.com', cached=True)
print(response.html.text)
在這個(gè)例子中,cached=True表示啟用緩存。
在本篇博客中,深入探討了requests-html這一Python爬蟲(chóng)庫(kù),揭示了其強(qiáng)大而靈活的功能。通過(guò)詳細(xì)的示例代碼和實(shí)際應(yīng)用場(chǎng)景,展示了如何使用該庫(kù)進(jìn)行HTTP請(qǐng)求、HTML解析、JavaScript渲染以及高級(jí)功能的應(yīng)用。requests-html的異步支持使得并發(fā)請(qǐng)求變得輕而易舉,通過(guò)連接池和緩存的利用,我們能夠更好地優(yōu)化性能,提高爬蟲(chóng)的效率。同時(shí),庫(kù)內(nèi)置的強(qiáng)大選擇器和靈活的數(shù)據(jù)提取方式讓頁(yè)面解析變得更為簡(jiǎn)單。
總體而言,requests-html為爬蟲(chóng)開(kāi)發(fā)者提供了一個(gè)強(qiáng)大而友好的工具,使得從靜態(tài)網(wǎng)頁(yè)到動(dòng)態(tài)渲染頁(yè)面的抓取都變得更加便捷。通過(guò)學(xué)習(xí)本文,不僅能夠熟練掌握requests-html的基本用法,還能深入理解其高級(jí)功能,為實(shí)際項(xiàng)目的開(kāi)發(fā)提供更全面的解決方案。希望通過(guò)這篇博客,能夠更加自信和高效地運(yùn)用requests-html來(lái)應(yīng)對(duì)各類(lèi)爬蟲(chóng)任務(wù)。
、BeautifulSoup簡(jiǎn)介
BeautifulSoup是Python爬蟲(chóng)應(yīng)用解析Html的利器,是Python三方模塊bs4中提供的進(jìn)行HTML解析的類(lèi),可以認(rèn)為是一個(gè)HTML解析工具箱,對(duì)HTML報(bào)文中的標(biāo)簽具有比較好的容錯(cuò)識(shí)別功能。lxml是一款html文本解析器,BeautifulSoup構(gòu)建對(duì)象時(shí)需要指定HTML解析器,推薦使用lxml。
BeautifulSoup和lxml安裝命令:
1.pip install -i https://pypi.tuna.tsinghua.edu.cn/simple bs4
2.pip install -i https://pypi.tuna.tsinghua.edu.cn/simple lxml
加載BeautifulSoup:
1.from bs4 import BeautifulSoup
BeatifulSoap解析HTML報(bào)文的常用功能:
通過(guò)標(biāo)簽的contents屬性,可以訪問(wèn)其下嵌套的所有下級(jí)HTML元素,這些該標(biāo)簽下的子標(biāo)簽對(duì)應(yīng)的HTML元素放到一個(gè)contents 指向的列表中。
如:print(soup.body.contents)
可以訪問(wèn)標(biāo)簽對(duì)應(yīng)的父、子、兄弟及祖先標(biāo)簽信息;
使用strings屬性迭代訪問(wèn)除標(biāo)簽外的所有內(nèi)容;
可以使用find、find_all、find_parent、find_parents等系列方法查找滿足特定條件的標(biāo)簽;
使用select通過(guò)css選擇器定位特定標(biāo)簽。
二、一些解析技巧
在HTML解析時(shí),如果通過(guò)簡(jiǎn)單的tag、或單個(gè)tag屬性(如id、class)或文本一次搜索或select定位是最簡(jiǎn)單的,而有些情況需要使用組合方法才能處理。
2.1、通過(guò)標(biāo)簽的多個(gè)屬性組合定位或查找
經(jīng)常有些要定位的標(biāo)簽有很多,按單個(gè)屬性查找也有很多,得使用多個(gè)屬性查找。如:
上面的html文本中有多個(gè)id為article_content的div標(biāo)簽,如果使用:
就會(huì)返回兩條記錄。這時(shí)候就可以使用多標(biāo)簽屬性定位的如下4種語(yǔ)句:
以上四種方式是等價(jià)的,因?yàn)閕d可以用#來(lái)標(biāo)記,class在查找時(shí)需要和Python關(guān)鍵字class區(qū)分,因此有上述不同方法,注意select的每個(gè)屬性必須用中括號(hào)括起來(lái),不同屬性的中括號(hào)之間不能有空格,如果有空格表示的就不是查找同一標(biāo)簽的屬性,空格后的屬性表示前一個(gè)屬性對(duì)應(yīng)標(biāo)簽的子孫標(biāo)簽的屬性。
2.2、利用tag標(biāo)簽關(guān)系定位內(nèi)容
tag標(biāo)簽關(guān)系包括父子、兄弟、祖先等關(guān)系,有時(shí)要查找或定位的內(nèi)容本身不是很好定位,但結(jié)合其他標(biāo)簽關(guān)系(主要是父子、祖先關(guān)系)則可以唯一確認(rèn)。
案例:
這是博文中關(guān)于博主個(gè)人信息的部分報(bào)文:
以上報(bào)文中,如果要取博主的原創(chuàng)文章數(shù)和周排名,原創(chuàng)文章數(shù)和博主周排名的tag標(biāo)簽完全相同,二者都在span標(biāo)簽內(nèi),標(biāo)簽的屬性及值都相同,只是span標(biāo)簽的父標(biāo)簽dt標(biāo)簽的兄弟標(biāo)簽dd標(biāo)簽的string的中文內(nèi)容才能區(qū)分。對(duì)于這種情況,首先要通過(guò)祖先標(biāo)簽<div class="data-info d-flex item-tiling">定位到祖先標(biāo)簽,再在祖先標(biāo)簽內(nèi)通過(guò)中文字符串定位到要訪問(wèn)屬性的兄弟標(biāo)簽的子標(biāo)簽,然后通過(guò)該子標(biāo)簽找到其父標(biāo)簽的父標(biāo)簽,再通過(guò)該父標(biāo)簽的dt子標(biāo)簽的span子標(biāo)簽訪問(wèn)具體取值。
示例代碼如下:
注意:上面的select使用的也是標(biāo)簽的屬性來(lái)定位標(biāo)簽,并且兩個(gè)中括號(hào)之間有空格,表明后一個(gè)要查找的標(biāo)簽在前一個(gè)屬性對(duì)應(yīng)標(biāo)簽的子孫標(biāo)簽范圍內(nèi)。
2.3、分析前去除程序代碼避免干擾
在解析HTML報(bào)文時(shí),絕大多數(shù)情況是需要分析有用的標(biāo)簽信息,但作為技術(shù)文章,大部分的博文中都有代碼,這些代碼可能會(huì)對(duì)分析進(jìn)行干擾。如本文中的代碼含有一些分析的HTML報(bào)文,如果獲取本文的完整HTML內(nèi)容,這些報(bào)文在非代碼部分也會(huì)出現(xiàn),此時(shí)要排除代碼的影響,可以將代碼先從分析內(nèi)容中去除再來(lái)分析。
目前大多數(shù)技術(shù)平臺(tái)的博文編輯器都支持對(duì)代碼的標(biāo)識(shí),象markdown等編輯器代碼的標(biāo)簽為code標(biāo)檢,如果有其他編輯器用不同標(biāo)簽的,只有確認(rèn)了標(biāo)簽名,都可以按下面介紹的類(lèi)似方式來(lái)處理。
處理步驟如下:
獲取報(bào)文;
構(gòu)建BeatifulSoap對(duì)象soup;
通過(guò)soup.code.extract()或soup.code.decompose()方式就從soup對(duì)象中去除了代碼部分,decompose方法與extract方法的區(qū)別就是decompose直接刪除對(duì)應(yīng)對(duì)象數(shù)據(jù)而extract再刪除時(shí)將刪除對(duì)象單獨(dú)返回。
三、小結(jié)
本文介紹了使用BeatifulSoap解析HTML報(bào)文的三個(gè)使用技巧,包括通過(guò)多屬性組合查找或定位標(biāo)簽、通過(guò)結(jié)合多個(gè)標(biāo)簽關(guān)系來(lái)定位標(biāo)簽以及去除html報(bào)文中的代碼標(biāo)簽來(lái)避免代碼對(duì)解析的影響。
寫(xiě)字不易,敬請(qǐng)支持:
如果閱讀本文于您有所獲,敬請(qǐng)點(diǎn)贊、評(píng)論、收藏,謝謝大家的支持!
————————————————
版權(quán)聲明:本文為轉(zhuǎn)載文章,如有侵權(quán),請(qǐng)聯(lián)系作者刪除。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。