自学Python第十五天-常用的HTML解析工具:bs4、xpath、re

自学Python第十五天-常用的HTML解析工具:bs4、xpath、re

  • BS4
    • 安装和引入
    • 开始使用
    • `find_all()` 方法获取标签
    • `find()` 方法获取标签
    • `select()` 方法获取标签,css 选择器
    • 从标签中获取数据
  • XPath
    • xpath 基础
    • xpath 语法规则
    • lxml 模块
      • `xpath()` 方法
  • RE
    • `match()` 方法
    • `search()` 方法
    • `findall()` 方法
    • `finditer()` 方法
    • `sub()` 方法
    • `subn()` 方法
    • `split()` 方法
    • `compile()` 方法
    • `flags` 参数
    • `match` 对象

之前应该写过关于 bs4、xpath、re 的python使用文章,但是找不到了。因为这3种工具在 html 解析中经常用到,所以重新写一遍。

在 python 学习中绕不过去的就是爬虫,学习爬虫绕不过去的就是HTML页面解析,而最常用的解析工具就是 BeautifulSoup4XPathRE 了。这三个工具的比较如下:

工具解析速度使用难度安装难度
bs最简单简单
lxml(xpath)简单一般
正则(re)最快困难无(内置)

BS4

BeautifulSoup 4 简称 BS4,是一个 HTML/XML 的解析器。它是基于 HTML DOM 文档的,会载入整个文档,解析整个 DOM 树,因此时间和内存开销会大很多,性能较低。但是其语法是基于 CSS Selector 的,所以学习和使用非常简单。

BS4中文文档

安装和引入

pip install beautifulsoup4
from bs4 import BeautifulSoup

开始使用

bs4 使用时,首先创建 Beautiful Soup 对象,然后使用该对象的对应方法来解析DOM获取需要的元素标签对象,最后使用该对象的对应方法获取需要的属性或文本数据。例如:

from bs4 import BeautifulSouphtml = """
<html><head><title>The Dormouse'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 little 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>
"""# 创建 Beautiful Soup 对象
soup = BeautifulSoup(html, "lxml")print(soup.prettify())

find_all() 方法获取标签

可以使用 find_all(self, name=None, attrs={}, recursive=True, string=None, limit=None, **kwargs) 方法来匹配相应的元素列表。该方法最常用的参数就是 nameattrsstring

  • name 参数可以传递标签名称字符串或列表,以及正则表达式匹配对象
# 根据标签名获取标签元素
ret_a = soup.find_all('a')
ret_img = soup.find_all('img')# 根据标签名列表,返回匹配任一列表元素,即为或的关系
ret = soup.find_all(['a', 'img'])# 根据正则表达式
ret_re = soup.find_all(re.compile('^b'))
  • attrs 参数可以根据标签的属性来匹配
# 匹配标签中 class 属性
ret_sister_1 = soup.find_all(attrs={'class': 'sister'})
# 简写
ret_sistet_2 = soup.find_all(class_='sister')	# 之所以使用 class_ 而不使用 class,是因为 class 是 python 关键字
ret_id = soup.find_all(id='link')
  • string 参数可以搜索文档中的文本字符串内容。与 name 一样,可以接受字符串、列表以及正则表达式
ret_1 = soup.find_all(string='Elsie')
ret_2 = soup.find_all(string=['Tillie', 'Elsie', 'Lacie'])
ret_3 = soup.find_all(string=re.compile('Dormouse'))

当然三个参数可以同时使用,以获取需要的匹配标签元素。

find() 方法获取标签

find 方法与 find_all() 方法一样,区别在于 find() 返回第一个匹配结果,而 find_all() 方法返回所有匹配结果列表。

select() 方法获取标签,css 选择器

bs4 可以直接使用 css 选择器语法作为 select() 方法的参数。需注意的是,返回值也是一个列表

# 选择 title 标签
soup.select('title')
# 选择 img 标签
soup.select('img')
# 类选择器
soup.select('.sister')
# id 选择器
soup.select('#link1')
# 层级选择器
soup.select('p #link1')
# 属性选择器
soup.select('a[class="sister"]')
soup.select('a[href="http://example.com/elsie"]')

从标签中获取数据

获取到标签对象后,可以使用一些方法获取具体需要的数据

  • get_text() 方法,可以获取文本内容
  • get() 方法,可以获取属性,参数为属性名
for attr in soup.select('a'):print(attr.get('href'))

XPath

XPath (XML Path Language)XML路径语言,最初时是作为在 XML 文档中查找需要的信息,现在也适用于 HTML 文档。

xpath 作为一种普遍使用的解析语法,有着广泛的作用。xpath 的解析速度不慢,学习和使用起来也算是简单,所以成为解析 html 文档最常用的方法之一。XPath可以很轻松的选择出想要的数据,提供了非常简单明了的路径选择表达式,几乎想要任何定位功能,XPath都可以很轻松的实现。

W3School官方文档

xpath 基础

在 xpath 中,每一个标签都称之为节点,最顶层的节点称为根节点
节点和根节点
学习 xpath 可以使用一些浏览器辅助工具:

  • Chrome浏览器插件: XPath Helper
  • Firefox浏览器插件:XPath Finder

注意: 这些工具是用来学习XPath语法的,可以在这些工具中测试和联系语法规则,当熟练掌握XPath的语法后就可以直接在代码中编写XPath而不一定非要用此工具。

xpath 语法规则

XPath使用路径表达式来选取文档中的节点或者节点集。

表达式描述
nodename选中该元素
/从根节点选取、或者是元素和元素间的过渡
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
.选取当前节点
..选取当前节点的父节点
@选取属性
text()选取文本
contains()测试是否包含特定字符

路径表达式

路径表达式结果
bookstore选择bookstore元素
/bookstore选取根元素 bookstore。注释:假如路径起始于正斜杠(/),则此路径始终代表到某元素的绝对路径!
bookstore/book选取属于 bookstore 的子元素的所有 book 元素
//book选取所有 book 子元素,而不管它们在文档中的位置
bookstore//book选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置
//book/title/@lang选择所有的book下面的title中的lang属性的值
//book/title/text()选择所有的book下面的title的文本

查询特定节点

路径表达式结果
//title[@lang="eng"]选择lang属性值为eng的所有title元素
/bookstore/book[1]选取属于 bookstore 子元素的第1个 book 元素
/bookstore/book[last()]选取属于 bookstore 子元素的最后1个 book 元素
/bookstore/book[last()-1]选取属于 bookstore 子元素的倒数第2个 book 元素
/bookstore/book[position()>1]选择bookstore下面的book元素,从第2个开始选择
/bookstore/book[position()>1 and position()<4]选择bookstore下面的book元素,从第2个开始取到第4个元素
//book/title[text()='Harry Potter']选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素
//book/title[contains(text(), 'arry')]选择所有book下的tiile元素中,文本包含 arry 的元素
//a[@href[contains(., 'about')]]选择所有 href 属性包含 ‘about’ 的 a 元素

注意点: 在XPath中,第一个元素的位置是1,最后一个元素的位置是last(),倒数第二个是last()-1

lxml 模块

python 中使用 xpath 最常用的模块就是 lxml 模块。

pip install lxml
from lxml import etree

使用此模块需要先将需要解析的文本转化为 Element 对象,Element 对象有 xpath 的方法

from lxml import etreetext = ''' <div> <ul> <li class="item-1"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html">third item</a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a> </ul> </div> '''html = etree.HTML(text)# 将Element对象转化为字符串
handled_html_str = etree.tostring(html).decode()
print(handled_html_str)

xpath() 方法

Element 对象的 xpath() 方法可以使用 xpath 语法来获取需要的对象或数据。注意返回的是列表,如果是元素对象,则是 Element 对象。所以也可以使用链式调用的方式来多层获取需要的数据。

# 获取数据列表,返回值为字符串列表
href_list = html.xpath("//li[@class='item-1']/a/@href")
title_list = html.xpath("//li[@class='item-1']/a/text()")
# 获取节点列表
li_list = html.xpath("//li[@class='item-1']")
# 从节点列表对象中继续使用 xpath 匹配查询
for li in li_list:item = dict()item["href"] = li.xpath("./a/@href")[0] if len(li.xpath("./a/@href")) > 0 else Noneitem["title"] = li.xpath("./a/text()")[0] if len(li.xpath("./a/text()")) > 0 else Noneprint(item)

RE

RE 模块是python中使用正则语法的模块,正则的语法比较复杂,另外起一篇文章学习。这里只有 re 模块的使用方法。re 模块是 python 的内置模块,所以可以直接引入

import re

re 模块的使用方式一般有两种:

  • 直接使用相应的匹配方法,将匹配字符串和待查找文本作为参数传入。
  • 将匹配字符串编译为一个Pattern对象,并用此对象的相关匹配方法来匹配目标待查找文本。

match 对象是 re 模块方法所返回的默认的匹配对象大部分匹配方法如果得到匹配结果,就会返回 match 对象。

match() 方法

match(pattern, string, flags=0) 方法可以从字符串开头开始检测是否于模式匹配。如果匹配成功,返回匹配对象,否则返回None

# 从开头检测字符串是否匹配
match = re.match(r'\d+', '123abc')
if match:print(match.group())		# 输出 123

search() 方法

search(pattern, string, flags=0) 方法可以在字符串中搜索并返回第一个匹配项。如果匹配成功,返回匹配对象,否则返回None

# 使用 search 方法在整个字符串中搜索匹配
search = re.search(r'\d+', 'abc123def')
if search:print(search.group())  # 输出: 123

findall() 方法

findall(pattern, string, flags=0) 方法会返回所有非重叠匹配项列表。如果匹配模式中有一个或多个捕获组(group),则会返回元组列表

# 使用 findall 方法找到所有匹配的数字
numbers = re.findall(r'\d+', 'abc123def456')
print(numbers)  # 输出: ['123', '456']

finditer() 方法

findall() 方法类似,不过返回值为一个迭代器,其中每一个元素都是一个匹配对象。

sub() 方法

sub(pattern, repl, string, count=0, flags=0) 方法可以将匹配项替换为 repl 参数的值,repl 可以是一个字符串或一个函数;如果是函数,每个匹配项都会作为参数传递给这个函数。count 用于指定最大替换次数;默认 0,替换所有匹配项。

# 使用 sub 方法替换所有的数字为 '#'
replaced = re.sub(r'\d+', '#', 'abc123def456')
print(replaced)  # 输出: abc#def#

subn() 方法

sub() 方法类似,不过返回值是一个包含新字符串和替换次数的元组

split() 方法

split(pattern, string, maxsplit=0, flags=0) 方法可以根据匹配项来分割字符串。maxsplit 用于指定最大分割次数;默认 0,表示分割所有匹配项。

# 使用 split 方法根据数字分割字符串
parts = re.split(r'\d+', 'abc123def456ghi')
print(parts)  # 输出: ['abc', 'def', 'ghi']

compile() 方法

compile(pattern, flags=0) 方法实际并不进行匹配,而是返回一个正则表达式匹配模式对象,这个对象可以使用 matchsearchfindall 等方法来进行匹配。常用于同一个正则表达式需要重复的与不同文本进行匹配的情况,避免重复编译相同的模式,提高效率。

p = re.compile(r'\d+')
search = p.search('abc123def')
if search:print(search.group())  # 输出: 123

flags 参数

几乎 re 模块的每种方法都有 flags 参数,该参数可以用于控制正则表达式的匹配方式:

简写说明
re.IGNORECASEre.I大小写不敏感。
re.MULTILINEre.M多行模式,改变 ^$ 的行为,使它们分别匹配每一行的开头和结尾,而不仅仅是整个字符串的开头和结尾。
re.DOTALLre.S使 . 特殊字符匹配任何字符,包括换行符。
re.UNICODEre.U根据 Unicode 字符集解析字符。这是 Python 3 中的默认行为。
re.ASCIIre.A使 \w, \W, \b, \B, \d, \D, \s\S 只匹配 ASCII 字符。
re.VERBOSEre.X允许在正则表达式中添加空白和注释。
import re# 忽略大小写的匹配
case_insensitive = re.findall(r'abc', 'ABCabc', flags=re.IGNORECASE)
print(case_insensitive)  # 输出: ['ABC', 'abc']# 多行模式的匹配
multiline = re.search(r'^abc', 'def\nabc', flags=re.MULTILINE)
if multiline:print(multiline.group())  # 输出: abc# 让点号匹配换行符
dotall = re.search(r'a.b', 'a\nb', flags=re.DOTALL)
if dotall:print(dotall.group())  # 输出: a\nb# 使用 ASCII 字符集
ascii_char = re.findall(r'\w+', 'café', flags=re.ASCII)
print(ascii_char)  # 输出: ['caf']# 使用 VERBOSE 模式,允许正则表达式分行并添加注释
verbose = re.compile(r"""\b      # 单词边界\w+     # 一个或多个字母数字字符\b      # 单词边界
""", flags=re.VERBOSE)
print(verbose.findall('Hello, world!'))  # 输出: ['Hello', 'world']

match 对象

match 对象有一些常用的属性和方法,来获取需要的数据

属性说明
string返回传递给 matchsearch 等函数的原始字符串。
re返回用于匹配的正则表达式对象。
pos返回用于匹配的字符串的起始位置。
endpos返回用于匹配的字符串的结束位置。
lastindex返回最后一个被捕获的分组在 Match 对象中的索引。
lastgroup返回最后一个被捕获的分组的名称。
方法说明
group(num=0)返回整个匹配的字符串,或者指定编号的分组。
groups(default=None)返回一个包含所有捕获组的元组,如果没有匹配则为 default
groupdict(default=None)返回一个字典,包含所有命名的捕获组。
start([group])返回指定分组的起始位置。
end([group])返回指定分组的结束位置。
span([group])返回 (start(group), end(group))
import re# 使用 search 方法查找数字
match = re.search(r'\d+', 'User ID: 12345')
if match:print(match.group())  # 输出匹配到的数字: 12345# 使用捕获组
match = re.search(r'User ID: (\d+)', 'User ID: 12345')
if match:print(match.group(1))  # 输出第一个捕获组匹配到的内容: 12345# 使用命名捕获组
match = re.search(r'User ID: (?P<id>\d+)', 'User ID: 12345')
if match:print(match.group('id'))  # 输出命名捕获组 'id' 匹配到的内容: 12345# 获取匹配的起始和结束位置
match = re.search(r'ID', 'User ID: 12345')
if match:print(match.span())  # 输出匹配字符串 'ID' 的起始和结束位置: (5, 7)# 获取所有捕获组
match = re.search(r'(\w+) (\w+)', 'Hello World')
if match:print(match.groups())  # 输出所有捕获组的内容: ('Hello', 'World')# 获取所有命名捕获组
match = re.search(r'(?P<first>\w+) (?P<second>\w+)', 'Hello World')
if match:print(match.groupdict())  # 输出所有命名捕获组的内容: {'first': 'Hello', 'second': 'World'}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/705782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git配置SSH

gitLab在Cenos7中安装&#xff0c;在Cenos7系统中执行以下操作 1.生成SSH ssh-keygen -t rsa -C xxxxxx.com 然后一路回车,直到出现以下界面为止(-C 参数是邮箱地址) 2.复制SSH 打开/root/.ssh/id_rsa.pub文件&#xff0c;复制其中的内容 在Linux系统中&#xff0c;/root/.…

初谈软件工程(一)

我就读于兰州交通大学的软件工程专业。虽然在全国众多的985、211高校中&#xff0c;兰州交通大学可能并不显眼&#xff0c;似乎未能跻身这些所谓的“顶尖”行列就意味着不被认可。然而&#xff0c;在甘肃省的教育领域中&#xff0c;它无疑是一座璀璨的明珠&#xff0c;名列前茅…

使用R语言进行主成分和因子分析

一、数据描述 数据来源2013年各地区水泥制造业规模以上企业的各主要经济指标&#xff0c;原始数据来源于2014年&#xff08;《中国水泥统计年鉴》&#xff09;&#xff0c;试对用主成分和因子进行经济效益评价。 地区,企业个数&#xff08;亿元&#xff09;,流动资产合计&…

pytest-配置项目不同环境URL

pytest自动化中&#xff0c;在不同环境进行测试&#xff0c;可以将项目中的url单独抽取出来&#xff0c;通过pytest.ini配置文件实现&#xff08;类似postman中的“Environments”&#xff09; 使用步骤&#xff1a; 1&#xff09;安装pytest-base-url插件 pytest-base-url …

阿里云国际云解析DNS如何开启/关闭流量分析?

流量分析服务会涉及产生日志费用&#xff0c;所以开通内网DNS解析服务后&#xff0c;默认不会主动开启流量分析&#xff0c;需要您手动开启流量分析。对于未开启流量分析的用户&#xff0c;进入界面会提示您展示的都是模拟数据&#xff0c;您可以点击开启流量分析服务&#xff…

【pytorch】常用代码

文章目录 条件与概率torch.tensor()torch.rand()torch.randn()torch.randint()torch.multinominal() 逻辑运算torch.argmax()torch.max()torch.sum()torch.tanh()torch.pow() 功能性操作 torch.nn.functionalF.normalize()F.elu()F.relu()F.softmax() 张量计算torch.zeros()tor…

基于JavaWeb实现的校园新闻发布系统

一、系统架构 前端&#xff1a;jsp | bootstrap | js | css 后端&#xff1a;springboot | jdbc 环境&#xff1a;jdk1.6 | mysql | maven 二、 代码及数据库 三、功能介绍 01. web端-首页 02. web端-新闻列表 03. web端-新闻明细 04. 管理端-登录页…

数据可视化引领智慧工业新时代

在智慧工业的大潮中&#xff0c;数据可视化崭露头角&#xff0c;以其直观、清晰的方式赋能工业生产&#xff0c;为智慧工业的高效运转提供了强有力的支持。下面我就以可视化从业者的角度&#xff0c;简单聊聊这个话题。 数据可视化首先在智慧工业的生产监控中大显身手。通过将…

Vue3前端实现一个本地消息队列(MQ), 让消息延迟消费或者做缓存

MQ功能实现的具体代码(TsMQ.ts)&#xff1a; import { v4 as uuidx } from uuid;import emitter from /utils/mitt// 消息类 class Message {// 过期时间&#xff0c;0表示马上就消费exp: number;// 消费标识&#xff0c;避免重复消费tag : string;// 消息体body : any;constr…

手机打开 第三方 “微信、快手、QQ、电话、信息” 等

前期回顾 Vue3 TS Element-Plus —— 项目系统中封装表格搜索表单 十分钟写五个UI不在是问题_vue3 封装table 配置表格-CSDN博客https://blog.csdn.net/m0_57904695/article/details/135538630?spm1001.2014.3001.5501 目录 &#x1f916; 下载App如下图所示&#xff1a;…

10 款数据恢复软件功能和有效性对比(2024 年更新)

数据丢失可能是一种痛苦的经历&#xff0c;无论是由于意外删除、硬件故障还是软件损坏。值得庆幸的是&#xff0c;数字时代带来了强大的数据恢复解决方案。 随着我们进入 2024 年&#xff0c;市场上充斥着旨在有效检索丢失数据的先进软件。在本文中&#xff0c;我们将探讨 2024…

代码随想录 Leetcode494. 目标和

题目&#xff1a; 代码(首刷看解析 2024年2月26日&#xff09; 思路&#xff1a;根据题意&#xff0c;设两个背包&#xff0c;packageA存放前面是""的数字之和&#xff0c;packageB存放前面是“-”的数字之和 则sum packageA packageB; target packageA - packag…

科普:哪几类人适合做人力RPO蓝海项目?

在当今竞争激烈的市场环境中&#xff0c;人力资源管理对于企业的重要性日益凸显。人办理RPO(招聘流程外包)作为一种新兴的服务模式&#xff0c;帮助企业优化招聘流程&#xff0c;提高招聘效率和质量。那么&#xff0c;哪几类人适合做人力RPO蓝海项目呢?本文将为大家详细总结一…

QT之项目经验(windows下的sqlite,c++开发)

目录 一、需要时间去磨练gui的调整和优化 1. 借鉴网上开源项目学习 2. gui的布局及调整是磨人的一件事情 3. gui的布局也是可以用组件复刻的 4. 耗时的设备树 二、多线程异步弹窗 三、定时任务动态变更设定 1.确定按钮触发 2.此处监听定时任务时间的改变 3.此处对改变做出具…

ClickHouse 指南(三)最佳实践 -- 跳数索引

Data Skipping Indexes Data Skipping Indexes 2 1、简介 影响ClickHouse查询性能的因素很多。在大多数情况下&#xff0c;关键因素是ClickHouse在计算查询WHERE子句条件时是否可以使用主键。因此&#xff0c;选择适用于最常见查询模式的主键对于有效的表设计至关重要。 然…

k8s(5)

目录 使用Kubeadm安装k8s集群&#xff1a; 初始化操作&#xff1a; 每台主从节点&#xff1a; 升级内核&#xff1a; 所有节点安装docker &#xff1a; 所有节点安装kubeadm&#xff0c;kubelet和kubectl&#xff1a; 修改了 kubeadm-config.yaml&#xff0c;将其传输给…

k8s pv与pvc理解与实践

参考文章&#xff1a; https://blog.csdn.net/qq_41337034/article/details/117220475 一、 pv/pvc简述 Pv是指PersistentVolume&#xff0c;中文含义是持久化存储卷是对底层的共享存储的一种抽象&#xff0c;Pv由管理员进行配置和创建&#xff0c;只要包含存储能力&#xff…

iPhone利用文件管理器批量导出语音备忘录和照片到电脑

步骤1&#xff1a;使用文件服务器在 iPhone 和电脑间共享文件 参考文献&#xff1a;苹果官网操作指南 步骤1.1&#xff1a;iPhone上打开文件app&#xff0c;点击右上角三个点&#xff0c;选择“连接服务器” 步骤1.2&#xff1a;输入电脑的登录账号和密码 步骤1.3&#xff1a…

基于uniapp框架的古汉语学习考试系统 微信小程序python+java+node.js+php

1、一般用户的功能及权限 所谓一般用户就是指还没有注册的过客,他们可以浏览主页面上的信息。但如果需要其它操作时&#xff0c;要登录注册&#xff0c;只有注册成功才有的权限。 2、管理员的功能及权限 用户信息的添加和管理&#xff0c;古汉语信息加和管理和学习视频添加和管…

php脚本输出中文在浏览器中显示乱码

问题说明 这个问题一般出现在较低版本的php中&#xff0c;原因是php和浏览器的字符解析方式不对应 &#xff0c;导致中文字符被错误解析成乱码 &#xff08;注&#xff0c;此处的php版本任意切换是依赖于小皮面板&#xff08;phpstudy&#xff09;实现的&#xff0c;感兴趣可以…