python3解析库pyquery的深入讲解


Posted in Python onJune 26, 2018

前言

pyquery是一个类似jquery的python库,它实现能够在xml文档中进行jQuery查询,pyquery使用lxml解析器进行快速在xml和html文档上操作,它提供了和jQuery类似的语法来解析HTML文档,支持CSS选择器,使用非常方便

1、pyquery安装

pip方式安装:

$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解析库

验证安装:

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'>

2、pyquery对象初始化

pyquery首先需要传入HTML文本来初始化一个pyquery对象,它的初始化方式有多种,如直接传入字符串,传入URL或者传入文件名

(1)字符串初始化

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初始化

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>

PyQuery能够从url加载一个html文档,之际上是默认情况下调用python的urllib库去请求响应,如果requests已安装的话它将使用requests来请求响应,那我们就可以使用request的请求参数来构造请求了,实际请求如下:

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>

(3)通过文件初始化

通过本地的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'))

3、CSS选择器

在使用属性选择器中,使用属性选择特定的标签,标签和CSS标识必须引用为字符串,它会过滤筛选符合条件的节点打印输出,返回的是一个PyQuery类型对象

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" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >second item</a></li>
  <li class="item-0 active"><a href="link3.html" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ><span class="bold">third item</span></a></li>
  <li class="item-1 active"><a href="link4.html" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >fourth item</a></li>
  <li class="item-0"><a href="link5.html" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >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" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ><span class="bold">third item</span></a><a href="link5.html" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >fifth item</a>
<li class="item-1"><a href="link2.html" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >second item</a></li>
  <li class="item-1 active"><a href="link4.html" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >fourth item</a></li>

4、查找节点

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')

5、遍历

对于pyquery的选择结果可能是多个字节,也可能是单个节点,类型都是PyQuery类型,它没有返回列表等形式,对于当个节点我们可指直接打印输出或者直接转换成字符串,而对于多个节点的结果,我们需要遍历来获取所有节点可以使用items()方法,它会返回一个生成器,循环得到的每个节点类型依然是PyQuery类型,所以我们可以继续方法来选择节点或属性,内容等

lis=doc('li').items()
for i in lis:
 print(i('a')) #继续获取节点下的子节点

6、获取信息

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>

7、节点操作

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

8、伪类选择器

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

9、实例应用

 抓取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-child(7) > 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(':')))

#学习阶段,代码写得通用性很差,以后改进!
#运行结果
#会有几个报错都忽略了是获取文件名时的分割问题和在图片很少的情况下导致获取不到单分页图片的数目,先忽略以后有时间再改正
#Exception: 'NoneType' object has no attribute 'split'
#list_get_pages_ValueError: invalid literal for int() with base 10: '下一页»'

开始下载地址:http://www.mzitu.com/page/137
OSError: image file is truncated (22 bytes not processed)
开始下载地址:http://www.mzitu.com/page/138

程序运行时间:28分27秒

进程完成,退出码 0

pyquery相关链接:

GitHub:https://github.com/gawel/pyquery (本地下载)

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

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python聊天室实例程序分享
Jan 05 Python
JPype实现在python中调用JAVA的实例
Jul 19 Python
python实现k-means聚类算法
Feb 23 Python
详谈Python3 操作系统与路径 模块(os / os.path / pathlib)
Apr 26 Python
python实现黑客字幕雨效果
Jun 21 Python
Python玩转Excel的读写改实例
Feb 22 Python
pandas的排序和排名的具体使用
Jul 31 Python
详解基于python的多张不同宽高图片拼接成大图
Sep 26 Python
python dumps和loads区别详解
Feb 04 Python
python 工具 字符串转numpy浮点数组的实现
Mar 14 Python
python实现读取类别频数数据画水平条形图案例
Apr 24 Python
python装饰器实现对异常代码出现进行自动监控的实现方法
Sep 15 Python
Python将list中的string批量转化成int/float的方法
Jun 26 #Python
python中从str中提取元素到list以及将list转换为str的方法
Jun 26 #Python
django2+uwsgi+nginx上线部署到服务器Ubuntu16.04
Jun 26 #Python
pycharm下查看python的变量类型和变量内容的方法
Jun 26 #Python
Python自然语言处理 NLTK 库用法入门教程【经典】
Jun 26 #Python
python实现俄罗斯方块游戏
Mar 25 #Python
python中的变量如何开辟内存
Jun 26 #Python
You might like
PHP文件缓存内容保存格式实例分析
2014/08/20 PHP
php+resumablejs实现的分块上传 断点续传功能示例
2017/04/18 PHP
一页面多XMLHttpRequest对象
2007/01/22 Javascript
JavaScript 继承的实现
2009/07/09 Javascript
location.href语句与火狐不兼容的问题
2010/07/04 Javascript
事件模型在各浏览器中存在差异
2010/10/20 Javascript
jquery中$.post()方法的简单实例
2014/02/04 Javascript
javascript高级编程之函数表达式 递归和闭包函数
2015/11/29 Javascript
JS获取随机数和时间转换的简单实例
2016/07/10 Javascript
Javascript学习之谈谈JS的全局变量跟局部变量(推荐)
2016/08/28 Javascript
利用Jquery队列实现根据输入数量显示的动画
2016/09/01 Javascript
Angularjs中controller的三种写法分享
2016/09/21 Javascript
Vue.js组件tree实现省市多级联动
2016/12/02 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
VUE 更好的 ajax 上传处理 axios.js实现代码
2017/05/10 Javascript
ReactNative Image组件使用详解
2017/08/07 Javascript
vue-resource + json-server模拟数据的方法
2017/11/02 Javascript
浅析node Async异步处理模块用例分析及常用方法介绍
2017/11/17 Javascript
微信小程序获取音频时长与实时获取播放进度问题
2018/08/28 Javascript
在React中写一个Animation组件为组件进入和离开加上动画/过度效果
2019/06/24 Javascript
VSCode搭建Vue项目的方法
2020/04/30 Javascript
[01:28:56]2014 DOTA2华西杯精英邀请赛 5 24 CIS VS DK
2014/05/26 DOTA
python文件和目录操作函数小结
2014/07/11 Python
python 连接sqlite及简单操作
2017/06/30 Python
Python 通过打码平台实现验证码的实现
2019/05/13 Python
Django数据统计功能count()的使用
2020/11/30 Python
柏林通行证:Berlin Pass
2018/04/11 全球购物
优瑞自动咖啡机官网:Jura
2018/09/29 全球购物
越南综合购物网站:Lazada越南
2019/06/10 全球购物
高级技校毕业生自荐信
2013/11/18 职场文书
大众服装店创业计划书范文
2014/01/01 职场文书
可口可乐广告词
2014/03/20 职场文书
离婚协议书怎样才有法律效力
2014/10/10 职场文书
2014流动人口计划生育工作总结
2014/12/20 职场文书
详解thinkphp的Auth类认证
2021/05/28 PHP
Python IO文件管理的具体使用
2022/03/20 Python