爬虫之正则表达式中级篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chengqiuming/article/details/86360099

一 通配匹配

1 点睛

基础篇中写的正则表达式其实比较复杂,出现空白字符我们就写\s匹配,出现数字我们就用\d匹配,这样的工作量非常大。其实完全没必要这么做,因为还有一个万能匹配可以用,那就是.*(点星)。其中.(点)可以匹配任意字符(除换行符),*(星)代表匹配前面的字符无限次,所以它们组合在一起就可以匹配任意字符了。有了它,我们就不用挨个字符地匹配了。

2 实战

2.1 代码

import re
# 将中间部分直接省略,全部用.*来代替,最后加一个结尾字符串就好了。
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$', content)
print(result)
print(result.group())
print(result.span())

2.2 运行结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
<_sre.SRE_Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)

2.3 说明

可以看到,group()方法输出了匹配的全部字符串,也就是说我们写的正则表达式匹配到了目标字符串的全部内容;span()方法输出(0, 41),这是整个字符串的长度。

因此,我们可以使用.*简化正则表达式的书写。

二 贪婪与非贪婪贪

1 贪婪匹配

1.1 代码

import re

content = 'Hello 1234567 World_This is a Regex Demo'
# 我们想获取中间的数字1234567,所以中间依然写的是(\d+)。
# 而数字两侧由于内容比较杂乱,所以想省略来写,都写成 .*。
# 最后,组成^He.*(\d+).*Demo$,看样子并没有什么问题。
result = re.match('^He.*(\d+).*Demo$', content)
print(result)
print(result.group(1))

1.2 结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7

1.3 说明

奇怪的事情发生了,我们只得到了7这个数字,这是怎么回事呢?

这里就涉及一个贪婪匹配与非贪婪匹配的问题了。在贪婪匹配下,.*会匹配尽可能多的字符。正则表达式中.*后面是\d+,也就是至少一个数字,并没有指定具体多少个数字,因此,.*就尽可能匹配多的字符,这里就把123456匹配了,给\d+留下一个可满足条件的数字7,最后得到的内容就只有数字7了。

2 非贪婪匹配

2.1 点睛

非贪婪匹配的写法是.*?,多了一个?

2.2 代码

import re

content = 'Hello 1234567 World_This is a Regex Demo'
# 只是将第一个.*改成了.*?,转变为非贪婪匹配。
result = re.match('^He.*?(\d+).*Demo$', content)
print(result)
print(result.group(1))

2.3 运行结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567

2.4 说明

此时就可以成功获取1234567了。原因可想而知,贪婪匹配是尽可能匹配多的字符,非贪婪匹配就是尽可能匹配少的字符。当.*?匹配到Hello后面的空白字符时,再往后的字符就是数字了,而\d+恰好可以匹配,那么这里.*?就不再进行匹配,交给\d+去匹配后面的数字。所以这样.*?匹配了尽可能少的字符,\d+的结果就是1234567了。

所以说,在做匹配的时候,字符串中间尽量使用非贪婪匹配,也就是用.*?来代替.*,以免出现匹配结果缺失的情况。

3 注意

3.1 代码

import re

content = 'http://weibo.com/comment/kEraCN'
result1 = re.match('http.*?comment/(.*?)', content)
result2 = re.match('http.*?comment/(.*)', content)
print('result1', result1.group(1))
print('result2', result2.group(1))

3.2 结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
result1
result2 kEraCN

3.3 说明

可以观察到,.*?没有匹配到任何结果,而.*则尽量匹配多的内容,成功得到了匹配结果。

如果匹配的结果在字符串结尾,.*?就有可能匹配不到任何内容了,因为它会匹配尽可能少的字符。

三 修饰符

1 一个错误例子

1.1 代码

import re

content = '''Hello 1234567 World_This
is a Regex Demo
'''
# content换行了,我们依然想匹配中间的1234567,看是否可以匹配
result = re.match('^He.*?(\d+).*?Demo$', content)
print(result.group(1))

1.2 结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
result1
Traceback (most recent call last):
  File "E:/WebSpider/3_3.py", line 70, in <module>
result2 kEraCN
    print(result.group(1))
AttributeError: 'NoneType' object has no attribute 'group'

1.3 说明

运行直接报错,也就是说正则表达式没有匹配到这个字符串,返回结果为None,而我们又调用了group()方法导致AttributeError。

那么,为什么加了一个换行符,就匹配不到了呢?这是因为\.匹配的是除换行符之外的任意字符,当遇到换行符时,.*?就不能匹配了,所以导致匹配失败。

2 错误修正

2.1 代码

import re

content = '''Hello 1234567 World_This
is a Regex Demo
'''
# content换行了,我们依然想匹配中间的1234567,看是否可以匹配
# result = re.match('^He.*?(\d+).*?Demo$', content)
# 只需加一个修饰符re.S,即可修正这个错误,
# 这个修饰符的作用是使.匹配包括换行符在内的所有字符。
result = re.match('^He.*?(\d+).*?Demo$', content, re.S)
print(result.group(1))

2.2 运行结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
1234567

2.3 说明

这个re.S在网页匹配中经常用到。因为HTML节点经常会有换行,加上它,就可以匹配节点与节点之间的换行了。

3 常见修饰符

修饰符

描述

re.I

使匹配对大小写不敏感

re.L

做本地化识别(locale-aware)匹配

re.M

多行匹配,影响^和$

re.S

使.匹配包括换行在内的所有字符

re.U

根据Unicode字符集解析字符。这个标志影响\w、\W、 \b和\B

re.X

该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解

在网页匹配中,较为常用的有re.S和re.I

四 转义匹配

1 代码

import re

content = '(百度)www.baidu.com'
# 当遇到用于正则匹配模式的特殊字符时,在前面加反斜线转义一下即可。
# 例如.就可以用\.来匹配,(可以用\(来匹配
result = re.match('\(百度\)www\.baidu\.com', content)

2 结果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_3.py
<_sre.SRE_Match object; span=(0, 17), match='(百度)www.baidu.com'>

3 说明

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

猜你喜欢

转载自blog.csdn.net/chengqiuming/article/details/86360099