爬蟲解析利器PyQuery詳解及使用實踐

作者:葉庭云
整理:Lemon
爬蟲解析利器
PyQuery詳解及使用實踐
之前跟大家分享了 selenium、Scrapy、Pyppeteer 等工具的使用。
今天來分享另一個好用的爬蟲解析工具 PyQuery。
一、簡介
每個網(wǎng)頁,都有一定的特殊結(jié)構(gòu)和層級關(guān)系,而且很多節(jié)點都有 id 或 class 作為區(qū)分,我們可以借助它們的結(jié)構(gòu)和屬性來提取信息。
PyQuery 是一個強大的 HTML 解析庫,利用它,我們可以直接解析 DOM 節(jié)點的結(jié)構(gòu),并通過 DOM 節(jié)點的一些屬性快速進行內(nèi)容提取。
pyquery 是 Python 的第三方庫,可以用 pip3 來安裝,安裝命令如下:
pip3?install?pyquery?-i?http://pypi.douban.com/simple?--trusted-host?pypi.douban.com
在解析 HTML 文本的時候,首先需要將其初始化為一個 pyquery 對象。它的初始化方式有多種,比如直接傳入字符串、傳入 URL、傳入文件名等等。
字符串初始化
可以直接把 HTML 的內(nèi)容當(dāng)作參數(shù)來初始化 pyquery 對象,下面用一個實例來感受一下:
from?pyquery?import?PyQuery?as?pq
html?=?'''
'''
doc?=?pq(html)
print(doc('li'))
運行結(jié)果如下:
class="item-0">first?itemli>
<li?class="item-1"><a?href="link2.html">second?itema>li>
<li><img?src="http://pic.netbian.com/uploads/allimg/210107/215736-1610027856f6ef.jpg"/>
190902/152344-1567409024af8c.jpg"/> ??
首先引入 pyquery 這個對象,取別名為 pq,然后定義了一個長 HTML 字符串,并將其當(dāng)作參數(shù)傳遞給 pyquery 類,這樣就成功完成了初始化。
接下來,將初始化的對象傳入 CSS 選擇器。在這個實例中,我們傳入 li 節(jié)點,這樣就可以選擇所有的 li 節(jié)點。
URL 初始化
#?-*-?coding:?UTF-8?-*-
from?pyquery?import?PyQuery?as?pq
url?=?'https://yetingyun.blog.csdn.net/'
doc?=?pq(url)
print(doc('title'))
運行結(jié)果如下:
葉庭云的博客_CSDN博客-python?爬蟲,python數(shù)據(jù)可視化,計算機視覺圖像處理領(lǐng)域博主
pyquery 對象會首先請求這個 URL,然后用得到的 HTML 內(nèi)容完成初始化。這就相當(dāng)于將網(wǎng)頁的源代碼以字符串的形式傳遞給 pyquery 類來初始化。
文件初始化
除了傳遞一個 URL,我們還可以傳遞本地的文件名,參數(shù)指定為 filename 即可:
from?pyquery?import?PyQuery?as?pq
doc?=?pq(filename='時間輪播圖.html')
print(doc('title'))
運行結(jié)果如下:
Awesome-pyecharts
當(dāng)然,這里需要有一個本地 HTML 文件,其內(nèi)容是待解析的 HTML 字符串。這樣它會先讀取本地的文件內(nèi)容,然后將文件內(nèi)容以字符串的形式傳遞給 pyquery 類來初始化。
以上 3 種方式均可初始化,當(dāng)然最常用的初始化方式還是以字符串形式傳遞。
二、pyquery基本使用
基本 CSS 選擇器
用一個實例來感受一下 pyquery 的 css 選擇器的用法:
from?pyquery?import?PyQuery?as?pq
html?=?'''
????
?????????- first?item
?????????- second?item
?????????- third?item
?????????- fourth?item
?????????- fifth?item
?????
?
'''
doc?=?pq(html)
print(doc('#container?.list?li'))
print(type(doc('#container?.list?li')))
運行結(jié)果如下:
class="item-0">first?itemli>
<li?class="item-1"><a?href="link2.html">second?itema>li>
<li?class="item-0?active"><a?href="link3.html"><span?class="bold">third?itemspan>a>li>
<li?class="item-1?active"><a?href="link4.html">fourth?itema>li>
<li?class="item-0"><a?href="link5.html">fifth?itema>li>
<class?'pyquery.pyquery.PyQuery'>
初始化 pyquery 對象之后,傳入 css 選擇器 #container .list li,它的意思是先選取 id 為 container 的節(jié)點,然后再選取其內(nèi)部 class 為 list 的所有 li 節(jié)點,最后打印輸出。
可以看到,我們成功獲取到了符合條件的節(jié)點。我們將它的類型打印輸出后發(fā)現(xiàn),它的類型依然是 pyquery 類型。
下面,我們直接遍歷這些節(jié)點,然后調(diào)用 text 方法,就可以獲取節(jié)點的文本內(nèi)容
from?pyquery?import?PyQuery?as?pq
html?=?'''
????
?????????- first?item
?????????- second?item
?????????- third?item
?????????- fourth?item
?????????- fifth?item
?????
?
'''
doc?=?pq(html)
for?item?in?doc('#container?.list?li').items():
????print(item.text())
運行結(jié)果如下:
first?item
second?item
third?item
fourth?item
fifth?item
而是直接通過選擇器和 text 方法,就得到了我們想要提取的文本信息,是不是挺方便的?
獲取信息
提取到節(jié)點之后,我們的最終目的當(dāng)然是提取節(jié)點所包含的信息了。比較重要的信息有兩類,一是獲取屬性,二是獲取文本,下面分別進行說明。
獲取屬性:提取到某個 pyquery 類型的節(jié)點后,可以調(diào)用 attr 方法來獲取屬性:
from?pyquery?import?PyQuery?as?pq
html?=?'''
????
????????
?????????????- first?item
?????????????- second?item
?????????????- third?item
?????????????- fourth?item
?????????????- fifth?item
?????????
?????
?
'''
doc?=?pq(html)
a?=?doc('.item-0.active?a')
print(a,?type(a))
print(a.attr('href'))
print(a.attr.href)
運行結(jié)果如下:
"link3.html">class="bold">third?itemspan>a>?<class?'pyquery.pyquery.PyQuery'>
link3.html
link3.html
在這個例子中我們首先選中 class 為 item-0 和 active 的 li 節(jié)點內(nèi)的 a 節(jié)點,它的類型是 pyquery 類型。然后調(diào)用 attr 方法。在這個方法中傳入屬性的名稱,就可以得到屬性值了。此外,也可以通過調(diào)用 attr 屬性來獲取屬性值。
遍歷獲取所有的 a 節(jié)點的屬性:
from?pyquery?import?PyQuery?as?pq
html?=?'''
????
????????
?????????????- first?item
?????????????- second?item
?????????????- third?item
?????????????- fourth?item
?????????????- fifth?item
?????????
?????
?
'''
doc?=?pq(html)
nodes?=?doc('a')
for?item?in?nodes.items():
????print(item.attr('href'))
運行結(jié)果如下:
link2.html
link3.html
link4.html
link5.html
因此,在進行屬性獲取時,先要觀察返回節(jié)點是一個還是多個,如果是多個,則需要遍歷才能依次獲取每個節(jié)點的屬性。
獲取文本
獲取節(jié)點之后的另一個主要操作就是獲取其內(nèi)部文本了,此時可以調(diào)用 text 方法來實現(xiàn):
from?pyquery?import?PyQuery?as?pq
html?=?'''
????
????????
?????????????- first?item
?????????????- second?item
?????????????- third?item
?????????????- fourth?item
?????????????- fifth?item
?????????
?????
?
'''
doc?=?pq(html)
nodes?=?doc('li')
for?item?in?nodes.items():
????print(item.text())
運行結(jié)果如下:
first?item
second?item
third?item
fourth?item
fifth?item
三、爬取B站視頻熱搜榜單數(shù)據(jù)
下面用一個爬取B站視頻熱搜榜單數(shù)據(jù)的實例來熟悉 PyQuery 的使用
URL:https://www.bilibili.com/ranking?spm_id_from=333.851.b_7072696d61727950616765546162.3

1. 發(fā)送請求
import?requests
#?偽裝請求頭
headers?=?{
????"Origin":?"https://www.bilibili.com",
????"User-Agent":"Mozilla/5.0?(Windows?NT?6.1;?WOW64)?AppleWebKit/537.1?(KHTML,?like?Gecko)?Chrome/22.0.1207.1?Safari/537.1"
}
#?目標(biāo)URL
url?=?'https://www.bilibili.com/v/popular/rank/all'
#?request請求獲取的文本傳入PyQuery初始化
resp?=?requests.get(url,?headers=headers)
print(resp.status_code)
print(resp.text)
在上面的代碼中,我們完成了以下幾件事:
導(dǎo)入 requests 庫 偽裝請求頭 使用 get 方法構(gòu)造請求 打印查看請求的狀態(tài)碼和網(wǎng)頁源代碼文本
2. 解析提取數(shù)據(jù)和保存
from?pyquery?import?PyQuery?as?pq
import?openpyxl
wb?=?openpyxl.Workbook()????#?初始化工作簿對象
sheet?=?wb.active???????????#?獲取活動的工作表
#?添加列名
sheet.append(['rank',?'title',?'link',?'bicon_play',?'bicon_view',?'creator',?'score'])
doc?=?pq(resp)
#?獲取class=rank-list?下所有l(wèi)i節(jié)點內(nèi)容
#?遍歷li節(jié)點
con1?=?doc('.rank-list?li')
for?item?in?con1.items():
????rank?=?item('.num').text()???#?排名
????title?=?item('.content?.info?a:first-child').text()?????????#?視頻標(biāo)題
????link?=?'https:'?+?item('.content?.info?a').attr('href')?????#?視頻鏈接
????#?creator?=?item('.content?.info?.detail?a?span').text()????#?UP主
????bicon_play,?bicon_view,?creator?=?item('.content?.info?.detail?span').text().split('?')
????#?print(bicon_play,?bicon_view,?creator)?????
????score?=?item('.content?.info?.pts?div').text()
????sheet.append([rank,?title,?link,?bicon_play,?bicon_view,?creator,?score])
wb.save(filename='data.xlsx')
3. 完整代碼
#?-*-?coding:?UTF-8?-*-
from?pyquery?import?PyQuery?as?pq
import?requests
import?logging
import?openpyxl
wb?=?openpyxl.Workbook()????#?初始化工作簿對象
sheet?=?wb.active???????????#?獲取活動的工作表
#?添加列名
sheet.append(['rank',?'title',?'link',?'bicon_play',?'bicon_view',?'creator',?'score'])
#?日志輸出配置
logging.basicConfig(level=logging.INFO,?format='%(asctime)s?-?%(levelname)s:?%(message)s')
#?偽裝請求頭
headers?=?{
????"Origin":?"https://www.bilibili.com",
????"User-Agent":"Mozilla/5.0?(Windows?NT?6.1;?WOW64)?AppleWebKit/537.1?(KHTML,?like?Gecko)?Chrome/22.0.1207.1?Safari/537.1"
}
#?目標(biāo)URL
url?=?'https://www.bilibili.com/v/popular/rank/all'
#?request請求獲取的文本傳入PyQuery初始化
resp?=?requests.get(url,?headers=headers).text
doc?=?pq(resp)
#?獲取class=rank-list?下所有l(wèi)i節(jié)點內(nèi)容
#?遍歷li節(jié)點
con1?=?doc('.rank-list?li')
for?item?in?con1.items():
????rank?=?item('.num').text()???#?排名
????title?=?item('.content?.info?a:first-child').text()?????????#?視頻標(biāo)題
????link?=?'https:'?+?item('.content?.info?a').attr('href')?????#?視頻鏈接
????#?creator?=?item('.content?.info?.detail?a?span').text()????????#?UP主
????bicon_play,?bicon_view,?creator?=?item('.content?.info?.detail?span').text().split('?')
????#?print(bicon_play,?bicon_view,?creator)?????#?排名
????score?=?item('.content?.info?.pts?div').text()
????sheet.append([rank,?title,?link,?bicon_play,?bicon_view,?creator,?score])
????logging.info([rank,?title,?link,?bicon_play,?bicon_view,?creator,?score])
wb.save(filename='data.xlsx')
運行效果如下:


作者:葉庭云
CSDN:https://yetingyun.blog.csdn.net/
推薦閱讀 誤執(zhí)行了rm -fr /*之后,除了跑路還能怎么辦?! 程序員必備58個網(wǎng)站匯總 大幅提高生產(chǎn)力:你需要了解的十大Jupyter Lab插件
----------? END? ----------
