「一往直前,就是光明」
正则表达式
前言
学习完爬虫网络请求模块之后,同学们基本上对爬虫已经有了一个浅显的认知了。爬虫、爬虫,肯定是要爬取数据。不管是网页端的数据又或者是移动端的数据。数据的类型有很多,诸如文字、图片、音频、视频…等等。我们爬取数据还是有特定的目标以及主题的。这个时候就要对数据进行筛选和解析。后面的章节会针对于这一块的内容来进行讲解,今天先介绍其中的一种方式「正则表达式」。当然我们还是以初学者的角度进行出发,以浅显易懂的方式来介绍知识点,降低学习的门槛。
正则表达式的简介
正则表达式的概念
那么究竟什么是正则表达式呢?在网络上看了很多概念。都是比较官方,不太容易理解。下面是「百度百科」对正则表达式的一段描述。
❝
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本
❞
读完之后,相信很多小伙伴就是一脸问号。感觉这个东西非常玄幻
那我们该如何理解呢? 正则表达式就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对其它字符串的一种逻辑过滤
下面有一幅图,左边是一堆苹果(数据)。我们都知道苹果是有大有小,规格不一的。大的苹果通常情况下都会比小的苹果卖的价格高一些。这个时候我们怎么把这一堆的苹果按照70 80 90这3种规格进行区分呢?其实也不难,我们只需要有一个测量苹果规格的尺子(正则表达式)。通过这个尺子,我们就可以把不同规格的苹果进行过滤了。最后把满足要求的苹果进行区分。这种现实生活中的场景,就是一种数据的逻辑过滤。把符合要求的数据通过正则表达式找到,不符和要求的数据就过滤掉了
正则表达式的应用场景
- 表单验证(例如 : 手机号、邮箱、身份证….)
- 爬虫
现在有很多软件都需要我们填写一些身份信息。例如手机号、身份证等等。那么这些功能在开发的时候,可以通过一些业务逻辑来实现,同样也可以同过正则表达式的方式来开发这些业务需求。第二个就是爬虫了。爬虫爬取的数据有很多,在解析提取数据这块就可以用到正则表达式来获取我们想要的数据了。
Python对正则表达式的支持
普通字符
字母、数字、汉字、下划线、以及没有特殊定义的符号,都是「普通字符」
表达式中的普通字符,在匹配的时候,只匹配与自身相同的一个字符。 例如:表达式a,在匹配字符串abcde时,匹配结果是:成功;匹配到的内容是a.匹配到的位置开始于0,结束于1。(注:下标从0开始)
咱们这块通过一个match()方法来举例
# match(pattern, string, flags=0)
# 第一个pattern 正则表达式 如果匹配成功 返回一个match对象 如果匹配失败返回一个None
# 第二个string 表示要匹配的字符串
# 第三个flags=0 标致位 用于控制正则表达式的匹配方式 如 是否区分大小写 是否换行匹配
pattern = 'a'
s = 'abcde'
result = re.match(pattern,s)
if result:
print(result.group())
else:
print('没有匹配到数据')
执行结果
元字符
正则表达式中使⽤了很多元字符,⽤来表示⼀些特殊的含义或功能
表达式 | 匹配 |
---|---|
. | 小数点可以匹配除了换行符(\n)以外的任意一个字符 |
I | 逻辑或操作符 |
[] | 匹配字符集中的一个字符 |
[^] | 对字符集求反,也就是上面的反操作 |
– | 定义[]里面的一个字符区间 例如[a-z] |
\ | 对紧跟其后的一个字符进行转义 |
() | 对表达式进行分组,将圆括号内的内容当做一个整体,并获得匹配的值 |
import re
print(re.match(r'a.c','abc').group()) # abc
print(re.match(r'a|c','a').group()) # a
print(re.match(r'[abc]','a').group()) # a
print(re.match(r'[^abc]','w').group()) # w
print(re.match(r'[a-z]','w').group()) # w
转义字符
一些无法书写或者具有特殊功能的字符,采用在前面加斜杠 \ 进行转义的方法
表达式 | 匹配 |
---|---|
\n | 匹配换行符 |
\t | 匹配制表符 |
\\ | 匹配斜杠 \ |
\^ | 匹配^符合 |
\$ | 匹配$符合 |
\. | 匹配小数. |
预定义匹配字符集
正则表达式中的一些表示方法,可以同时匹配某个预定义字符集中的任意一个字符。比如,表达式\d可以匹配任意一个数字。虽然可以匹配其中任意字符,但是只能是一个,不是多个
表达式 | 匹配 |
---|---|
\d | 匹配0-9中任意一个数字 |
\w | 匹配0-9,a-z,A-Z,_,中任意一个数字或字母或下划线 |
\s | 匹配空格,制表符,换页符,等空白字符的其中任意一个 |
\D | \d的反集 也就是匹配非数字的任意一个 |
\W | \w的反集 |
\S | \s的反集 |
import re
print(re.match(r'\d','123').group()) # 1
print(re.match(r'\w','a123').group()) # a
print(re.match(r'\s',' ').group()) # ' '
print(re.match(r'\D','a123').group()) # a
重复匹配
前面的表达式,无论是只能匹配一种字符的表达式,还是可以匹配多种字符其中任意一个的表达式,都只能匹配一次。但是有时候我们需要对某个字段进行重复匹配,例如手机号码「13666666666」,一般的新手可能会写成\d\d\d\d\d\d\d\d\d\d\d(注意,这不是一个恰当的表达式),不但写着费劲,看着也累,还不⼀定准确恰当。 这种情况可以使用表达式再加上修饰匹配次数的特殊符号{},不用重复书写表达式就可以重复匹配。例如[abcd][abcd]可以写成[abcd]{2}
表达式 | 匹配 |
---|---|
{n} | 表达式重复n次 例如\d{2}等价于 \d\d |
{m,n} | 表达式至少重复m次,最多重复n次 |
{m,} | 表达式至少可以重复m次 |
? | 表达式0次或者1次 相当于 {0,1} |
+ | 表达式至少出现1次 相当于 {1,} |
* | 表达式 出现0次到任意次 相当于 {0,} |
import re
print(re.match(r'\d{3}','123').group()) # 123
print(re.match(r'\d{3,4}-\d{7,8}','0123-1234567').group()) # 0123-1234567
print(re.match(r'\d{3,}-\d{7,8}','0123456-1234567').group()) # 0123456-1234567
print(re.match(r'w[a-z]?','weabc').group()) # we
print(re.match(r'w[a-z]+','weabc').group()) # weabc
html_content = '''asfdsfdsf fdsfdsf fdfdf sfds fdf fdf fdf '''
print(re.match(r'.*',html_content).group()) # asfdsfdsf
# 添加一个匹配方式匹配换行 re.S 这样就可以匹配换行的数据了
print(re.match(r'.*',html_content,re.S).group())
看到这里不知道大家是否感觉还好,脑子犯迷糊的同学可以适当的休息一下。抽抽烟,看看远处的天空,吸收一下新鲜的空气(当然现在的空气…)以上的代码,只是列举了部分功能,更多的还是需要同学们自己去实践一下。
位置匹配
有时候,我们对匹配出现的位置有要求,比如开头、结尾、单词之间等等
表达式 | 匹配 |
---|---|
^ | 在字符串开始的地方匹配,符合本身不匹配任何字符 |
$ | 在字符串结束的地方匹配,符合本身不匹配任何字符 |
\b | 匹配一个单词边界,也就是单词和空格之间的位置,符合本身不匹配任何字符 |
\B | 匹配非单词边界,即左右两边都是\w范围或者左右两边都不是\w范围时的字符缝隙 |
后面两个的位置匹配用的不多,有兴趣的同学可以自行拓展一下。
非贪婪匹配
「贪婪匹配」会一直匹配到最后,以最长的结果作为返回。但是很多时候我们并不需要所有你匹配到的数据,所以一般我们会采用到「非贪婪匹配」的模式
在Python里数量词默认是贪婪的,总是尝试匹配尽可能多的字符。非贪婪则相反,总是尝试匹配尽可能少的字符 我们可以「在 * + {m,n} 后面加上 ?」 使贪婪变成非贪婪
import re
# 贪婪匹配
s = r'<div>abc</div><div>bcd</div><div>bcd</div>'
# 需求匹配<div>abc</div>
ptn = '<div>.*</div>'
r = re.match(ptn,s)
print(r.group()) # <div>abc</div><div>bcd</div><div>bcd</div>
s = r'<div>abc</div><div>bcd</div><div>bcd</div>'
# 需求匹配<div>abc</div>
ptn = '<div>.*?</div>'
r = re.match(ptn,s)
print(r.group()) # <div>abc</div>
re模块常用的方法
方法 | 描述 | 返回值 |
---|---|---|
compile(pattern[,flags]) | 根据包含正则表达式的字符串创建模式对象 | re对象 |
search(pattern,string[,flags]) | 在字符串中查找 | 第一个匹配到的对象或者None |
match(pattern,string[,flags]) | 在字符串的开始处匹配模式 | 在字符串开头匹配到的对象或者None |
split(pattern,string[,maxsplit=0,flags]) | 根据模式的匹配项来分割字符串 | 分割后的字符串列表 |
sub(pattern,rel,string[,count=0,flags]) | 将字符串中所有的pattern的匹配项用rel替换 | 完成替换后的新字符串 |
import re
print(re.search(r'abc','123abc567abc').group()) # abc
print(re.findall(r'abc','123abc567abc').group()) # ['abc','abc']
s = 'i am jack i am ten years old'
print(re.sub(r'i','I',s)) # I am jack I am ten years old
分组功能
Python的re模块有⼀个分组功能。所谓的分组就是去已经匹配到的内容⾥⾯再筛选出需要的内容,相当于⼆次过滤。实现分组靠圆括号(),⽽获取分组的内容靠的是group()、groups()
# 需求匹配下面数据的价格 $99 $88
import re
s = 'banana price is $99,lemon price is $88'
result = re.search('.+(\$\d+).+(\$\d+)',s)
print(result.group(0)) # apple banana is $99,lemon price is $88
print(result.group(1)) # $99
print(result.group(2)) # $88
print(result.groups()) # ('$99', '$88')
好啦,正则表达式博大精深很多语言都可以使用,我们现在能够掌握以上的内容基本在爬虫上面是够用了。如果有同学对于正则表达式有更高的追求,也可以在去往深层去拓展。下一篇将继续数据解析的学习「xpath and lxml」
今天的文章Python爬虫企业级开发05篇分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18298.html