网络爬虫笔记—正则表达式(re库)

网络爬虫笔记—正则表达式(re库)

1、正则表达式中各字符代表的含义

字符 描述
\ 将后面一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n"表示匹配字符"n”;“\n"表示匹配一个换行符;”\(“表示匹配”("。
^ 匹配输入字符串的开始位置(字符串开头需要有^后面的字符)。
$ 匹配输入字符串的结束位置(字符串末尾需要有$前面的字符)。
* 匹配前面的子表达式零次或多次。例如,"zo*“能匹配"z"以及"zoo”。
+ 匹配前面的子表达式一次或多次。例如,“zo+“能匹配"zo"以及"zoo”,但不能匹配"z”。
? 匹配前面的子表达式零次或一次。例如,"do(es)?“可以匹配"do"或"does"中的"do”。
{n} n是一个非负整数。匹配确定的n次。例如,"o{2}“不能匹配"Bob"中的"o”,但是能匹配"food"中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,"o{2,}“不能匹配"Bob"中的"o”,但能匹配"foooood"中的所有o。
{n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,"o{1,3}"将匹配"fooooood"中的前三个o。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串"oooo","o+?“将匹配单个"o”,而"o+“将匹配所有"o”。
. 匹配除"\n"(换行符)之外的任何单个字符。要匹配包括"\n"在内的任何字符,请使用象"[.\n]"的模式。
(pattern) 匹配pattern(是指正则表达式)并获取这一匹配。
x|y 匹配x或y。例如,“z|food"能匹配"z"或"food”。“(z|f)ood"则匹配"zood"或"food”。
[xyz] 字符集合。匹配所包含的任意一个字符。例如,"[abc]“可以匹配"plain"中的"a”。
[^xyz] 负值字符集合。表示非得意思。匹配未包含的任意字符。例如,"[abc]“可以匹配"plain"中的"p”。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,"[a-z]"可以匹配"a"到"z"范围内的任意小写字母字符。
[^a-z] 负值字符范围。表示非得意思。匹配任何不在指定范围内的任意字符。例如,"[a-z]"可以匹配任何不在"a"到"z"范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b"可以匹配"never"中的"er”,但不能匹配"verb"中的"er"。
\B 匹配非单词边界。“er\B"能匹配"verb"中的"er”,但不能匹配"never"中的"er"。
\cx 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的"c"字符。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c和\cL。
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。
\S 匹配任何非空白字符。等价于[^\f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09和\cI。
\v 匹配一个垂直制表符。等价于\x0b和\cK。
\w 匹配包括下划线的任何单词字符。等价于"[A-Za-z0-9_]"。
\W 匹配任何非单词字符。等价于"[^A-Za-z0-9_]"。

2、match匹配

运用match方法进行匹配,文本的开头就需要与编写的正则表达式相匹配。如果只是文本中间部分匹配,则无法成功匹配。

import re
content = "Hello welcome to HIMACROSPIDER,I was founded in 2020.Thanks"
#match的第一个参数是正则表达式,第二个参数是需要解析的文本
result = re.match("Hello[a-zA-Z\s,\.]*(\d*)[a-zA-Z\s,\.]*",content)
print("result的返回结果:",result)
print("result.group()的返回结果:",result.group())
print("result.group(1)的返回结果:",result.group(1))
print("result.span()的返回结果:",result.span())

输出结果:

result的返回结果: <re.Match object; span=(0, 59), match='Hello welcome to HIMACROSPIDER,I was founded in 2>
result.group()的返回结果: Hello welcome to HIMACROSPIDER,I was founded in 2020.Thanks
result.group(1)的返回结果: 2020
result.span()的返回结果: (0, 59)
函数/方法 作用
re.match() 返回的是一个对象,如果没有匹配结果,返回的是None。当返回值为None时,调用group方法会报错。
re.match().group() 返回的是完整匹配结果。
re.match().group(1) group(1)里面加数字,则返回的是正则表达式中括号里面的匹配结果。1表示返回第一个括号中的结果,2表示返回第二个括号中的结果…
re.match().span() 返回的是匹配的范围,即从第几个字符开始匹配,第几个字符停止匹配
import re
content = "Hello welcome to HIMACROSPIDER,I was founded in 2020.Thanks"
#将正则表达式第一个字母H去掉,看一下返回结果
result = re.match("ello[a-zA-Z\s,\.]*(\d*)[a-zA-Z\s,\.]*",content)
print("result的返回结果:",result)

输出结果:

result的返回结果: None

将正则表达式的第一个字母H去掉以后,可以发现返回的结果为None。这也就验证了,当通过match方法匹配时,只有当开头的正则表达式和文本的开头相匹配时,才会匹配出结果。如果开头不符合正则表达式要求,则不能匹配出结果。

3、贪婪匹配和非贪婪匹配

import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match("^He.*(\d+).*Demo$",content)
print(result.group(1))
#输出结果为7

我们想获取字符中的1234567这7个数字,但是从返回结果来看,只返回了一个数字7,这不是我们想要的结果。这是因为正则表达式在匹配时发生了贪婪匹配。“^He.*” 这一部分正则表达式对应匹配了"Hello 123456",而括号中的"\d+“只匹配到了一个数字7。当发生贪婪匹配时,如果某一处字符串有多处既符合前面的正则表达式又符合后面的正则表达式,这时前面的正则表达式就会尽力匹配全部符合结果的字符,而只给后面一个正则表达式留一个符合要求的字符。为了能够正常获取全部数字,我们需要运用非贪婪匹配,非贪婪匹配只需要在”.*“加一个”?"即可。

import re
content = "Hello 1234567 World_This is a Regex Demo"
result = re.match("^He.*?(\d+).*Demo$",content)
print(result.group(1))
#输出结果为1234567

运用非贪婪匹配后,返回字符串中的全部数字。当使用非贪婪匹配时,".*"会匹配尽可能少的字符,而将字符留给后面的正则表达式去匹配。非贪婪匹配一般只在正则表达中间使用,如在正则表达式结尾使用,则可能出现匹配不到结果的情况。

4、修饰符

import re
content = """Hello 1234567 World_This
is a Regex Demo"""
result = re.match("^He.*?(\d+).*Demo$",content)
print(result.group(1))

输出结果:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [42], in <cell line: 5>()
      2 content = """Hello 1234567 World_This
      3 is a Regex Demo"""
      4 result = re.match("^He.*?(\d+).*Demo$",content)
----> 5 print(result.group(1))

AttributeError: 'NoneType' object has no attribute 'group'

和前面的例子一样,我们只是在文本中加了一个换行符,正则表达式都是一样的,但是就无法匹配到结果了。这是因为".*?"只能匹配到换行符以外的其他字符,当我们在文本加入换行符后,就不能进行正常匹配了。这时需要加一个修饰符re.S,进行修饰,这样便能正常进行匹配。

import re
content = """Hello 1234567 World_This
is a Regex Demo"""
result = re.match("^He.*?(\d+).*Demo$",content,re.S)
print(result.group(1))
#输出结果为1234567

加过修饰符之后,可以正常返回数字。这个修饰符的作用是使"."匹配包括换行符在内的所有字符。在实际使用中还有其他修饰符:

修饰符 描述
re.I 使匹配对大小写不敏感,即将大写字母和小写字母等同于同一个字母
re.L 做本地化识别( locale-aware )匹配
re.M 多行匹配,影响^和$
re.S 使"."匹配包括换行符在内的所有字符
re.U 根据 Unicode字符集解析字符。这个标志影响\w、\W、\b和\B
re.X 该标志通过给予你更灵活的格式以便你将正 表达式写得更易于理解

5、search匹配

match匹配是从字符串的开头匹配,如果开头不匹配那么整个匹配就会失败。有时我们需要匹配的结果在字符串中间,这时就需要用到search匹配。search匹配会扫描整个字符串,并返回第一个成功匹配的结果。search匹配最多只能匹配一个结果。

import re
content = "Extra thing Hello 1234567 World_This is a Regex Demo"
match_result = re.match("He.*?(\d+).*Demo$",content,re.S)
search_result = re.search("He.*?(\d+).*Demo$",content,re.S)
print("match的匹配结果为:",match_result)
print("search的匹配结果为:",search_result)
print("search中正则表达式括号中的值:",search_result.group(1))

输出结果:

match的匹配结果为: None
search的匹配结果为: <re.Match object; span=(12, 52), match='Hello 1234567 World_This is a Regex Demo'>
search中正则表达式括号中的值: 1234567

由于match匹配需要从开头匹配,而正则表达式的开头为"He",文本的开头为"Ex"所以匹配结果为None。search会扫描整个字符串,并返回符合要求的第一个结果,所以search可以成功匹配数据。

6、findall匹配

search匹配只能匹配第一个结果,而如果想要匹配所有满足条件的结果,这时就需要用到findall匹配。findall匹配会扫描整个字符串并返回所有满足正则表达式结果的内容。

import re
content = "Extra thing Hello 1234567 World_This is a Regex Demo 7654321"
#匹配文本中的数字
search_result = re.search("\d+",content,re.S)
findall_result = re.findall("\d+",content,re.S)
print("search的匹配结果为:",search_result.group())
print("findall的匹配结果为:",findall_result)#返回的是一个列表
print("findall的匹配的第一个结果:",findall_result[0])#返回的是一个列表

输出结果:

search的匹配结果为: 1234567
findall的匹配结果为: ['1234567', '7654321']
findall的匹配的第一个结果: 1234567

search只能匹配第一个满足要求的结果,所以search只返回了一组数据。findall可以查找所有满足正则表达要求的内容,所以以列表的形式返回了两组数据。

7、sub文本替换

sub方法可以将字符串中满足正则表达式规则的文本替换成所需文本。

import re
content = "Extra thing Hello 1234567 World_This is a Regex Demo 7654321"
#将文本中的数字替换成himacrospider
aftercontent = re.sub("\d+","himacrospider",content)
print("替换前的文本:",content)
print("替换后的文本:",aftercontent)

输出结果:

替换前的文本: Extra thing Hello 1234567 World_This is a Regex Demo 7654321
替换后的文本: Extra thing Hello himacrospider World_This is a Regex Demo himacrospider

使用sub方法成功的将字符串中的数字转化成了"himacrospider"。sub方法一共有三个参数,第一个参数为需要匹配的字符串规则,第二个参数为替换成的字符串,第三个参数为原文本(需要处理的文本内容)。

8、compile方法

从上面的例子中我们可以发现对于正则表达式规则,我们会在后面的代码中经常使用该正则表达式规则,为了方便正则表达式的复用,可以用compile方法将正则表达式封装,这样便可以重复引用。

import re
content = "Extra thing Hello 1234567 World_This is a Regex Demo 7654321"
pattern = re.compile("\d+",re.S)
aftercontent = re.sub(pattern,"himacrospider",content)
print("替换前的文本:",content)
print("替换后的文本:",aftercontent)

输出结果:

替换前的文本: Extra thing Hello 1234567 World_This is a Regex Demo 7654321
替换后的文本: Extra thing Hello himacrospider World_This is a Regex Demo himacrospider

使用compile方法封装后,得到的结果与封装前相同

  • 本文章,首发于微信公众号:宏蜘蛛,原文链接:网络爬虫笔记—正则表达式(re库)

—End—

参考资料:

1、《Python3网络爬虫开发实战》_崔庆才

2、正则表达式中各种字符的含义_给你取暖的博客-CSDN博客_正则表达式符号含义

你可能感兴趣的:(正则表达式,爬虫)