HTML解析技术之pyquery

一、安装

pip install pyquery

二、简介

pyquery是Python仿照jQuery严格实现的HTML解析库。它可以让我们直接解析DOM节点的结构,并通过DOM节点的一些属性(如:id,class等)对内容进行快速提取。

三、开始使用

1. 初始化

在使用pyquery库中的方法对HTML进行解析之前,我们需要先将网页进行初始化,使其变成一个PyQuery对象,才能使用该对象对应的方法。

(1). 字符串初始化

直接把字符串类型的HTML内容作为参数去传递来初始化成PyQuery对象。

源HTML字符串:

html = """
<div>
    <ul>
         <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>
"""

初始化:

from pyquery import PyQuery as pq
# 初始化html字符串为PyQuery对象
doc = pq(html)

操作对象:

print(type(doc))
print(doc('li'))

结果:
pyquery.pyquery.PyQuery
<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>

(2). URL初始化

直接把URL作为参数去传递来初始化成PyQuery对象。

源URL:

url = "https://www.baidu.com"

初始化:

from pyquery import PyQuery as pq
doc = pq(url=url)

操作对象:

print(doc('title'))
# 结果,乱码
<title>ç™¾åº¦ä¸€ä¸‹ï¼Œä½ å°±çŸ¥é“</title>

PyQuery首先请求url,用得到的HTML内容完成初始化。相当于将网页的源代码以字符串的形式传递给PyQuery类来进行初始化。
那么,可以改进一下:

import requests

# 将内容变成二进制结果传入PyQuery
doc = pq(requests.get(url=url).content)

print(doc('title'))
# 结果
<title>百度一下,你就知道</title>

(3). 文件(路径+名)初始化

直接把URL作为参数去传递来初始化成PyQuery对象。

from pyquery import PyQuery as pq
doc = pq(filename="./test.html")

2. CSS选择器操作

利用CSS选择器进行:查找节点、遍历节点、获取信息等操作

格式例子含义
.class.list选择class='list’的所有元素
#id#container选择id='container’的所有元素
**选择所有元素
elementli选择所有的li元素
element,elementdiv,li选择所有div元素和所有li元素
element elementdiv li选择所有div标签下的所有li元素
[attribute][color]选择带有color属性的所有元素
[attribute=value][color=‘red’]选择color='red’的所有元素
element.classdiv.list选择类为list的所有div标签的元素

后续使用的HTML

html = """
<div class="wrap">
	<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>
         	<p><li>sixth item</li></p>
     	</ul>
 	</div>
 </div>
"""

(1). 查找节点

子孙节点和子节点

子孙节点的查找需要使用find()方法,而子节点的查找使用children()方法

先通过CSS选择器,选取一个节点:

doc = pq(html)
class_list = doc(" .list")
print(class_list)

# 打印
<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>
         <p><li>sixth item</li></p>
</ul>

在该节点下选择子孙节点:

# 使用find方法
tag_li = class_list.find('li')
print(tag_li)

# 打印
		 <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>
         <li>test</li>
# <li>test</li>是孙节点

在该节点下选择子节点:

# 使用children方法
tag_li = class_list.children('li')
print(tag_li)

# 打印
		 <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>
祖先节点和父节点

祖先节点的查找需要使用parents()方法,父节点的查找需要使用parent()方法


# 父节点
tag_parent = class_list.parent()
print(tag_parent)


# 打印(父节点)
<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>
         <p class="active"><li>sixth item</li></p>
     </ul>
 </div>
# 祖先节点
tag_parents = p_list.parents()
print(tag_parents)

# 打印(父节点的父节节点+父节点)
<div class="wrap">
    <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>
             <p class="active"><li>sixth item</li></p>
         </ul>
     </div>
 </div>
 <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>
            <p class="active"><li>sixth item</li></p>
       </ul>
</div>

根据class选择祖先:

tag_parents = p_list.parents('.wrap')
print(tag_parents)

# 打印(类为wrap的节点)
<div class="wrap">
    <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>
             <p class="active"><li>sixth item</li></p>
         </ul>
     </div>
 </div>
兄弟节点

兄弟节点的查找需要使用siblings()方法

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
# <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>

print(li.siblings)
# 结果
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0">first item</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>
<p class="active"><li>sixth item</li></p>

(2). 遍历节点

从前面节点的选取可知,节点既可以是单个也可以是多个,并且都是PyQuery类型,而不是列表或其他Python中的容器类型。对于结果,可以转换成str类型,也可以保留PyQuery类型。

from pyquery import PyQuery as pq
doc = pq(html)
## 单个结果
result1 = doc('.item-0.active')

# 保留
type(result1)
print(result1)
# pyquery.pyquery.PyQuery
# <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>

# 转换str
type(str(result2))
print(str(result2))
# str
# <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>

## 多个结果遍历
result2 = doc('li').items()
print(type(result2))
for li in result2:
	print(li, type(li))
# 结果
<class 'generator'>

<li class="item-0">first item</li>
<class 'pyquery.pyquery.PyQuery'>

<li class="item-1"><a href="link2.html">second item</a></li>
<class 'pyquery.pyquery.PyQuery'>

<li class="item-0 active">
	<a href="link3.html">
		<span class="bold">third item</span>
	</a>
</li>
<class 'pyquery.pyquery.PyQuery'>

<li class="item-1 active">
	<a href="link4.html">fourth item</a>
</li>
<class 'pyquery.pyquery.PyQuery'>

<li class="item-0">
	<a href="link5.html">fifth item</a>
</li>
<class 'pyquery.pyquery.PyQuery'>

<li>sixth item</li> 
<class 'pyquery.pyquery.PyQuery'>

调用items()方法后,会转化PyQuery类型,得到一个生成器类型,遍历生成器,得到的每一个结果,还是PyQuery类型。

(3). 获取信息

提取到节点后,进一步提取节点中的信息。信息主要分成两种:属性信息和文本信息

获取属性信息

属性信息的获取使用attr('属性')方法,或者attr.属性方法

单个元素的属性信息获取:

from pyquery import PyQuery as pq

doc = pq(html)
a = doc(".item-0.active a")

print(a.attr('href'))
print(a.attr.href)

# link3.html
# link3.html

多个元素的属性信息获取:

from pyquery import PyQuery as pq

doc = pq(html)
a = doc("a")

print(a.attr('href'))
print(a.attr.href)

# 结果,4个a元素,但是只有一个结果
<a href="link2.html">second item</a>
<a href="link3.html"><span class="bold">third item</span></a>
<a href="link4.html">fourth item</a>
<a href="link5.html">fifth item</a>
link2.html
link2.html

整体取属性时,只会取第一个元素的属性信息。

所以需要进行遍历:

a = doc("a")
for item in a.items():
    print(item.attr('href'))
    
# 结果
link2.html
link3.html
link4.html
link5.html
获取文本信息

纯文本信息的获取使用text(),带标签的文本信息获取html()

单个元素的文本信息获取:

from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active a')
print(a)
print(a.text())
print(a.html())

# <a href="link3.html"><span class="bold">third item</span></a>
# third item
# <span class="bold">third item</span>

text()会忽略节点内部包含的HTML标签,只返回纯文本内容。
html()会返回内部HTML标签+文本内容

多个元素的文本信息获取:
对于多个元素的属性信息获取,需要遍历,但是文本信息获取是否需要呢?

a = doc('li')
print(a)
print(type(a.text()))
print(a.text())
print(type(a.html()))
print(a.html())

# 结果
<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>
<li>sixth item</li>

<class 'str'>
first item second item third item fourth item fifth item sixth item
<class 'str'>
first item

获取节点内部所有标签的文本,使用text,无需遍历。而获取节点内部的标签+文本,使用html,需要进行遍历,否则还是打印第一个元素的标签+文本。

(4). 节点的操作

html = '''
<div class="wrap">
    <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>
 </div>
'''
类属性的增加与删除

标签的类属性的增加addclass方法,删除removeclass方法

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.removeClass('active')
print(li)
li.addClass('action')
print(li)

# 结果
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             
<li class="item-0"><a href="link3.html"><span class="bold">third item</span></a></li>
             
<li class="item-0 action"><a href="link3.html"><span class="bold">third item</span></a></li>
标签的属性,纯文本和HTML内容的更改

标签的属性更改使用attr()方法,若传入一个参数,则是获取该属性;若传入两个参数,则是将第一个参数代表的属性更改为第二个参数值。

纯文本更改使用text()方法,不传入参数,则为获取值;传入一个参数,则为更改值

HTML内容更改使用html()方法,不传入参数,则为获取值;传入一个参数,则为更改值

li = doc('.item-0.active')
print(li)
# li节点增加了新的属性name
li.attr("name","lyh")
print(li)
# li节点内部全部被改成文本
li.text("play together!")
print(li)
# li节点内部全部被改成标签
li.html("<p>extra tag</p>")
print(li)

# 结果
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             
<li class="item-0 active" name="lyh"><a href="link3.html"><span class="bold">third item</span></a></li>
             
<li class="item-0 active" name="lyh">play together!</li>
             
<li class="item-0 active" name="lyh"><p>extra tag</p></li>
节点的删除

remove()删除节点

提取p标签下的内容:sixth item

text_all = doc('.list')
print(text_all)
print(text_all.text())
"""
<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>
             <p class="active"><li>sixth item</li></p>
</ul>

first item second item third item fourth item fifth item sixth item
"""

删除li节点:

li = li_p.children('li')
print(li)
li.remove()
"""
<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>
             
[<li.item-0>, <li.item-1>, <li.item-0.active>, <li.item-1.active>, <li.item-0>]
"""

打印p标签下的文本:

print(li_p)
print(li_p.text())
"""
<ul class="list">
             <p class="active"><li>sixth item</li></p>
</ul>
     
sixth item
"""

还有许多其他方法,如append、empty 和 prepend ,可参考官方文档:
其他方法(官网)

3. 伪类选择器

CSS选择器很强大,它支持多种多样的伪类选择器,可指定选择节点的位置,如:第一个、最后一个、偶数个、奇数个、含有某一文本的节点等。

doc = pq(html)

li = doc('li:first-child')
print(li)
li = doc('li:last-child')
print(li)
li = doc('li:nth-child(2)')
print(li)
li = doc('li:gt(2)')
print(li)
li = doc('li:nth-child(2n)')
print(li)
li = doc('li:contains(second)')
print(li)

以上使用了CSS伪类选择器,具体可参考文档:
CSS文档

参考文档(总)

官方文档
W3school之CSS

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值