前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络爬虫 | 正则表达式

网络爬虫 | 正则表达式

作者头像
数据STUDIO
发布2021-06-24 10:33:26
1.2K0
发布2021-06-24 10:33:26
举报
文章被收录于专栏:数据STUDIO

正则表达式中匹配与查找

正则表达式,简称为regex,是文本模式的描述方法。

代码语言:javascript
复制
>>> 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对

代码语言:javascript
复制
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()方法,扫描整个字符串并返回第一个成功的匹配。

代码语言:javascript
复制
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组。

代码语言:javascript
复制
>>> 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'或'云朵'。如果都出现在被查找的字符串中,则匹配第一次出现的文本。

代码语言:javascript
复制
>>> pattern = (r'Jim|yunduo')
>>> match=re.search(pattern,'yunduo is the author of DATASTUDIO')
>>> match.group()#第一次出现的匹配文本
'yunduo'

用问号实现可选匹配

不论这段文本在不在,正则表达式都会认为匹配。字符?表明它前面的分组在这个模式中是可选的。

代码语言:javascript
复制
>>> 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'

用星号匹配零次或多次

  • *(称为星号)意味着"匹配零次或多次",即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复。
  • +(加号)则意味着"匹配一次或多次"。星号不要求分组出现在匹配的字符串中,但加号不同,加号前面的分组必须"至少出现一次"。
代码语言:javascript
复制
>>> 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'

贪婪与非贪婪

如果需要匹配一段包含各种不同类型数据的字符串,传统方法需要挨个去匹配,而使用.*可以匹配所有字符,是一种万能匹配的方式。

  • 正则表达式默认是贪婪的,尽可能匹配最长的字符串
  • 另一种为非贪婪模式:加问号'?',尽可能匹配最短的字符
代码语言:javascript
复制
>>> 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):匹配任意字符,包括换行
代码语言:javascript
复制
# 点匹配任意一个字符
>>> 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()方法匹配所有内容

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

代码语言:javascript
复制
re.findall(pattern, string, flags=0)
pattern.findall(string[, pos[, endpos]])

pattern 匹配模式,由要匹配的正则表达式转换而来 string 待匹配的字符串。 flags 可选参数,标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 pos 可选参数,指定字符串的起始位置,默认为 0。 endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。


代码语言:javascript
复制
# findall() 匹配多个,返回的是列表
regex = re.compile(r'\d+')
regex.findall('one1two2three33four4444')
['1', '2', '33', '4444']

匹配字符串边界

如果字符串在开始处、结尾处,或者字符串的分界符为空格、标点符号以及换行,可以使用\b 匹配字符串边界。

代码语言:javascript
复制
# 需要匹配两侧均为边界
# 左侧为边界,右侧不是边界
>>> 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'>

匹配所有指定字符开头的字符串

代码语言:javascript
复制
>>> 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用于替换字符串中的匹配项,即将某个字符串中所有匹配正则表达的部分替换成其他字符串。

代码语言:javascript
复制
re.sub(pattern, repl, string, count=0, flags=0)

pattern : 正则中的模式字符串,由要匹配的正则表达式转换而来。 repl : 替换的字符串,也可为一个函数。 string : 要被查找替换的原始字符串。 count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 flags : 编译时用的匹配模式,数字形式。可选参数,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。


代码语言:javascript
复制
# 替换字符串
>>> 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 方法按照能够匹配的子串将字符串分割后返回列表。

代码语言:javascript
复制
re.split(pattern, string[, maxsplit=0, flags=0])

pattern 正则中的模式字符串,由要匹配的正则表达式转换而来。 string 要被查找替换的原始字符串。 maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。如若需要分割的字符串非常大,并且不希望穷尽分割,可使用此参数。 flags 编译时用的匹配模式,数字形式。可选参数,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。


代码语言:javascript
复制
>>> 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' 之前的位置。

*

匹配前面的子表达式零次或多次。例


获取更多常见匹配字符及描述,可关注公众号并回复"正则表达式"获取

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据STUDIO 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正则表达式中匹配与查找
    • compile()
      • search()
        • group()
          • 用管道匹配多个分组
            • 用问号实现可选匹配
              • 用星号匹配零次或多次
                • 用花括号匹配特定次数
                  • 贪婪与非贪婪
                    • findall()方法匹配所有内容
                      • 匹配字符串边界
                        • 匹配所有指定字符开头的字符串
                        • re模块中的字符处理
                          • re.sub()
                            • re.split()
                            • 附录常见匹配
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档