
目錄
- pyquery庫
- 基本用法
- CSS選擇器
- 查找節點
- 查找子節點
- 查找父節點
- 查找其兄弟節點
- 獲取節點資訊
- 修改節點
- 偽類選擇器
- 實戰:抓取ZOL熱門手機排行榜
pyquery庫
雖然Beautiful Soup庫的功能非常強大,但CSS選擇器功能有些弱,至少對于pyquery庫來說是非常弱的,
而且pyquery庫并不是Python的標準庫,所以在使用pyquery庫之前需要安裝,示例命令如下所示:
pip install pyquery
安裝完成之后,我們就可以愉快的玩耍pyquery庫了,需要注意的是,后面的所有決議代碼都是基于下面的HTML代碼(除了實戰):
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>我是一個測驗頁面</title>
</head>
<body>
<ul class="ul">
<li class="li"><a href="https://liyuanjinglyj.blog.csdn.net/">我的主頁</a></li>
<li class="li"><a href="https://www.csdn.net/">CSDN首頁</a></li>
<li class="li"><a href="https://www.csdn.net/nav/python" class="aaa">Python板塊<a>>1111</a></a>
</ul>
</body>
</html>
基本用法
在pyquery庫中,有一個PyQuery類,我們獲取的HTML或者說XML代碼,需要通過其建構式創建其物件實體,
示例代碼(獲取網頁標題以及所有<a>標簽的href屬性值):
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html.strip())
print(doc('title').text())
for a in doc('a'):
print(a.get('href'), a.text)
運行之后,效果如下:

pyquery庫通過get獲取屬性的值,用text()方法獲取標簽的文本資訊,不過,我們這里直接加載的檔案,其實pq()可以直接傳入網址,它會自己獲取網址代碼,感興趣的可以試試,
CSS選擇器
pyquery庫這些基本的屬性以及標簽獲取方式是其最不顯眼的優勢,其真正的優勢還是如前文所說的CSS選擇器,
下面,我們舉例層級訪問,以及直接訪問的示例:
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html.strip())
print("直接獲取class等于aaa的標簽")
print(doc('.aaa'))
print("層級獲取class等于aaa的標簽")
print(doc('html body .ul .li .aaa'))
運行之后,就是2個“<a href=“https://www.csdn.net/nav/python” class=“aaa”>Python板塊”標簽內容,這里就不展示了,
查找節點
其實學完上面這些,要爬取一個網站已經可以手到擒來了,不過,我們還是將pyquery庫全部介紹一遍,這里開始講解其節點的查找,
查找子節點
在實際的爬蟲專案中,我們需要獲取某個節點的子節點,那么如何操作呢?
比如,這里我們獲取ul標簽的所有<a>子節點,示例如下:
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html)
print("find")
ul = doc('.ul1')
a_list = ul.find('a')
for a in a_list:
a = str(etree.tostring(a, pretty_print=True, encoding='UTF-8'), 'UTF-8')
if a.strip() != '':
print(a)
print("children")
ul = doc('.ul1')
a_list = ul.children('a')
for a in a_list:
a = a.html()
if a.strip() != '':
print(a)
運行之后,效果如下:

可以看到,這里的find()能查找所有<a>子節點,但是children()卻什么都獲取不到,這是因為children獲取的是直接子節點,而find()獲取的是子孫節點,
查找父節點
在pyquery庫中,通過parent()方法可以直接查找其父節點,而通過parents()方法可以查找所有的父節點,
這里,我們來測驗查找最后一個<a>標簽的所有父節點與父節點,示例如下:
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html)
a = doc('.aaa')
print("獲取其父節點")
print(a.parent())
print("獲取其所有父節點")
for parent in a.parents():
print(parent.tag)
print("-----")
運行之后,效果如下:

查找其兄弟節點
在pyquery庫中,通過siblings()方法可以查找某個節點的兄弟節點,它也可以通過CSS選擇器引數來查找,
我們將上面的HTML-li代碼更新一下:
<li class="li1"><a href="https://liyuanjinglyj.blog.csdn.net/">我的主頁</a></li>
<li class="li"><a href="https://www.csdn.net/">CSDN首頁</a></li>
<li class="li"><a href="https://www.csdn.net/nav/python" class="aaa">
Python板塊
<a>1111</a>
</a>
示例如下:
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html)
li1 = doc(".li1")
print(li1.siblings())
print('針對屬性查找兄弟節點')
print(li1.siblings('.li'))
運行之后,效果如下:

獲取節點資訊
節點資訊包括節點的名稱,屬性,文本,整個節點的HTML代碼以及其節點內部的HTML代碼,下面,博主一一舉例進行獲取:
from pyquery import PyQuery as pq
from lxml import etree
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html)
a = doc('.li1')
print('節點名稱:', a[0].tag)
print("節點屬性:", a[0].get('class'))
print("節點屬性:", a.attr('class'))
print("節點文本:", a.text())
print("整個節點HTML代碼:", str(etree.tostring(a[0], pretty_print=True, encoding='UTF-8'), 'UTF-8'))
print("節點內部HTML代碼:", a.html())
運行之后,效果如下:

需要注意的是,如果需要獲取整個節點的HTML代碼,需要借助lxml庫進行完成,如果獲取的節點的父節點只有它一個子節點,倒是可以通過獲取父節點在獲取內部的HTML代碼獲取整個節點的HTML代碼,但一般來說,一個父節點應該有很多子節點,這么做行不通,目前也沒什么好的辦法解決,只能借助lxml庫,
修改節點
博主記得大學的時候,那時候學校網址很卡,畢業申請網頁總是打不開,就算打開了根本就無法加載全部的網頁資訊,提交更是卡著不動,(稍微人多就崩了)
這個時候,博主取巧直接將學校提交網址的源代碼下載了下來,然后將提交的資訊全部寫在對應的HTML標簽中,然后直接提交的,
不過,當時博主是手動操作的,如果需要代碼操作,可以借助pyquery庫進行,比如我們可以給一個標簽添加文本,屬性等,對應代碼如下:
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html)
# 添加一個標簽的class屬性值
li = doc('.li1')
li.add_class('li')
print(doc)
# 洗掉一個標簽的class屬性值
li.remove_class('li')
print(doc)
# 修改一個標簽的class屬性值
li.attr('class', 'li123')
print(doc)
# 修改一個標簽的文本
a = doc('.aaa')
a.text('我是修改的值')
print(doc)
# 修改一個標簽的HTML代碼
a = doc('.aaa')
a.html('<a href="www.csdn.net">華為</a>')
print(doc)
# 洗掉一個節點
li.remove()
print(doc)
運行結果這里就不放置了,因為代碼每次列印產生了大量資料,大量的圖片在博文堆積,閱讀體驗不好,還請見諒,感興趣的自己復制運行查看,
不過,需要特別注意一個點,text()方法是替換文本,如果替換的是HTML代碼需要使用html()方法,如果text()替換html代碼,會導致<變成<,
偽類選擇器
pyquery庫之所以CSS選擇器非常強大,是因為其支持多種多樣的偽類選擇器,例如,選擇第1個節點,最后一個節點,索引為奇數的節點,索引為偶數的節點等,
這些都可以通過pyquery庫的CSS選擇器直接操作,下面,我們來舉例說明,示例代碼如下所示:
from pyquery import PyQuery as pq
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
doc = pq(html)
# 獲取第一個li節點
li = doc('li:first-child')
print(li.html())
# 獲取最后一個li節點
li = doc('li:last-child')
print(li.html())
# 獲取第2個li節點
li = doc('li:nth-child(2)')
print(li.html())
# 獲取索引小于3的li節點(從0開始,0,1節點)
li = doc('li:lt(2)')
print(li)
# 獲取索引大于1的li節點(從0開始,只有2節點大于0,也就是第3個li)
li = doc('li:gt(1)')
print(li)
# 選擇奇數位的li節點
li = doc('li:nth-child(2n+1)')
print(li)
# 選擇偶數位的li節點
li = doc('li:nth-child(2n)')
print(li)
# 選取文本內容包含CSND的所有li節點
li = doc('li:contains(CSDN)')
print(li)
# 選取文本內容包含CSND的所有節點
li = doc(':contains(CSDN)')
print(len(li))
運行結果太多,這里也不展示運行結果,具體的結果與代碼注釋一模一樣,pyquery庫到這里就已經全部講解完成,下面,將通過pyquery庫進行實戰測驗,
實戰:抓取ZOL熱門手機排行榜
首先,我們來查看其網頁的源代碼,看看這個榜單的內容在哪個標簽中,如下圖所示:

可以看到,我們的手機熱榜在class等于section的div標簽中,同時class等于rank-list__item clearfix才是每行的榜單內容,所以,我們可以直接獲取class等于rank-list__item clearfix的所有div然后遍歷,
from pyquery import PyQuery as pq
from lxml import etree
import requests
url = "https://top.zol.com.cn/compositor/57/cell_phone.html"
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
result = requests.get(url=url, headers=headers)
doc = pq(result.text)
result = doc('.section')
divs = result('.rank-list__item')
接著,我們需要獲取每個div榜單里面的資訊,比如排名,手機名稱,價位等等,我們先來看看這些資料到底在哪些標簽中,

如上圖所示,class=rank__number的div是其排名,class=rank__name的div下的a標簽是手機的名稱以及鏈接,class=rank__price的div是其價格,
知道了這些,我們可以直接上代碼了,不過需要注意的是,第一名的排行顯示的是一個皇冠,并沒有排行的數字,所以獲取不到排行的數字,
當然,本身串列就是順序的,你可以自己遍歷數字從1開始排即可,根本不需要獲取class=rank__number的內容,不過這里我們還是獲取一下,代碼如下:
from pyquery import PyQuery as pq
import requests
url = "https://top.zol.com.cn/compositor/57/cell_phone.html"
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
result = requests.get(url=url, headers=headers)
doc = pq(result.text)
result = doc('.section')
divs = result('.rank-list__item')
for div in divs.items():
if '' == div('.rank__number').text().strip():
print("手機排名:", 1)
else:
print("手機排名:", div('.rank__number').text())
print("手機名稱:", div('.rank__name a').text())
print("手機價格:", div('.rank__price').text())
print("手機詳情鏈接:", div('.rank__name a').attr('href'))
print()
運行之后,手機的熱門榜單就完全獲取到了,這樣購買手機的參考也就有了,效果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/290443.html
標籤:python
