Python网络爬虫及正则表达式使用详解
微信关注公众号:夜寒信息
致力于为每一位用户免费提供更优质技术帮助与资源供给,感谢支持!
相信大家都听说过正则表达式及其神奇的用法,正则表达式是用来简洁表达一组字符串的表达式,下面我们来介绍它的用法。
假设有如下的一组字符串,它由’PY’构成,首字母为P后续为一个或无穷多个Y:
PY
PYY
PYYY
PYYYY
...
PYYYYY...
我们知道这组字符串的规律,到我们无法列举出所有的字符串,而这组字符串用正则表达式表达却只需要一句:
PY+
又例如我们有一组字符串,‘PY’开头,后续存在不多于10个字符,其中不包含’P’和’Y’:
PYABC
PYABCD
...
这样的字符串组合为有穷个,我们可以枚举出来,但会很繁琐。到我们可以使用一句正则表达式代替:
PY[^PY]{0,10}
是不是觉得很神奇呢?
正则表达式是一组字符串的表达框架,能显示出字符串的特征。像我们之前举的两个例子==PY+和PY[ ^PY]{0,10}==都是符合正则表达式语法的一串字符串。我们可以这么理解,我们所写出的正则表达式,是按照字符串规律总结出的一串字符串,而需要利用它则需要编译,即如下语句:
p = re.compile(regex) #regex为符合正则表达式语法的字符串
下面我们便来学习正则表达式的语法吧!
正则表达式语法操作符
.
表示任何单个字符
[ ]
字符集,对单个字符给出取值范围,例:
[abc]表示a、b、c,而 [a-z] 表示 a到z单个字符
[ ^ ]
非字符集,对单个字符给出排除范围,例:
[ ^abc ] 表示非a或b或c的单个字符
*
前一个字符0次或无限次扩展,例:
abc表示ab、abc、abcc、sbccc*等
+
前一个字符1次或无限次扩展,例:
abc+表示abc、abcc、sbccc等
?
前一个字符0次或1次扩展,例:
abc?表示ab、abc
|
左右表达式任意一个,例:
abc|def表示abc、def
{m}
扩展前一个字符m次,例:
ab{2}c表示abbc
{m,n)
扩展前一个字符m至n次(含n),例:
ab{1,2}c表示abc、abcc
^
匹配字符串开头,例:
^abc表示abc且在一个字符串的开头
$
匹配字符串结尾,例:
abc $表示abc且在一个字符串的结尾
( )
分组标记,内部只能使用|操作符,例:
(abc)表示abc,(abc|def)表示abc、def
\d
数字,等价于**[0-9]**
\w
单词字符,等价于**[A-Za-z0-9]**
上面这些都是最基本且常用的操作符,为了加深理解,我们举一些例子:
Re库的基本使用
我们只要使用import re便可以使用Re库。正则表达式常用raw string类型(原生字符串类型)。原生字符串,就是字符串内的转义符不会被当作转义符,而是会当作字符串的一部分。例如 raw string 类型中’D:\text’便可以表示文件地址,而string类型则需要’D:\text’才能表达。
Re库的主要功能函数
re.search(pattern, string, flags)
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
**pattern:**正则表达式的字符串或原生字符串表示
**string:**待匹配字符串
**flags:**正则表达式使用是的控制标记
flags的常用标记:
**re.I:**忽略正则表达式的大小写,[A-Z]能够匹配小写字符
**re.M:正则表达式中的^**操作符能够将给定的字符串的每行当作匹配开始
**re.S:**正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符
下面给个例子:
>>> import re
>>> match = re.search(r'[1-9]\d{5}', 'BIT 100081')
>>> if match:
print(match.group(0))
100081
我们看到,search函数匹配出了100081
re.match(pattern, string, flags)
从一个字符串的开始位置起匹配正则表达式,返回match对象
**pattern:**正则表达式的字符串或原生字符串表示
**string:**待匹配字符串
**flags:**正则表达式使用是的控制标记,标记同上介绍
下面举个例子:
match = re.match(r'[1-9]\d{5}', 'BIT 100081')
>>> if match:
print(match.group(0))
>>> match.group(0)
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
match.group(0)
AttributeError: 'NoneType' object has no attribute 'group'
>>> print(match)
None
因为他是从头匹配的,我们可以看出它的匹配结果报错,显示匹配结果为空,而若将要它匹配出结果则需要改变字符串参数:
>>> match = re.match(r'[1-9]\d{5}', '100081 BIT')
>>> if match:
print(match.group(0))
'100081'
re.findall(pattern, string, flags)
搜做字符串,以列表类型返回全部能匹配的子串
**pattern:**正则表达式的字符串或原生字符串表示
**string:**待匹配字符串
**flags:**正则表达式使用是的控制标记,标记同上介绍
下面举个例子:
>>> ls = re.findall(r'[1-9]\d{5}', 'BIT 100081 TSU 100084')
>>> ls
['100081', '100084']
我们可以看到,它返回了一个列表里面包含了所有匹配结果。
re.split(pattern, string, maxsplit, flags)
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
**pattern:**正则表达式的字符串或原生字符串表示
**string:**待匹配字符串
**maxsplit:**最大分割数,剩余部分作为最后一个元素输出
**flags:**正则表达式使用是的控制标记,标记同上介绍
下面举个例子:
>>> re.split(r'[1-9]\d{5}', 'BIT 100081 TSU 100084')
['BIT ', ' TSU ', '']
我们可以看到,返回了一个列表包含了所有去除匹配结果后,分割后的字符串,下面我们来添加上最大分割数:
>>> re.split(r'[1-9]\d{5}', 'BIT 100081 TSU 100084',1)
['BIT ', ' TSU 100084']
我们可以看到,在匹配到第一个字符串后,将前一部分分隔出来后,将去除将匹配结果后的所有字符标为一个字符串
re.finditer(pattern, string, flags)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
**pattern:**正则表达式的字符串或原生字符串表示
**string:**待匹配字符串
**flags:**正则表达式使用是的控制标记,标记同上介绍
下面举个例子:
>>> for m in re.finditer(r'[1-9]\d{5}', 'BIT 100081 TSU 100084'):
if m:
print(m.group(0))
100081
100084
我们看到,可以迭代的处理所有匹配到的结果。
re.sub(pattern, repl, string, count, flags)
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
**pattern:**正则表达式的字符串或原生字符串表示
**repl:**替换匹配字符串的字符串
**string:**待匹配字符串
**count:**匹配的最大替换次数
**flags:**正则表达式使用是的控制标记,标记同上介绍
下面举个例子:
>>> re.sub(r'[1-9]\d{5}','夜寒信息', 'BIT 100081 TSU 100084')
'BIT 夜寒信息 TSU 夜寒信息'
我们可以看到,匹配到的结果被替换为微信公众号的名称’夜寒信息’
Re库的等加用法
我们以上介绍的方法都是一次性操作,例如match = re.search(r'[1-9]\d{5}', 'BIT 100081')
而我们可以使用面向对象的方式使用compile函数编译后再使用,这样可以多次重复使用已约定的正则表达式,需要以下两步:
>>> pat = re.compile(r'[1-9]\d{5}')
>>> rst = pat.search('BIT 100081')
我们可以正常的使用函数的参数,注意无需添加正则表达式参数,例如:
原式:
>>> re.split(r'[1-9]\d{5}', 'BIT 100081 TSU 100084',1)
['BIT ', ' TSU 100084']
面向对象:
>>> pat = re.compile(r'[1-9]\d{5}')
>>> rat = pat.split('BIT 100081 TSU 100084',1)
>>> rat
['BIT ', ' TSU 100084']
Re库的Match对象
match对象中存放着匹配的所有结果,下面对他介绍。
>>> match = re.search(r'[1-9]\d{5}', 'BIT 100081')
>>> if match:
print(match.group(0))
100081
>>> type(match)
<class 're.Match'>
我们可以看到,match为正则表达式的Match类型,他有几个属性:
.string
待匹配文本
.re
匹配时使用的pattern对象(正则表达式)
.pos
正则表达式搜索文本的开始位置
.endpos
正则表达式搜索文本的结束位置
它还有一些方法:
.group()
获得匹配后的字符串
.start()
匹配字符串在原始字符串的开始位置
.end()
匹配字符串在原始字符串的结束位置
.span()
返回起始结束位置的元组**(.start(), .end())**
Re库的贪婪匹配和最小匹配
Re库默认采用贪婪匹配,即输出匹配最长的字符串,例如:
>>> match = re.search(r'PY.*N', 'PYANBNCNDN')
>>> match.group(0)
'PYANBNCNDN'
我们看出,本来可以匹配出’PYAN’,‘PYANBN’,‘PYANBNCN’,'PYANBNCNDN’四种结果,但我们不加约束则默认匹配最长字符串。
若要输出最小匹配则需要将正则表达式变为'PY.*?N'
,例如:
>>> match = re.search(r'PY.*?N', 'PYANBNCNDN')
>>> match.group(0)
'PYAN'
若有问题请关注微信公众号"夜寒信息"
微信关注公众号:夜寒信息
致力于为每一位用户免费提供更优质技术帮助与资源供给,感谢支持!