php 正则表达式获取html标签内容_Python正则表达式的使用方法(下)

29f37503bc7781216c662d4ffa14de5e.png

转义匹配

我们知道正则表达式定义了许多匹配模式,如.匹配除换行符以外的任意字符,但是如果目标字符串里面它就包含.我们改怎么匹配?

那么这里就需要用到转义匹配了,我们用一个实例来感受一下:

import re

content = '(百度)www.baidu.com'

result = re.match('(百度)www.baidu.com', content)

print(result)

当遇到用于正则匹配模式的特殊字符时,我们在前面加反斜线来转义一下就可以匹配了。例如.我们就可以用.来匹配,运行结果:

<_sre.sre_match object span="(0," match="(百度)www.baidu.com">

可以看到成功匹配到了原字符串。

以上是写正则表达式常用的几个知识点,熟练掌握上面的知识点对后面我们写正则表达式匹配非常有帮助。

search()

我们在前面提到过match()方法是从字符串的开头开始匹配,一旦开头不匹配,那么整个匹配就失败了。

我们看下面的例子:

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'

result = re.match('Hello.?(d+).?Demo', content)

print(result)

在这里我们有一个字符串,它是以Extra开头的,但是正则表达式我们是以Hello开头的,整个正则表达式是字符串的一部分,但是这样匹配是失败的,也就是说只要第一个字符不匹配整个匹配就不能成功,运行结果如下:

None

所以match()方法在我们在使用的时候需要考虑到开头的内容,所以在做匹配的时候并不那么方便,它适合来检测某个字符串是否符合某个正则表达式的规则。

所以在这里就有另外一个方法search(),它在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果,也就是说,正则表达式可以是字符串的一部分,在匹配时,search()方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容,如果搜索完了还没有找到,那就返回None。

03e3a22b7de61a106b678acc6bdd4e09.png

我们把上面的代码中的match()方法修改成search(),再看下运行结果:

<_sre.sre_match object span="(13," match="Hello 1234567 World_This is a Regex Demo">

1234567

这样就得到了匹配结果。

所以说,为了匹配方便,我们可以尽量使用search()方法。

下面我们再用几个实例来感受一下search()方法的用法。

首先这里有一段待匹配的HTML文本,我们接下来写几个正则表达式实例来实现相应信息的提取。

html = '''

经典老歌

经典老歌列表

一路上有你

沧海一声笑

往事随风

光辉岁月记事本

但愿人长久

'''

观察到

  • 节点里面有许多
  • 节点,其中
  • 节点有的包含节点,有的不包含节点,节点还有一些相应的属性,超链接和歌手名。

    首先我们尝试提取class为active的

  • 节点内部的超链接包含的歌手名和歌名。

    所以我们需要提取第三个

  • 节点下的节点的singer属性和文本。

    所以正则表达式可以以

  • 开头,然后接下来寻找一个标志符active,中间的部分可以用.?来匹配,然后接下来我们要提取singer这个属性值,所以还需要写入singer="(.?)",我们需要提取的部分用小括号括起来,以便于用group()方法提取出来,它的两侧边界是双引号,然后接下来还需要匹配节点的文本,那么它的左边界是>,右边界是,所以我们指定一下左右边界,然后目标内容依然用(.?)来匹配,所以最后的正则表达式就变成了(.*?)',然后我们再调用search()方法,它便会搜索整个HTML文本,找到符合正则表达式的第一个内容返回。

另外由于代码有换行,所以这里第三个参数需要传入re.S

1a2d306327151b7698f273ee597b69e3.png

所以整个匹配代码如下:

result = re.search('
(.?)', html, re.S)

if result:

print(result.group(1), result.group(2))

由于我们需要获取的歌手和歌名都已经用了小括号包围,所以可以用group()方法获取,序号依次对应group()的参数。

运行结果:

齐秦 往事随风

可以看到这个正是我们想提取的class为active的

节点内部的超链接包含的歌手名和歌名。

那么正则表达式不加active会怎样呢?也就是匹配不带class为active的节点内容,我们将正则表达式中的active去掉,代码改写如下:

result = re.search('
(.*?)', html, re.S)

if result:

print(result.group(1), result.group(2))

由于search()方法会返回第一个符合条件的匹配目标,那在这里结果就变了。

运行结果如下:

任贤齐 沧海一声笑

因为我们把active标签去掉之后,从字符串开头开始搜索,符合条件的节点就变成了第二个

节点,后面的就不再进行匹配,所以运行结果自然就变成了第二个节点中的内容。

注意在上面两次匹配中,search()方法的第三个参数我们都加了re.S,使得.*?可以匹配换行,所以含有换行的

节点被匹配到了,如果我们将其去掉,结果会是什么?
result = re.search('
(.*?)', html)

if result:

print(result.group(1), result.group(2))

运行结果:

beyond 光辉岁月

可以看到结果就变成了第四个

节点的内容,这是因为第二个和第三个标签都包含了换行符,去掉re.S之后,.*?已经不能匹配换行符,所以正则表达式不会匹配到第二个和第三个节点,而第四个节点中不包含换行符,所以成功匹配。

由于绝大部分的HTML文本都包含了换行符,所以通过上面的例子,我们尽量都需要加上re.S修饰符,以免出现匹配不到的问题。

findall()

在前面我们说了search()方法的用法,它可以返回匹配正则表达式的第一个内容,但是如果我们想要获取匹配正则表达式的所有内容的话怎么办?这时就需要借助于findall()方法了。

findall()方法会搜索整个字符串然后返回匹配正则表达式的所有内容。

还是上面的HTML文本,如果我们想获取所有节点的超链接、歌手和歌名,就可以将search()方法换成findall()方法。如果有返回结果的话就是list类型,所以我们需要遍历一下list来获依次获取每组内容。

4ea271e2c0f30cbd74ebdf0bdad718b6.png
results = re.findall('
(.*?)', html, re.S)

print(results)

print(type(results))

for result in results:

print(result)

print(result[0], result[1], result[2])

运行结果:

[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风'), ('/4.mp3', 'beyond', '光辉岁月'), ('/5.mp3', '陈慧琳', '记事本'), ('/6.mp3', '邓丽君', '但愿人长久')]

('/2.mp3', '任贤齐', '沧海一声笑')

/2.mp3 任贤齐 沧海一声笑

('/3.mp3', '齐秦', '往事随风')

/3.mp3 齐秦 往事随风

('/4.mp3', 'beyond', '光辉岁月')

/4.mp3 beyond 光辉岁月

('/5.mp3', '陈慧琳', '记事本')

/5.mp3 陈慧琳 记事本

('/6.mp3', '邓丽君', '但愿人长久')

/6.mp3 邓丽君 但愿人长久

可以看到,返回的list的每个元素都是tuple类型,我们用对应的索引依次取出即可。

所以,如果只是获取第一个内容,可以用search()方法,当需要提取多个内容时,就可以用findall()方法。

sub()

正则表达式除了提取信息,我们有时候还需要借助于它来修改文本,比如我们想要把一串文本中的所有数字都去掉,如果我们只用字符串的replace()方法那就太繁琐了,在这里我们就可以借助于sub()方法。

我们用一个实例来感受一下:

import re

content = '54aK54yr5oiR54ix5L2g'

content = re.sub('d+', '', content)

print(content)

运行结果:

aKyroiRixLg

在这里我们只需要在第一个参数传入d+来匹配所有的数字,然后第二个参数是替换成的字符串,要去掉的话就可以赋值为空,第三个参数就是原字符串。

得到的结果就是替换修改之后的内容。

那么在上面的HTML文本中,如果我们想正则获取所有

节点的歌名,如果直接用正则表达式来提取可能比较繁琐,比如可以写成这样子:
results = re.findall('
s?()?(w+)()?s?', html, re.S)

for result in results:

print(result[1])

运行结果:

一路上有你

沧海一声笑

往事随风

光辉岁月

记事本

但愿人长久

但如果我们借助于sub()函数就比较简单了,我们可以先用sub()函数将节点去掉,只留下文本,然后再利用findall()提取就好了。

12be9d1c4be4036908d3cb4a06912439.png
html = re.sub('|', '', html)

print(html)

results = re.findall('

(.*?)', html, re.S)

for result in results:

print(result.strip())

运行结果:

经典老歌

经典老歌列表

一路上有你

沧海一声笑

往事随风

光辉岁月记事本

但愿人长久

一路上有你

沧海一声笑

往事随风

光辉岁月

记事本

但愿人长久

可以到标签在经过sub()函数处理后都没有了,然后再findall()直接提取即可。所以在适当的时候我们可以借助于sub()方法做一些相应处理可以事半功倍。

compile()

前面我们所讲的方法都是用来处理字符串的方法,最后再介绍一个compile()方法,这个方法可以讲正则字符串编译成正则表达式对象,以便于在后面的匹配中复用。

import re

content1 = '2016-12-15 12:00'

content2 = '2016-12-17 12:55'

content3 = '2016-12-22 13:21'

pattern = re.compile('d{2}:d{2}')

result1 = re.sub(pattern, '', content1)

result2 = re.sub(pattern, '', content2)

result3 = re.sub(pattern, '', content3)

print(result1, result2, result3)

例如这里有三个日期,我们想分别将三个日期中的时间去掉,所以在这里我们可以借助于sub()方法,sub()方法的第一个参数是正则表达式,但是这里我们没有必要重复写三个同样的正则表达式,所以可以借助于compile()函数将正则表达式编译成一个正则表达式对象,以便复用。

运行结果:

2016-12-15 2016-12-17 2016-12-22

另外compile()还可以传入修饰符,例如re.S等修饰符,这样在search()、findall()等方法中就不需要额外传了。所以compile()方法可以说是给正则表达式做了一层封装,以便于我们更好地复用。

2ca1d3bffdf8fb561ec98566e8be2993.png

到此为止,正则表达式的基本用法就介绍完毕了,后面我们会有实战来讲解正则表达式的使用,记得关注我们哦

注:python学习关注我们企鹅qun: 8393 83765 各类入门学习资料免费分享哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值