整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

通过python的正则表达式re模块匹配出html标签以及内容

代码如下:

#以下代码是通过python的正则表达式re模块匹配出html标签以及内容
import re #必须导入内置的正则表达式re模块
info='<html><h2>zhangsan</h2></html>'
#上面一行代码定义info为html标签内容,包含2个标签,第1个标签是html,第2个标签是h2,标签内容是zhangsan
pattern1=re.compile(r'<(\w+)><(\w+)>(.+)</\2></\1>$')
#上面这行代码的(\w+)代表至少1个数字字母下划线,(.+)匹配除换行符 \n 之外的任何至少1个单字符,</\2>代表第2个标签的</h2>,</\1>代表第1个标签的</html>
result1=re.match(pattern1,info)
#上面这行代码代表从头开始匹配info里符合正则规则pattern1的内容,并赋值给result1
print("result1:",result1)
print("result1.group():",result1.group())
#上面这行代码代表要打印匹配出来的所有结果,group()代表所有的
print("result1.group(1):",result1.group(1))
#上面这行代码代表要打印匹配出来的第一个结果,group(1)代表第一个结果
print("result1.group(2):",result1.group(2))
#上面这行代码代表要打印匹配出来的第二个结果,group(2)代表第二个结果
print("result1.group(3):",result1.group(3))
#上面这行代码代表要打印匹配出来的第三个结果,group(3)代表第三个结果

代码运行结果如下:

result1: <re.Match object; span=(0, 30), match='<html><h2>zhangsan</h2></html>'>

result1.group(): <html><h2>zhangsan</h2></html>

result1.group(1): html

result1.group(2): h2

result1.group(3): zhangsan

图片示例如下:

一节介绍了re模块中常用函数的用法,我们可以通过使用re模块和正则表达式对文本进行解析并获取值。当并未真正获取到search()、match()等函数匹配到的字符串。本节将会介绍如何获取匹配到的字符串。

匹配对象和编组

在模块re中,查找与模式匹配的子串的函数都在找到时返回MatchObject对象。这种对象包含与模式匹配的子串的信息,还包含模式的哪部分与子串的哪部分匹配的信息。这些子串部分称为编组(group)

编组就是放在圆括号内的子模式,它们是根据左边的括号数编号的,其中编组0指的是整个模式。因此,在下面的模式中:

'There (was a (wee) (cooper)) who (lived in Fyfe)'

包含如下编组:

0 There was a wee cooper who lived in Fyfe

1 was a wee cooper

2 wee

3 cooper

4 lived in Fyfe

通常,编组包含诸如通配符和重复运算符等特殊字符,因此你可能想知道与给定编组匹配的内容。re模块为我们提供了匹配对象的一些重要的方法,用于获取编组对应的值。具体如下表所示:

方法

描述

group([group1, ...])

获取与给定子模式(编组)匹配的子串

start([group])

返回与给定编组匹配的子串的起始位置

end([group])

返回与给定编组匹配的子串的终止位置(与切片一样,不包含终止位置)

span([group])

返回与给定编组匹配的子串的起始和终止位置

group():返回与模式中给定编组匹配的子串。如果没有指定编组号,则默认为0。如果只指定了一个编组号(或使用默认值0),将只返回一个字符串;否则返回一个元组,其中包含与给定编组匹配的子串。

start():返回与给定编组(默认为0,即整个模式)匹配的子串的起始索引。

end():与start()类似,但返回终止索引加1。

span():返回一个元组,其中包含与给定编组(默认为0,即整个模式)匹配的子串的起始索引和终止索引。

上面关于匹配对象方法的用法如下my_re_continue.py程序所示:

my_re_continue.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

string = 'www.guanhu.name'

# group()方法,获取与给定子模式(编组)匹配的子串
m = re.match(r'www\.(.*)\..{4}', string)
print('m = {}'.format(m))
print(m.group(1))

# start()方法,返回与给定编组匹配的子串的起始索引
print(m.start(1))

# end()方法
print(m.end(1))

# span()方法
print(m.span(1))

程序执行结果如下所示:
m = <re.Match object; span=(0, 15), match='www.guanhu.name'>
guanhu
4
10
(4, 10)

替换中的组号和函数

在上一节的示例程序中,我们使用re.sub()函数,将一个字串替换为了另一个字串。当然这也可以使用字符串中的replace()方法轻松完成。但是,正则表达式很有用,它能够让我们以更灵活的方式进行检索,还能够执行更复杂的替换。

为利用re.sub的强大功能,最简单的方式是在替代字符串中使用组号。在替换字符串中,任何类似于'\n'的转义序列都将被替换为与模式中编组n匹配的字符串。例如,假设要将'*something*'替换为'<em>something</em>',其中前者是在纯文本文档(如电子邮件)表示突出的普通方式,而后者是相应的HTML代码(用于网页中)。下面先创建一个正则表达式,具体如下所示:

>>> pat = r'\*([^\*]+)\*'

创建模式之后,我们就可以使用re.sub来完成所需的替换了,具体如下所示:

>>> re.sub(pat, r'<em></em>', string)

'<em>something</em>'

简短的两行代码,就将纯文本转换成了网页所需的HTML代码。通过使用函数来替换内容,可执行更复杂的替换。在这里,re.sub()这个函数将MatchObject作为唯一的参数,它返回的字符串即为替换后的内容。我们可以对匹配的字符串做任何处理,并通过细致的处理来生成替换内容。

贪婪模式和非贪婪模式

重复运算默认都是贪婪的,因此,它们将会匹配尽可能多的内容。重写前面的突出程序,在其中使用了如下模式:

>>> pat = r'\*(.+)\*'

这个模式与以星号打头并以星号结尾的内容匹配,这看起来毫无破绽,但是实际情况并非如此,如下所示:

>>> re.sub(pat, r'<em></em>', '*This* is *it*!')

'<em>This* is *it</em>!'

从上面的执行结果,可以看出这个模式匹配了从第一个星号开始到最后一个星号之间的全部内容,其中包括了另外两个星号!这就是贪婪的意思:能匹配多少就匹配多少。

显然,这并不是我们想要的结果,当我们知道不应该将某个特定的字符包含在内时,使用本节前面的解决方案能够很好的解决我们的问题。但是,如果我们要使用'**something**'来表示突出内容呢?在这种情形下,在要强调的内容中包含单个星号不是问题,但是如何避免过度贪婪呢?

这实际上很容易,只需使用重复运算符的非贪婪版即可。对于所有的重复运算符,都可在后面加上问号来将其指定为非贪婪的。

>>> re.sub(r'\*\*(.+?)\*\*', r'<em></em>', '**some** **thing**')

'<em>some</em> <em>thing</em>'

这里使用的是运算符+?而不是+。这意味着与以前一样,这个模式将匹配一个或多个通配符,但匹配尽可能少的内容,因为它是非贪婪的。因此,这个模式只匹配到下一个'\*\*',即它末尾的内容。

总结

本节主要介绍了以下内容:

  1. 匹配对象和编组。
  2. 匹配对象的方法。
  3. 如何通过匹配对象的方法以及编组获取匹配到的字符串。
  4. 使用re.sub()函数进行内容替换。
  5. 贪婪模式和非贪婪模式。

下一节将会介绍一些实例来巩固正则表达式以及re模块中常用的方式和方法,敬请关注!

创作不容易,还请点个免费赞!喜欢的小伙伴请点关注、收藏!欢迎大家转发、评论!

#Python#

在《Python进阶记录之urllib模块》中,我们介绍了Python内置的HTTP请求库urllib模块的基本用法,需要重点掌握使用urllib的request模块进行简单的get、post请求。今天我们讲一下Python内置的HTML解析库HTMLParser模块,并结合之前的re模块和urllib模块实现爬取指定新闻页提取新闻文本内容的小需求。

HTMLParser模块简介

我们使用urllib模块进行HTTP请求获取到的是整个网页的HTML,但是我们往往只需要其中一部分对我们有用的内容。这时我们就可以使用HTMLParser模块来帮助我们处理HTML。

HTMLParser是Python内置的专门用来解析HTML的模块。利用HTMLParser,我们可以分析出一段HTML里面的标签、数据等,是一种处理HTML的简便途径。我们先来看一个官方的例子。

HTMLParser模块官方例子

从上述代码中可以看出,HTMLParser模块来自html.parser,导包时要格外注意。使用HTMLParser时,我们需要定义一个继承自HTMLParser的子类,并根据需要重写HTMLParser父类中的成员方法。例子中使用的各方法作用如下:

handle_starttag(tag, attrs):识别HTML的开始标签,例如<html>、<title>、<body>、<div>等。

handle_endtag(tag):识别HTML的结束标签,例如</html>、</body>、</div>、</p>等。

handle_data(data):识别HTML标签内容,例如“<p>Test</p>”中的Test。

handle_startendtag(tag, attrs):识别没有结束标签的HTML标签,例如<img />等。

handle_comment(data):识别HTML中的注释内容,一般是“<!-- 注释 -->”中的注释内容。

HTMLParser采用的是一种事件驱动的模式,HTMLParser找到一个特定的标记时,它会去调用一个用户定义的函数,以此来通知程序处理。

我们可以利用这些方法来实现HTML解析相关的功能。其中参数tag表示的是HTML标签,attrs是一个列表,列表元素为一个个“(属性,值)”形式的元组。HTMLParser会自动将tag和attrs都转为小写,解析时调用feed( )方法,把待解析的HTML字符串传入即可。

HTMLParser模块的简单应用

现在有以下网页,我们需要获取出里面的新闻文本内容。

待请求网页

首先就是获取该网页的HTML。经过上节内容的学习,我们很容易想到利用urllib库请求获取这个网页的HTML。

获取网页HTML

代码很简单,使用urlopen( )方法,传入url即可。此时,我们已经得到了整个网页的HTML,但是我们要获取的是新闻内容,显然此时的HTML中有太多我们不需要的东西。

观察整个网页HTML,我们发现新闻内容是包含在一个div中的。

新闻内容相关HTML

我们可以使用正则表达式re模块将包含新闻内容的这个div提取出来。

提取新闻内容相关的HTML

新闻内容的div格式主要是:<div class="article-content">...</div>。由于该div下嵌套了其他div,如果我们直接使用r'<div class=\"article-content\">(.*?)</div>'进行正则提取,会发现在下一个</div>处就截断了。为了正确提取所有新闻内容相关的HTML,我们需要在</div>前加一个</p>,以保证是在新闻内容结束的</div>处截断。

此时,我们已经得到了新闻内容相关的HTML。现在还剩最后一部,就是把HTML标签去掉,保留新闻文本内容。这一步,我们就可以利用HTMLParser来实现了。

HTMLParser提取新闻内容

我们定义一个继承自HTMLParser的子类,然后重写handle_data(data)方法获取当前HTML中的文本内容即可。由于我们定义的私有变量__text是通过一个列表来逐条接收新闻内容的,所以我们在类中定义一个获取私有变量__text的方法,并将列表转换成字符串。至此,我们已经获取到了新闻的文本内容。

然而,当前文本内容一整段在一起,看起来并不美观,与实际分段的新闻文本内容也有差别。我们可以使用HTMLParser来美化新闻内容。我们知道,网页上的新闻内容是通过“\n”、“\t”、“<br/>”等特殊符号或标签进行间隔和分段的。因此,我们只需要在解析时替换掉这些特殊符号和标签即可。

替换特殊符号和标签

重写handle_data(data)方法,识别文本的同时替换掉“\t”、“\r”、“\n”等特殊字符;重写handle_starttag(tag, attrs)方法,识别出<p>、<br>进行替换;重写handle_startendtag(tag, attrs)方法,识别出<br/>进行替换。再次运行程序,可以看到,新闻内容进行了分段,看起来就美观多了。

上述过程实现了一个非常简单的爬虫,爬取新闻网页,提取新闻内容。当然,由于我们目前还没介绍其他第三方库,实现起来还不够灵活,例如获取新闻内容的div我们现在只能通过正则表达式实现,但实际上,如果使用lxml(etree、xpath)、BeautifulSoup等第三方库会更简单实用。

总结

以上内容介绍了Python内置的HTML解析库HTMLParser模块,需要重点掌握HTMLParser类常用方法的作用,能够重写这些方法进行自定义解析。感谢大家的支持与关注,欢迎一起学习交流~