python3解析庫pyquery

pyquery是一個相似jquery的python庫,它實現可以在xml文檔中進行jQuery查詢,pyquery使用lxml解析器進行快速在xml和html文檔上操做,它提供了和jQuery相似的語法來解析HTML文檔,支持CSS選擇器,使用很是方便css

一、pyquery安裝

pip方式安裝:html

$pip install pyquery

#它依賴cssselect和lxml包
pyquery==1.4.0
  - cssselect [required: >0.7.9, installed: 1.0.3] #CSS選擇器並將它轉換爲XPath表達式
  - lxml [required: >=2.1, installed: 4.2.2] #處理xml和html解析庫

驗證安裝:python

In [1]: import pyquery

In [2]: pyquery.text
Out[2]: <module 'pyquery.text' from '/root/pp1/.venv/lib/python3.6/site-packages/pyquery/text.py'>

二、pyquery對象初始化

pyquery首先須要傳入HTML文原本初始化一個pyquery對象,它的初始化方式有多種,如直接傳入字符串,傳入URL或者傳入文件名jquery

(1)字符串初始化git

from pyquery import PyQuery as pq

html='''
<div id="wenzhangziti" class="article 389862">
<p>人生是一條沒有盡頭的路,不要留戀逝去的夢,把命運掌握在本身手中,讓咱們來掌握本身的命運,別讓別人的干擾與誘惑,別讓功名與利祿,來打翻咱們這壇陳釀已久的命運之酒!</p> </div>
''' doc=pq(html) #初始化並建立pyquery對象 print(type(doc)) print(doc('p').text()) # <class 'pyquery.pyquery.PyQuery'>
人生是一條沒有盡頭的路,不要留戀逝去的夢,把命運掌握在本身手中,讓咱們來掌握本身的命運,別讓別人的干擾與誘惑,別讓功名與利祿,來打翻咱們這壇陳釀已久的命運之酒!

(2)URL初始化github

from pyquery import PyQuery as pq

doc=pq(url='https://www.cnblogs.com/zhangxinqi/p/9218395.html')
print(type(doc))
print(doc('title'))

#
<class 'pyquery.pyquery.PyQuery'>
<title>python3解析庫BeautifulSoup4 - Py.qi - 博客園</title>&#13;

PyQuery可以從url加載一個html文檔,之際上是默認狀況下調用python的urllib庫去請求響應,若是requests已安裝的話它將使用requests來請求響應,那咱們就可使用request的請求參數來構造請求了,實際請求以下:windows

from pyquery import PyQuery as pq
import requests

doc=pq(requests.get(url='https://www.cnblogs.com/zhangxinqi/p/9218395.html').text)
print(type(doc))
print(doc('title'))

#輸出同上同樣
<class 'pyquery.pyquery.PyQuery'>
<title>python3解析庫BeautifulSoup4 - Py.qi - 博客園</title>&#13;

(3)經過文件初始化api

經過本地的HTML文件來構造PyQuery對象網絡

from pyquery import PyQuery as pq

doc=pq(filename='demo.html',parser='html')
#doc=pq(open('demo.html','r',encoding='utf-8').read(),parser='html')  #注意:在讀取有中文的HTML文件時,請使用此方法,不然會報解碼錯誤
print(type(doc))
print(doc('p'))

三、CSS選擇器

在使用屬性選擇器中,使用屬性選擇特定的標籤,標籤和CSS標識必須引用爲字符串,它會過濾篩選符合條件的節點打印輸出,返回的是一個PyQuery類型對象app

from pyquery import PyQuery as pq
import requests
html='''
<div id="container">
    <ul class="list">
         <li class="item-0">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
doc=pq(html,parser='html')
print(doc('#container .list .item-0 a'))
print(doc('.list .item-1'))

#
<a href="link3.html"><span class="bold">third item</span></a><a href="link5.html">fifth item</a>
<li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>

四、查找節點

PyQuery使用查詢函數來查詢節點,同jQuery中的函數用法徹底相同

(1)查找子節點和子孫節點

使用find()方法獲取子孫節點,children()獲取子節點,使用以上的HTML代碼測試

from pyquery import PyQuery as pq
import requests

doc=pq(html,parser='html')
print('find:',doc.find('a'))
print('children:',doc('li').children('a'))

(2)獲取父節點和祖先節點

parent()方法獲取父節點,parents()獲取祖先節點

doc(.list).parent()
doc(.list).parents()

(3)獲取兄弟節點

siblings()方法用來獲取兄弟節點,能夠嵌套使用,傳入CSS選擇器便可繼續匹配

doc('.list .item-0 .active').siblings('.active')

五、遍歷

對於pyquery的選擇結果多是多個字節,也多是單個節點,類型都是PyQuery類型,它沒有返回列表等形式,對於當個節點咱們可指直接打印輸出或者直接轉換成字符串,而對於多個節點的結果,咱們須要遍從來獲取全部節點可使用items()方法,它會返回一個生成器,循環獲得的每一個節點類型依然是PyQuery類型,因此咱們能夠繼續方法來選擇節點或屬性,內容等

lis=doc('li').items()
for i in lis:
    print(i('a'))   #繼續獲取節點下的子節點

六、獲取信息

attr()方法用來獲取屬性,如返回的結果有多個時能夠調用items()方法來遍歷獲取

doc('.item-0.active a').attr('href')  #多屬性值中間不能有空格

text()方法用來獲取文本內容,它只返回內部的文本信息不包括HTML文本內容,若是想返回包括HTML的文本內容可使用html()方法,若是結果有多個,text()方法會方法全部節點的文本信息內容並將它們拼接用空格分開返回字符串內容,html()方法只會返回第一個節點的HTML文本,若是要獲取全部就須要使用items()方法來遍歷獲取了

from pyquery import PyQuery as pq
html='''
<div id="container">
    <ul class="list">
         <li class="item-0">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
doc=pq(html,parser='html')
print('text:',doc('li').text())  #獲取li節點下的全部文本信息
lis=doc('li').items()
for i in lis:
    print('html:',i.html()) #獲取全部li節點下的HTML文本

#
text: first item second item third item fourth item fifth item
html: first item
html: <a href="link2.html">second item</a>
html: <a href="link3.html"><span class="bold">third item</span></a>
html: <a href="link4.html">fourth item</a>
html: <a href="link5.html">fifth item</a>

七、節點操做

pyquery提供了一系列方法來對節點進行動態修改,如添加一個class,移除某個節點,修改某個屬性的值

addClass()增長Class,removeClass()刪除Class

attr()增長屬性和值,text()增長文本內容,html()增長HTML文本,remove()移除

from pyquery import PyQuery as pq
import requests
html='''
<div id="container">
    <ul class="list">
         <li id="1">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-3 active"><a href="link4.html">fourth item</a></li>
         <li class="item-4"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
doc=pq(html,parser='html')
print(doc('#1'))
print(doc('#1').add_class('myclass'))  #增長Class
print(doc('.item-1').remove_class('item-1'))  #刪除Class
print(doc('#1').attr('name','link'))  #添加屬性name=link
print(doc('#1').text('hello world'))   #添加文本
print(doc('#1').html('<span>changed item</span>')) #添加HTML文本
print(doc('.item-2.active a').remove('span'))  #刪除節點

#
<li id="1">first item</li>
         
<li id="1" class="myclass">first item</li>
         
<li class=""><a href="link2.html">second item</a></li>
         
<li id="1" class="myclass" name="link">first item</li>
         
<li id="1" class="myclass" name="link">hello world</li>
         
<li id="1" class="myclass" name="link"><span>changed item</span></li>
<a href="link3.html"/>

after()在節點後添加值

before()在節點以前插入值

append()將值添加到每一個節點

contents()返回文本節點內容

empty()刪除節點內容

remove_attr()刪除屬性

val()設置或獲取屬性值

另外還有不少節點操做方法,它們和jQuery的用法徹底一致,詳細請參考:http://pyquery.readthedocs.io/en/latest/api.html

八、僞類選擇器

CSS選擇器之因此強大,是由於它支持多種多樣的僞類選擇器,如:選擇第一個節點,最後一個節點,奇偶數節點等。

#!/usr/bin/env python
#coding:utf-8
from pyquery import PyQuery as pq

html='''
<div id="container">
    <ul class="list">
         <li id="1">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-3 active"><a href="link4.html">fourth item</a></li>
         <li class="item-4"><a href="link5.html">fifth item</a></li>
     </ul>
     <div><input type="text" value="username"/></div> 
</div>
'''
doc=pq(html,parser='html')
print('第一個li節點:',doc('li:first-child')) #第一個li節點
print('最後一個li節點:',doc('li:last_child')) #最後一個li節點
print('第二個li節點:',doc('li:nth-child(2)'))  #第二個li節點
print('第三個以後的全部li節點:',doc('li:gt(2)'))  #第三個以後的全部li節點
print('偶數的全部li節點:',doc('li:nth-child(2n)'))  #偶數的全部li節點
print('包含文本內容的節點:',doc('li:contains(second)')) #包含文本內容的節點
print('索引第一個節點:',doc('li:eq(0)'))
print('奇數節點:',doc('li:even'))
print('偶數節點:',doc('li:odd'))

#
第一個li節點: <li id="1">first item</li>
         
最後一個li節點: <li class="item-4"><a href="link5.html">fifth item</a></li>
     
第二個li節點: <li class="item-1"><a href="link2.html">second item</a></li>
         
第三個以後的全部li節點: <li class="item-3 active"><a href="link4.html">fourth item</a></li>
         <li class="item-4"><a href="link5.html">fifth item</a></li>
     
偶數的全部li節點: <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-3 active"><a href="link4.html">fourth item</a></li>
         
包含文本內容的節點: <li class="item-1"><a href="link2.html">second item</a></li>
         
索引第一個節點: <li id="1">first item</li>
         
奇數節點: <li id="1">first item</li>
         <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-4"><a href="link5.html">fifth item</a></li>
     
偶數節點: <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-3 active"><a href="link4.html">fourth item</a></li>

更多僞類參考:http://pyquery.readthedocs.io/en/latest/pseudo_classes.html

更多css選擇器參考:http://www.w3school.com.cn/cssref/css_selectors.asp

九、實例應用

 抓取http://www.mzitu.com網站美女圖片12萬張用時28分鐘,總大小9G,主要受網絡帶寬影響,下載數據有點慢

#!/usr/bin/env python
#coding:utf-8
import requests
from requests.exceptions import RequestException
from pyquery import PyQuery as pq
from PIL import Image
from PIL import ImageFile
from io import BytesIO
import time
from multiprocessing import Pool,freeze_support
ImageFile.LOAD_TRUNCATED_IMAGES = True

headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
,'Referer':'http://www.mzitu.com'
}

img_headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
,'Referer':'http://i.meizitu.net'
}
#保持會話請求
sesion=requests.Session()

#獲取首頁全部URL並返回列表
def get_url(url):
    list_url = []
    try:
        html=sesion.get(url,headers=headers).text
        doc=pq(html,parser='html')
        url_path=doc('#pins > li').children('a')
        for i in url_path.items():
            list_url.append(i.attr('href'))
    except RequestException as e:
        print('get_url_RequestException:',e)
    except Exception as e:
        print('get_url_Exception:',e)
    return list_url

#組合首頁中每一個地址的圖片分頁返回列表
def list_get_pages(list_url):
    list_url_fen=[]
    try:
        for i in list_url:
            doc_children = pq(sesion.get(i,headers=headers).text,parser='html')
            img_number = doc_children('body > div.main > div.content > div.pagenavi > a:nth-last-child(2) > span').text()
            number=int(img_number.strip())
            for j in range(1,number+1):
                list_url_fen.append(i+'/'+str(j))
    except ValueError as e:
        print('list_get_pages_ValueError:',e)
    except RequestException as e:
        print('list_get_pages_RequestException',e)
    except Exception as e:
        print('list_get_pages_Exception:',e)
    return list_url_fen

#獲取image地址並下載圖片
def get_image(url):
    im_path=''
    try:
        html=sesion.get(url, headers=headers).text
        doc=pq(html,parser='html')
        im_path=doc('.main-image a img').attr('src')
        image_names = ''.join(im_path.split('/')[-3:])
        image_path = 'D:\images\\' + image_names
        with open('img_url.txt','a') as f:
            f.write(im_path + '\n')
        r=requests.get(im_path,headers=img_headers)
        b=BytesIO(r.content)
        i=Image.open(b)
        i.save(image_path)
        b.close()
        i.close()
        #print('下載圖片:{}成功!'.format(image_names))
    except RequestException as e:
        print('RequestException:',e)
    except OSError as e:
        print('OSError:',e)
    except Exception as e:   #必須捕獲全部異常,運行中有一些連接地址不符合抓取規律,須要捕獲異常使程序正常運行
        print('Exception:',e)
    return im_path


#主調用函數
def main(item):
    url1='http://www.mzitu.com/page/{}'.format(item) #分頁地址
    print('開始下載地址:{}'.format(url1))
    獲取首頁連接地址
    html=get_url(url1)
    #獲取分頁連接地址
    list_fenurl = list_get_pages(html)
    #根據分頁連接地址獲取圖片並下載
    for i in list_fenurl:
        get_image(i)
    return len(list_fenurl)  #統計下載數

if __name__ == '__main__':
    freeze_support()  #windows下進程調用時必須添加
    pool=Pool()    #建立進程池
    start=time.time()
    count=pool.map(main,[i for i in range(1,185)])  #多進程運行翻頁主頁
    print(sum(count),count)  #獲取總的下載數
    end=time.time()
    data=time.strftime('%M:%S',time.localtime(end-start))  #獲取程序運行時間
    print('程序運行時間:{}分{}秒'.format(*data.split(':')))

#學習階段,代碼寫得通用性不好,之後改進!
#運行結果
#注意:若是是固定IP網須要使用代理

開始下載地址:http://www.mzitu.com/page/137
OSError: image file is truncated (22 bytes not processed)
開始下載地址:http://www.mzitu.com/page/138
125571 
程序運行時間:28分27秒

進程完成,退出碼 0

pyquery相關連接:

GitHub:https://github.com/gawel/pyquery

PyPI:https://pypi.python.org/pypi/pyquery

官方文檔:http://pyquery.readthedocs.io

相關文章
相關標籤/搜索