python爬虫之正则表达式(二)
在《python爬虫之正则表达式(一)》文章中,我们介绍了正则表达式的应用场景以及普通字符、元字符、预定义匹配字符集和重复匹配。在本篇博文中,我们将续上文,re模块常用方法、分组功能,以及最后进行一些练习。
1 re模块常用方法
- compile(pattern, flags=0)
(1)这个方法是 re 模块的工厂法,用于将字符串形式的正则表达式编译为 Pattern 模式对象,可以实现更加效率的匹配,第⼆个参数 flag 是匹配模式。
(2)使用 compile()完成⼀次转换后,再次使用该匹配模式的时候就不能进行转换了。经过compile() 转换的正则表达式对象也能使⽤普通的 re 方法。
import re
# compile:正则表达式的模式 re.compile(pattern='',flags='')
ptn = re.compile(r'abc')
print(ptn.match('abc123').group()) # abc
ptn = re.compile(r'abc',re.I) # 不区分大小写
print(ptn.match('ABC123').group()) # ABC
- search(pattern, string, flags=0)
(1)在文本内查找,返回第⼀个匹配到的字符串。它的返回值类型和使用方法与match() 是⼀样的。
(2)唯⼀的区别就是查找的位置不用固定在文本的开头
# search:类似于match,从任意位置查找 re.search(pattern='',string='',flags='')
print(re.search(r'abc','123abc567abc789').group()) # abc
# match: re.match(pattern='',string='',flags='')
print(re.match(r'abc','abc567abc789').group()) # abc
- findall(pattern, string, flags=0
(1)作为 re 模块的三大搜索函数之⼀, findall() 和 match() 、 search() 的不同之处在于,前两者都是单值匹配,找到⼀个就忽略后⾯,直接返回不再查找了。而findall 是全文查找,它的返回值是⼀个匹配到的字符串的列表。
(2)这个列表没有group() 方法,没有 start 、 end 、 span ,更不是⼀个匹配对象,仅仅是个列表!
如果⼀项都没有匹配到那么返回⼀个空列表
# findall: re.findall(pattern=,string=,flags=) 以列表形式返回
print(re.findall(r'\d+','8+7*5+6/3')) # ['8', '7', '5', '6', '3']
print(re.findall(r'ABC','123abc567abc789',re.I)) # ['abc', 'abc']
(2)无分组
'''
无分组:匹配所有合规则的字符串,匹配到的字符串放到一个列表中
注意:正则匹配到空字符的情况,如果规则里只有一个组,而组后面是*就表示组里的内容可以是0个或者多个
这样组里就有了两个意思,一个意思是匹配组里的内容,二个意思是匹配组里0内容(即是空白)所以尽量避免用*否则会有可能匹配出空字符串
否则就会出现例子2
'''
import re
#无分组 例子1
#!/usr/bin/env python
# -*- coding:utf8 -*-
import re
#无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("a\w+", origin) #浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中
print(r)
#输出结果
#['alex', 'alex', 'alex', 'acd'] #匹配所有合规则的字符串,匹配到的字符串放到一个列表中表
#无分组 例子2
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("(a)*", origin)
print(r)
#输出结果 ['', '', '', '', '', '', 'a', '', '', '', '', '', '', '', '', 'a', '', '', '', '', '', '', '', '', 'a', '', '', '', '', 'a', '', '', '', '', '', '']
(3)有分组
'''
有分组:只将匹配到的字符串里,组的部分放到列表里返回,相当于groups()方法
'''
import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("a(\w+)", origin) #有分组:只将匹配到的字符串里,组的部分放到列表里返回
print(r)
#输出结果 #['lex', 'lex', 'lex', 'cd']
(4)多个分组
'''
多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返
相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回
'''
import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("(a)(\w+)", origin) #多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返回
print(r)
#输出结果
#[('a', 'lex'), ('a', 'lex'), ('a', 'lex'), ('a', 'cd')]
(5)分组中有分组
'''
分组中有分组:只将匹配到的字符串里,组的部分放到一个元组中,
将包含有组的组,看作一个整体也就是一个组,放入一个元组里
然后再把组里的组放入一个元组,最后将所有组放入一个列表返回
'''
import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("(a)(\w+(e))", origin) #分组中有分组:只将匹配到的字符串里,组的部分放到一个元组中,先将包含有组的组,看作一个整体也就是一个组,把这个整体组放入一个元组里,然后在把组里的组放入一个元组,最后将所有组放入一个列表返回
print(r)
#输出结果
#[('a', 'le', 'e'), ('a', 'le', 'e'), ('a', 'le', 'e')]
(6)?:
'''
?: :在有分组的情况下findall()函数,不只拿分组里的字符串,拿所有匹配到的字符串
注意?: :只用于不是返回正则对象的函数如findall()
'''
import re
origin = "hello alex bcd alex lge alex acd 19"
b = re.findall("a(?:\w+)",origin) #?:在有分组的情况下,不只拿分组里的字符串,拿所有匹配到的字符串
# 注意?:只用于不是返回正则对象的函数如findall() 返回的是列表
print(b)
#输出
# ['alex', 'alex', 'alex', 'acd']
注意:(3)-(5)参考博文re模块中常用功能函数。这篇博文写得很详细,推荐学习
- split(pattern, string, maxsplit=0, flags=0)
(1)re 模块的 split() 方法和字符串的 split() 方法很相似,都是利用特定的字符去分割字符串。但是 re 模块的 split() 可以使用正则表达式,因此更灵活,更强大。
(2)split 有个参数 maxsplit ,用于指定分割的次数
# spilt: 分割 re.split(pattern='',string='',maxsplit=,flags=) pattern是按照什么分割,string是分割的内容,max是分割最多次数,flag是分割模式
print(re.split(r'[+*\-\/]','5+3*2/1')) # ['5', '3', '2', '1']
print(re.split(r'[+*\-\/]','5+3*2/1',maxsplit=2)) # ['5', '3', '2/1']
- sub(pattern, repl, string, count=0, flags=0)
sub()方法类似字符串的 replace() 方法,用指定的内容替换匹配到的字符,可以指定替换次数
# sub: re.sub(pattern=,repl=,string=,count=0,flags=)
print(re.sub('abc','124','abcEDabc',count=1,flags=re.I)) # 124EDabc
print(re.sub('abc','124','abcEDabcabc',count=0,flags=re.I)) # 124ED124124 全部替换
print(re.sub('abc','124','abcEDabcABC',count=0,flags=re.I)) # 124ED124124 全部替换 不区分大小写
2 分组功能
Python 的 re 模块有⼀个分组功能。
- 所谓的分组就是去已经匹配到的内容再筛选出需要的内容,相当于二次过滤。==实现分组靠圆括号 () ==。
- 而获取分组的内容靠的是 group() 、 groups() ,其实前面我们已经展示过。
# 分组
import re
# 需求是匹配到 $88 $55
text = 'apple price is $88,orange price is $55'
r = re.search('.(\d+).+(\$\d+)',text)
print(r.group(0)) # apple price is $88,orange price is $55
print(r.groups()) # ('$88', '$55')
print(r.group(1)) # $88
print(r.group(2)) # $55
result = r.groups()
print(type(result)) # <class 'tuple'>
# 需求匹配到数字
text = 'abc123cde456'
r = re.search('[a-z]+([0-9]+)[a-z]+([0-9]+)',text)
print(r.group(0)) # apple price is $88,orange price is $55
print(r.groups()) # ('123', '456')
print(r.group(1)) # 123
print(r.group(2)) # 456
result = r.groups()