网络爬虫 | 正则表达式
Posted 数据STUDIO
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络爬虫 | 正则表达式相关的知识,希望对你有一定的参考价值。
正则表达式中匹配与查找
正则表达式,简称为regex
,是文本模式的描述方法。
>>> import re
>>> pattern = re.compile('\d\d\d-\d\d\d-\d\d\d\d')
>>> phone=pattern.search('Call me at 415-555-1011 tomorrow')
>>> phone.group() #通过group返回匹配的结果
'415-555-1011'
compile()
Python中所有正则表达式的函数都在re模块中,向re.compile()
传入一个字符串值,表示正则表达式,它将返回一个regex模式对象。
regex对象
的search()方法
查找传入的字符串,寻找该正则表达式的所有匹配。
如果字符串中没有找到该正则表达式模式,search()方法
将返回None
。如果找到了该模式,search()方法
将返回一个match对
。
re.compile(pattern[, flags])
pattern : 一个字符串形式的正则表达式
flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I
忽略大小写re.L
表示特殊字符集\w, \W, \b, \B, \s, \S
依赖于当前环境re.M
多行模式re.S
即为' . '
并且包括换行符在内的任意字符(' . '
不包括换行符)re.U
表示特殊字符集\w, \W, \b, \B, \d, \D, \s, \S
依赖于 Unicode 字符属性数据库re.X
为了增加可读性,忽略空格和' # '
后面的注释
search()
另一种方法,直接使用re.search()方法
,扫描整个字符串并返回第一个成功的匹配。
re.search(pattern, string, flags=0)
pattern: 匹配的正则表达式转换而来的字符串。
string: 要匹配的字符串。
flags: 可选参数,标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
group()
search对象
可以使用group(num) 或 groups() 匹配对象函数
来获取匹配表达式,它返回被查找字符串中实际匹配的文本。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,可以取得匹配文本的不同部分,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
(\d\d\d)-(\d\d\d-\d\d\d\d)
,然后可以使用group()匹配对象方法
,从一个分组中获取匹配的文本。第一对括号是第1组。第二对括号是第2组。
>>> pattern = ('(\d\d\d)-(\d\d\d-\d\d\d\d)')
>>> phone=re.search(pattern,'Call me at 415-555-1011 tomorrow')
>>> phone.group(0)#返回所有匹配的文本
'455-555-1011'
>>> phone.group(1)#返回第一个括号内容
'455'
>>> phone.group(2)#返回第二个括号内容
'555-1011'
>>> phone.groups()#返回的是元组
('455', '555-1011')
用管道匹配多个分组
字符|
称为"管道"。希望匹配许多表达式中的一个时,就可以使用它。例如,正则表达式r'Jim|云朵'将匹配'Jim'或'云朵'。如果都出现在被查找的字符串中,则匹配第一次出现的文本。
>>> pattern = (r'Jim|yunduo')
>>> match=re.search(pattern,'yunduo is the author of DATASTUDIO')
>>> match.group()#第一次出现的匹配文本
'yunduo'
用问号实现可选匹配
不论这段文本在不在,正则表达式都会认为匹配。字符?表明它前面的分组在这个模式中是可选的。
>>> pattern = re.compile(r'(\d\d\d-)?\d\d\d-\d\d\d\d')#包含或者不包含区号
>>> phone = pattern.search('My number is 415-555-1011')#有区号
>>> phone.group()
'415-555-1011'
>>> phone = pattern.search('My number is 555-1011')#有区号
>>> phone.group()
'555-1011'
用星号匹配零次或多次
-
*(称为星号)
意味着"匹配零次或多次"
,即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复。 -
+(加号)
则意味着"匹配一次或多次"
。星号不要求分组出现在匹配的字符串中,但加号不同,加号前面的分组必须"至少出现一次"。
>>> pattern = (r'DA(TA)*STUDIO')
>>> match=re.search(pattern,'DATATATATASTUDIO')
>>> match.group()
'DATATATATASTUDIO'
>>> match=re.search(pattern,'DASTUDIO')
>>> match.group()
'DASTUDIO'
>>> pattern = (r'DA(TA)+STUDIO') # 至少出现一次
>>> match=re.search(pattern,'DASTUDIO')
>>> match.group()
----------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-122-4009f4d8d45b> in <module>
1 pattern = (r'DA(TA)+STUDIO') # 至少出现一次
2 match=re.search(pattern,'DASTUDIO')
----> 3 match.group()
AttributeError: 'NoneType' object has no attribute 'group'
用花括号匹配特定次数
如果想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上花括号包围的数字。例如,正则表达式(Ha){3}
将匹配字符串'HaHaHa',但不会匹配'HaHa'
。
可以指定一个范围,即在花括号中写下一个最小值、一个逗号和一个最大值。例如,正则表达式(Ha){3,5}
将匹配'HaHaHa'、'HaHaHaHa'和'HaHaHaHaHa'
。
贪婪与非贪婪
如果需要匹配一段包含各种不同类型数据的字符串,传统方法需要挨个去匹配,而使用.*
可以匹配所有字符,是一种万能匹配的方式。
-
正则表达式默认是贪婪的,尽可能匹配最长的字符串
-
另一种为非贪婪模式:
加问号'?'
,尽可能匹配最短的字符
>>> haRegex = re.compile(r'(ha){3}')
>>> match = haRegex.search('hahahahha')
>>> match.group()
'hahaha'
>>> haRegex = re.compile(r'(ha){3,5}')
>>> match = haRegex.search('hahahahaha')#贪婪模式,尽可能长的匹配
>>> match.group()
'hahahahaha'
>>> haRegex = re.compile(r'(ha){3,5}?')
>>> match = haRegex.search('hahahahaha')#非贪婪模式,尽可能短的匹配
>>> match.group()
'hahaha'
用点'.' 星'*'
匹配所有字符
-
.
---- 匹配任意字符,除换行 -
*
---- 匹配零个或者多个表达式 -
.*
---- 匹配任意零个或者多个字符 -
.*?
---- 匹配任意零个或者多个字符,非贪婪模式
有\n 换行符
是需要用跨行匹配
-
(.,re.DOTALL)
:匹配任意字符,包括换行
# 点匹配任意一个字符
>>> regex = re.compile(r'<.>')
>>> match = regex.search('STU<D>IO')
>>> match.group()
'<D>'
# 点星匹配任意字符
>>> regex = re.compile(r'<.*>')
>>> match = regex.search('STU<loveyunduo>DIO')
>>> match.group()
'<loveyunduo>'
# 点星问号匹配任意字符, 非贪婪匹配
>>> regex = re.compile(r'<.*?>')
>>> match = regex.search('STU<loveyunduo>lovedata>DIO')
>>> match.group()
'<loveyunduo>'
#跨行匹配
>>> regex = re.compile(r'<.*>',re.DOTALL)
>>> text='''data<stu
... dio>yunduo'''
>>> match = regex.search(text)
>>> match.group()
'<stu\ndio>'
findall()方法匹配所有内容
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
re.findall(pattern, string, flags=0)
pattern.findall(string[, pos[, endpos]])
pattern 匹配模式,由要匹配的正则表达式转换而来
string 待匹配的字符串。
flags 可选参数,标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
pos 可选参数,指定字符串的起始位置,默认为 0。
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
# findall() 匹配多个,返回的是列表
regex = re.compile(r'\d+')
regex.findall('one1two2three33four4444')
['1', '2', '33', '4444']
匹配字符串边界
如果字符串在开始处、结尾处,或者字符串的分界符为空格、标点符号以及换行,可以使用\b
匹配字符串边界。
# 需要匹配两侧均为边界
# 左侧为边界,右侧不是边界
>>> regex = re.compile(r'\bdata\b')
>>> match = regex.search('datastudio')
>>> print(match)
None
# 左侧为边界,右侧是空格
>>> regex = re.compile(r'\bdata\b')
>>> match = regex.search('data studio')
>>> print(match)
<re.Match object; span=(0, 4), match='data'>
# 左侧为空格,右侧不是边界
>>> regex = re.compile(r'\bdata\b')
>>> match = regex.search(' datastudio')
>>> print(match)
None
# 左侧是边界,右侧是符号点
>>> regex = re.compile(r'\bdata\b')
>>> match = regex.search('data.studio')
>>> print(match)
<re.Match object; span=(0, 4), match='data'>
匹配所有指定字符开头的字符串
>>> pattern = 'data_\w+'
>>> string = '关注DATA_STUDIO DATA_STUDIO data_studio'
>>> match = re.findall(pattern, string, re.I) # 搜索字符串,不区分大小写
>>> print(match)
['DATA_STUDIO', 'data_studio']
re模块中的字符处理
re.sub()
re.sub用于替换字符串中的匹配项,即将某个字符串中所有匹配正则表达的部分替换成其他字符串。
re.sub(pattern, repl, string, count=0, flags=0)
pattern : 正则中的模式字符串,由要匹配的正则表达式转换而来。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。可选参数,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
# 替换字符串
>>> import re
>>> pattern = r'1[3456789]\d{9}'
>>> string = '电话号码为:18188888888 的提取码为:12345678'
>>> match = re.sub(pattern, '1**********', string)
>>> print(match)
'电话号码为:1********** 的提取码为:12345678'
# 删除多余字符串
>>> string = 'a1l8l1 8kh8oo88 8oo8ool8lll8'
>>> pattern = '[a-z]'
>>> match = re.sub(pattern, "", string, flags=re.I)
# 匹配字符串,将所有字母替换为空,并区分大小写
>>>
print(match)
181 8888 8888
re.split()
split 方法按照能够匹配的子串将字符串分割后返回列表。
re.split(pattern, string[, maxsplit=0, flags=0])
pattern 正则中的模式字符串,由要匹配的正则表达式转换而来。
string 要被查找替换的原始字符串。
maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。如若需要分割的字符串非常大,并且不希望穷尽分割,可使用此参数。
flags 编译时用的匹配模式,数字形式。可选参数,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
>>> import re
>>> pattern = r'[?|&]'
>>> url = 'http://httpbin.org/get?name="Jim"&age=18'
>>> match = re.split(pattern, url)
>>> print(result)
['http://httpbin.org/get', 'name="Jim"', 'age=18']
附录常见匹配
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\' 匹配 "" 而 "(" 则匹配 "("。 |
^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
* | 匹配前面的子表达式零次或多次。例 |
获取更多常见匹配字符及描述,可关注公众号并回复" 正则表达式 "获取-- 数据STUDIO --
以上是关于网络爬虫 | 正则表达式的主要内容,如果未能解决你的问题,请参考以下文章