python3解析库(Beautiful Soup、pyquery、parsel)
Beautiful Soup
基本使用
<html>
<head>
<title>
The Document's story
</title>
</head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!--Elsie--></a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
</html>
from bs4 import BeautifulSoup
# 使用lxml解析器
soup=BeautifulSoup(html,'lxml')
# 通过prettify修正html
print(soup.prettify())
//输出title的内容
print(soup.title.string)
节点选择器
from bs4 import BeautifulSoup
# 使用lxml解析器
soup=BeautifulSoup(html,'lxml')
print(soup.title)
# <title>The Document's story</title>
print(soup.title.string)
#The Document's story
print(soup.head)
#<head><title>The Document's story</title></head>
print(soup.p)
#当有多个节点时,此方法只会选择匹配到的第一个,后面的忽略
#<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
提取信息
获取名称
利用name属性可以获取节点的名称。
print(soup.title.name)
获取属性
一个节点可能有多个属性,例如id和class等,选择这个节点元素后可以调用attrs获取其所有属性:
print(soup.p.attrs)
print(soup.p.attrs['name'])
{'class':['title'],'name':'dromouse'} dromouse
调用attrs属性返回结果是字典形式,包括所选择节点的所有属性和属性值。其中attrs可以省略,直接使用[],有一些属性会返回列表,有一些返回字符串,因为class可能会有多个
print(soup.p['name']) # dromouse print(soup.p['class']) # ['title']
获取内容
print('soup.p.string')
这里只会选取p节点的第一个节点
关联选择
from bs4 import BeautifulSoup
html = """
<html>
<head>
<title>
The Document's story
</title>
</head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!--Elsie--></a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
</html>
"""
soup = BeautifulSoup(html, 'lxml')
#获取直接子元素
print("这是子节点所以内容", soup.p.contents)
# 对子节点进行遍历
for i, child in enumerate(soup.p.children):
print("这是子节点", i, child)
print('\n')
# 获取子孙元素
for i, child in enumerate(soup.p.descendants):
print("这是子孙节点", i, child)
print('--------------------------------------------------------')
# 获取父元素
print('这是父元素', soup.a.parent)
# 获取兄弟元素
print('这是前面的兄弟元素' , list(enumerate(soup.a.previous_siblings)))
print('这是后面的兄弟元素' , list(enumerate(soup.a.next_siblings)))
方法选择器
Beautiful Soup提供一些查询的方法
find_all
find_all(name,attrs,recursive,text,**kwargs)
name
from bs4 import BeautifulSoup
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
<div>
</div>
'''
soup=BeautifulSoup(html,'lxml')
print(soup.find_all(name='ul'))
''' [<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>]
'''
print(type(soup.find_all(name='ul')[0]))
# <class 'bs4.element.Tag>'
for ul in soup.find_all(name='ul'):
print(ul.soup.find_all(name='li'))
for li in ul.soup.find_all(name='li'):
print(li.string)
"""
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
Foo
Bar
Jay
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
Foo
Bar
"""
attrs
通过属性进行查询
# id可以省略attrs属性直接使用id='list-1'
print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all(attrs={'name':'elements'}))
# class为python关键字,所以需要再class后加一个_
print(soup.find_all(class_='element'))
text
可以使用text参数来匹配文本,输入类型可以是字符串也可以是正则表达式
print(soup.find_all(text=re.compile('Foo')))
使用text会警告 DeprecationWarning: The 'text' argument to find()-type methods is deprecated. Use 'string' instead。换成string=即可
find
除了fand_all方法,fand方法也可以查询符合条件的元素,不过find方法返回的元素是单个,是匹配的第一个元素。而fand_all会返回一个元素组成的列表。
其他方法
- find_parents和find_parent:前者返回所有祖先节点。后者返回父节点。
- find_next_siblings和find_next_sibling:前者返回后面的所有兄弟节点,后者返回后面第一个兄弟节点。
- find_previous_siblings和find_previous_sibling:前者返回前面的所有兄弟节点,后者返回前面第一个兄弟节点。
- find_all_next和find_next:前者返回节点后面所有符合条件的节点,后者返回后面第一个符合条件的节点。
- find_all_previous和find_previous:前者返回节点前面所有符合条件的节点,后者返回前面第一个符合条件的节点。
CSS选择器
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'lxml')
print(soup.select('ul li'))
# [<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
print(soup.select('.panel .panel-heading'))
# [<div class="panel-heading"><h4>Hello</h4></div>]
print(soup.select('#list-2 .element'))
# [<li class="element">Foo</li>, <li class="element">Bar</li>]
# 嵌套选择
for ul in soup.select('ul'):
print(ul.select('li')) # 和ul ul显示结果一致
# 获取属性
for ul in soup.select('ul'):
# 获取每个节点的id属性
print(ul['id'])
print(ul.attrs["id"])
# 获取文本
for li in soup.select('li'):
# 除了通过string属性获取文本,还可以通过方法get_text()
print(li.string)
print(li.get_text())
pyquery
基本使用
from pyquery import PyQuery as pq
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>
"""
doc = pq(html)
print(doc('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>
'''
URL初始化
访问url地址解析html
from pyquery import PyQuery as pq
import requests
doc=pq(url='hppts://www.baidu.com')
print(doc('title'))
# 显示乱码
# 等同于以下
# 使用ruquests选择编码格式
resp=requests.get('hppts://www.baidu.com')
resp.encoding="utf-8"
doc=pq(resp.text)
print(doc('title'))
# <title>百度一下,你就知道</title>
文件初始化
读取本地文件html进行解析
doc=pq(filename='demo.html')
CSS选择器
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)
# 打印id为container下的class为list的所有li
print(doc('#container .list 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>
"""
print(type(doc('#container .list li')))
# <class 'pyquery.pyquery.PyQuery'>
# PyQuery类型可以进行遍历
for item in doc('#container .list li'):
print(item.text())
# first item
# second item
# third item
# fourth item
# fifth item
查找节点
子节点
from pyquery import PyQuery as pq
doc=pq(html)
items=doc('.list')
print(type(items))
# <class 'pyquery.pyquery.PyQuery'>
print(items)
"""
<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>
"""
lis=items.find('li')
print(type(lis))
# <class 'pyquery.pyquery.PyQuery'>
print(lis)
"""
<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>
"""
# 查找子元素
lis=items.chlidren()
# 筛选子元素中符合条件的节点
print(items.children('.active'))
# <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>
find()的范围是所有子孙元素,children()是子元素
父元素
parent()寻找某个节点的直接父元素,不会寻找父元素的父元素。parents()寻找祖先元素,如果存在多个相同的元素调用,会返回所有的祖先元素,如果要筛选某个特定的祖先元素可以传入parents()方法需要筛选的节点
兄弟元素
使用siblings()方法可以筛选出兄弟节点,如果需要对多个兄弟节点进行进一步筛选可以在siblings()方法中传入符合条件的节点
遍历节点
from pyquery import PyQuery as pq
doc=pq(html)
li=doc('.item-0.active')
print(li)
# <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
print(str(li))
# <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
# 如果是多个节点需要遍历使用方法items()
lis=doc('li').items()
print(type(lis))
for li in lis:
print(li,type(li))
PyQuery返回单个节点或者多个节点不想beautifulsoup会返回一个列表,所以如果是多个节点需要使用items()方法进行遍历
获取属性
from pyquery import PyQuery as pq
doc=pq(html)
a=doc('.item-0.active a')
print(a.attr('href'))
# link3.html
# 也可以使用
print(a.attr.href)
# 当获取多个a时,使用a.attr只会返回第一个所以需要使用items()方法
a=doc('a')
for item in a.items():
print(item.arrt('href'))
#link2.html link3.html link4.html link5.html
获取文本
使用text()方法可以把标签内部文字输出。如果要获取标签内部的html文本,可以使用html()
如果标签有多个使用text()会返回所有文字,使用逗号隔开。html()只会返回第一个
节点操作
addClass和removeClass
对节点中的class进行新增或者删除
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print("删除一次", li.removeClass('active'))
print("新增一次", li.add_class('active'))
# 删除一次 <li class="item-0"><a href="link3.html"><span class="bold">third item</span></a></li>
# 新增一次 <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
attr、text、和html
除了使用addClass和removeClass对节点进行操作,还可以通过attr方法对属性进行操作,text和html对内容进行操作
from pyquery import PyQuery as pq html=""" <ul class="list"> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> </ul> """ lis = """ <ul class="list"> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> </ul> """ doc = pq(lis) li = doc(".item-0.active") print("原始数据", li) li.attr('name', 'link') print("添加属性", li) li.text('changed item') print("修改内容", li) li.html('<span>changed item</span>') 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="link"><a href="link3.html"><span class="bold">third item</span></a></li> 修改内容 <li class="item-0 active" name="link">changed item</li> 修改内部属性 <li class="item-0 active" name="link"><span>changed item</span></li> """
remove
当只想要显示信息里的具体内容时可以使用remove删除节点
from pyquery import PyQuery as pq lis = """ <ul class="list"> hh <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> </ul> """ text = doc('.list') text.find('li').remove() print(text.text()) # hh
伪类选择器
from pyquery import PyQuery as pq
doc=pq('html')
# 第一个li节点
li=doc('li:first-child')
# 最后一个li节点
li=doc('li:last-child')
# 第二个li节点
li=doc('li:nth-child(2)')
# 第三个li后的节点
li=doc('li:gt(2)')
# 偶数位置li节点
li=doc('li:nth-child(2n)')
# 包含文本second的li节点
li=doc('li:contains(second)')
parsel
可以将Xpath、PyQuery库联合使用。Scrapy选择器基于做二次封装
pip3 install parsel
from parsel import Selector
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>
"""
selector=Selector(text=html)
# 返回一个SelectorList可迭代对象
items=selector.css('.item-0')
for item in items:
# 提前当前所有节点内容,输入文本
text=item.xpath('.//text()').get()
# 获取class属性为item-0的所以li节点文本,只会显示一个
# 需要使用getall()才会显示所有文本
items2=selector.xpath('//li[contains(@class,"item-0")]').get()
# 也可以替换为
# *提取所有子节点。::text提取文本
selector.css('.item-0::text').getall()
# 提取属性
selector.css('.item-0.active a::attr(href)').get()
selector.xpath('//li[contains(@class,"item-0") and contains(@class,"active")]/a/@href').get()
# 正则表达式提取
selector.css('.item-0').re('link.*')
本文作者:Kang_kin
本文链接:https://www.cnblogs.com/kangkin/p/17360350.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步