一起學爬蟲——PyQuery常用用法總結
什麼是PyQuery
PyQuery是一個類似於jQuery的解析網頁工具,使用lxml操作xml和html文件,它的語法和jQuery很像。和XPATH,Beautiful Soup比起來,PyQuery更加靈活,提供增加節點的class資訊,移除某個節點,提取文字資訊等功能。
初始化PyQuery物件
html文件的所有操作都需要PyQuery物件來完成,初始化PyQuery物件主要有三種方式,分別是通過網址、字串和檔名建立。
方式一:通過網址初始化PyQyery物件
先看一段程式碼:
from pyquery import PyQuery as pq s = '<html><title>PyQuery用法總結<title></html>' doc = pq(s) print(doc('title'))
執行結果:
<title>PyQuery用法總結</title>
首先要import PyQuery類,然後將字串傳遞給PyQuery類,這樣就生成了一個PyQuery物件,通過該物件就可以訪問字串中的title節點。
PyQuery還會將殘缺的html文件補全。看下面的程式碼:
from pyquery import PyQuery as pq s = '<html><title>PyQuery用法總結</title>' doc = pq(s) print(doc('html'))
執行的結果:
<html><head><title>PyQuery用法總結</title></head></html>
可以我們的字串的html節點是沒有閉合的,並且缺少head節點。初始化PyQuery物件之後,會把html文件補全,並且自動加上head節點。
方式二:URL網址初始化PyQyery物件
將要解析的URL網址當做引數傳遞給PyQuery類:
from pyquery import PyQuery as pq url = 'http://www.bigdata17.com' doc = pq(url=url,encoding='utf-8') print(doc('title'))
執行結果:
<title>Home - Summer哥的自留地</title>
方式三:通過檔案初始化PyQyery物件
這個方式也比較常用,很多時候我們會將網站爬取下來然後儲存在本地磁碟:
from pyquery import PyQuery as pq doc = pq(filename='test_pyquery.html',encoding='utf-8') print(doc('title'))
訪問節點屬性:
使用attr()方法訪問節點的屬性:
from pyquery import PyQuery as pq li = pq('<li id="test1" class="test1"></li><li id="test2" class="test2"></li>')('li') print(li.attr("id"))
執行結果:
test1
上面的程式碼中有兩個id不同的li節點,但是attr()方法只取第一個li節點的id屬性值,而不取第二個,我們把上面的程式碼修改下,把第一個li節點的id屬性去掉,attr方法是否只取第一個複合條件節點的屬性值:
from pyquery import PyQuery as pq li = pq('<li class="test1"></li><li id="test2" class="test2"></li>')('li') print(li.attr("id"))
執行結果:
None
第一個li節點沒有id屬性,因此返回結果為None,所以可見,attr()方法返回的是第一個節點的屬性值。
那要取多個li節點的屬性值,要怎麼做呢?這就要結合items()方法來實現。items()方法是返回的節點的生成器generator object PyQuery.items
:
from pyquery import PyQuery as pq li = pq('<li id="test1" class="test1"></li><li id="test2" class="test2"></li>')('li') print(li.items()) for item in li.items(): print(item.attr("id"))
執行結果:
<generator object PyQuery.items at 0x0000027F26082728> test1 test2
動態新增節點屬性
PyQuery有很多方法動態新增節點的屬性,我們挑選幾個比較常用的方法介紹個大夥。
addClass(),動態新增節點class屬性:
from pyquery import PyQuery as pq html = '<li id="test1" class="test1"></li>' li = pq(html)('li') li.addClass("addClass") print(li)
執行結果:
<li id="test1" class="test1 addClass"/>
可見li節點的calss屬性值有test1變為test1 addclass。
addClass()方法只能動態新增節點class屬性的值,能不能動態新增其他屬性呢?答案是當然可以,attr()方法就可以實現:
from pyquery import PyQuery as pq html = '<li id="test1" class="test1"></li>' li = pq(html)('li') li.attr("name","li name") print(li) li.attr("type","li") print(li) print(li.attr("type"))
執行結果:
<li id="test1" class="test1" name="li name"/> <li id="test1" class="test1" name="li name" type="li"/> li
上面的程式碼一共執行了3次attr()方法,執行第一次attr()方法時,有兩個引數,分別是name和li name。這是給li節點新增name屬性及屬性值。執行第二次attr()方法也有兩個引數,分別是type和li,這是給li幾點新增type屬性及type屬性值。執行第三次方法attr()方法只有一個type引數,根據前面介紹的attr()方法的用法可知,是獲取li節點type屬性的值。
小結:attr()方法只有一個引數時,是獲取節點的屬性值,有兩個引數時,是給節點新增屬性及屬性值,第一個引數時屬性,第二個引數時屬性值。
removeClass(),動態移除節點的class屬性:
from pyquery import PyQuery as pq html = '<li id="test1" class="test1"></li>' li = pq(html)('li') li.removeClass("test1") print(li)
執行結果:
<li id="test1" class=""/>
將class節點的屬性值有test1變為“”。
動態新增/修改文字值
PyQuery支援動態給節點新增文字值:
from pyquery import PyQuery as pq html = '<li id="test1" class="test1"></li>' li = pq(html)('li') li.html("use html() dynamic add text") print(li) li.text("use text() dynamic add text") print(li)
執行結果:
<li id="test1" class="test1">use html() dynamic add text</li> <li id="test1" class="test1">use text() dynamic add text</li>
可見使用html()和text()方法都可以動態的給節點新增或修改節點的文字值。
獲取節點文字值
PyQuery提供text()和html()方法獲取節點的文字屬性值:
from pyquery import PyQuery as pq html = '<li id = "test_id">li text value</li>' li = pq(html)('li') print(li.text()) print(li.html())
執行結果:
li text value li text value
小結:html()和text()如果沒引數,則是獲取屬性的文字值,如果有引數,則是改變或者新增節點的屬性值。
移除節點:
remove()方法可以動態移除節點:
from pyquery import PyQuery as pq html = ''' <ul> hello I am ul tag <li>hello I am li tag</li> </ul> ''' ul = pq(html)('ul') print(ul.text()) print('執行remove()移除節點') ul.find('li').remove() print(ul.text())
執行結果:
hello I am ul tag hello I am li tag 執行remove()移除節點 hello I am ul tag
上述程式碼的ul節點中有個li節點,執行ul.text()方法會返回包括li節點的文字資訊,如果我們不想返回li節點的文字資訊,僅僅只需要ul節點的文字資訊“hell I am ul tag”,要怎麼做呢?這時候remove()方法就派上用場了,它刪除掉ul節點內的li節點。
查詢節點
PyQuery支援使用css的.和#來查詢節點:
from pyquery import PyQuery as pq html = ''' <div class="div_tag"> <ul id = "ul_tag"> hello I am ul tag <li>hello I am li tag</li> <li>hello I am li tag too</li> </ul> </div> ''' doc = pq(html) print(doc('.div_tag #ul_tag li'))
執行結果:
<li>hello I am li tag</li> <li>hello I am li tag too</li>
上述程式碼是通過.div_tag獲取class為div_tag的節點,然後通過#ul_tag獲取id為ul_tag的節點,最後返回所有的li節點。
find()方法查詢節點:
html = ''' <div class="div_tag"> <ul id = "ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</li> <li>hello I am li tag too</li> </ul> </div> ''' doc = pq(html) print(doc('.div_tag #ul_tag').find("li"))
執行結果:
<li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li>
可見find("li")是把所有li節點及子節點都查找出來。
還有一個children()方法,是獲取當前節點的所有子節點。該方法可以傳入css選擇器:children('.ul_tag')。
html = ''' <div class="div_tag"> <ul id = "ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</li> <li>hello I am li tag too</li> </ul> </div> ''' doc = pq(html) print(doc('.div_tag #ul_tag').find("li"))
執行結果:
<li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li>
使用parent()方法獲取當前節點的父親節點:
html = ''' <div class="div_tag"> <ul id = "ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</li> <li>hello I am li tag too</li> </ul> </div> ''' doc = pq(html) print(doc('.div_tag #ul_tag li').parent())
執行結果:
<ul id="ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li> </ul>
上述程式碼通過.div_tag #ul_tag li css選擇器定位到li節點,然後呼叫parent()方法獲取li節點的父節點ul。
parents()返回當前節點的所有祖宗節點:
html = ''' <div class="div_tag"> <ul id = "ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</li> <li>hello I am li tag too</li> </ul> </div> ''' doc = pq(html) print(doc('.div_tag #ul_tag li').parents())
執行結果:
<html><body><div class="div_tag"> <ul id="ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li> </ul> </div> </body></html><body><div class="div_tag"> <ul id="ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li> </ul> </div> </body><div class="div_tag"> <ul id="ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li> </ul> </div> <ul id="ul_tag"> hello I am ul tag <li>hello I am li tag<a>www.bigdata17.com</a></li> <li>hello I am li tag too</li> </ul>
上面程式碼返回li節點的所有祖宗節點:html,body,div,ul。
siblings()方法返回當前節點的兄弟節點:
html = ''' <div class="div_tag"> <ul id = "ul_tag"> hello I am ul tag <li class="li_class1">hello I am li tag<a>www.bigdata17.com</li> <li class="li_class2">hello I am li tag too</li> <li class="li_class3">hello I am the third li tag</li> </ul> </div> ''' doc = pq(html) print(doc('.div_tag #ul_tag .li_class1').siblings())
執行結果:
<li class="li_class2">hello I am li tag too</li> <li class="li_class3">hello I am the third li tag</li>
使用.div_tag #ul_tag .li_class1 CSS節點選擇器獲取到class為liclassq1的li節點,就是第一個li節點,然後呼叫siblings()方法獲取到子節點,分別是
第二和第三個li節點。
sibligs()還支援傳入css選擇器篩選符合條件的li節點:
print(doc('.div_tag #ul_tag .li_class1').siblings('.li_class3'))
執行結果:
<li class="li_class3">hello I am the third li tag</li>
總結:本文講述瞭如何使用PyQuery獲取網頁節點,節點的文字資訊,改變節點屬性,刪除節點屬性,增加節點屬性等知識點。