小白学爬虫连载--正则表达式详细介绍
Posted 哈希大数据
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小白学爬虫连载--正则表达式详细介绍相关的知识,希望对你有一定的参考价值。
正则表达式详细介绍
哈希大数据致力于互联网、金融、物流等行业大数据采集、分析、营销与决策提供综合解决方案
中介绍了如何用Requests获取网页内容,可是html文档中的内容比较繁杂,如何提取出我们需要的信息呢?本篇文章为大家介绍一个用于文本信息提取的强有力的工具——正则表达式。
什么是正则表达式
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个字符串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某种条件的子串等。——菜鸟教程
正则表达式在文本处理中十分常用,可以用于查找、替换、匹配一组字符串。接下来介绍几个正则表达式经典的实例:
正则表达式 |
匹配字符串类型 |
[\u4e00-\u9fa5] |
匹配中文字符串 |
[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])? |
|
[a-zA-z]+://[^\s]* |
匹配网址 |
\d{3}-\d{8}|\d{4}-\{7,8} |
|
[1-9][0-9]{4,} |
匹配QQ号 |
^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$ |
匹配18位身份证号 |
^[A‐Za‐z0‐9]+$ |
匹配由26个字母和数字组成的字符串 |
由实例可以看出正则表达式的语由字符和操作符构成,正则表达式的常用操作符如下表所示:
操作符 |
说明 |
实例 |
\s |
匹配任何空白字符,包括空格、制表符、换页符等等 |
|
\S |
匹配任何非空白字符 |
|
^ |
匹配字符串开头 |
^abc表示abc且在一个字符串的结尾 |
$ |
匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$ |
abc$表示abc且在一个字符串的结尾 |
() |
标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \) |
(abc)表示abc,(abc|def)表示abc、 def |
* |
匹配前面的子表达式0次或多次。要匹配 * 字符,请使用 \* |
ab* 表示a、ab、abb、abbb... |
+ |
匹配前面的子表达式1次或多次。要匹配 + 字符,请使用 \+ |
ab+ 表示ab、abb、abbb... |
? |
匹配前面的子表达式0次或1次。要匹配 + 字符,请使用 \+ |
ab? 表示a、ab |
. |
匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \. |
|
[ ] |
字符集,对单个字符给出取值范围 |
[abc]表示匹配a、b、c中的任意一个,[a-z]表示a到z的单个字符 |
| |
左右表达式任意一个 |
abc|def 表示abc、def |
{m} |
扩展前一个字符m次 |
ab{2}c表示abbc |
{m,n} |
扩展前一个字符m到n次,含n次 |
ab{1,2}c表示abc,abbc |
\d |
数字,等价于[0-9] |
|
\w |
单词字符,等价于[A-Za-z0-9] |
Re库正则表达式表示介绍
正则表达式不是Python独有的,Python中re标准库,提供正则表达式的各种处理,接下来我们初步认识一下这个库。
首先re库可采用string和raw string(原生字符串)两种类型表示正则表达式,建议大家使用原生字符串。什么是原生字符串呢?在一般字符串'abc\tdef'前面加一个r,便成为了原生字符串。它的作用是使转义符\不起作用,字符串原样输出。比如:
s = 'abc\tdef'
s1 = r'abc\tdef'
print(s)
abc def
print(s1)
abc\tdef
原生字符串s1并没有把\t识别为制表符。同时大家要特别注意的是由于正则表达式使用反斜杠来转义特殊字符,而python自身处理字符串时,反斜杠也是用于转义字符,这样就产生了一个双重转换的问题。这个地方稍微有些复杂,不想深究可跳过下面不同字体的部分,大家只需注意当正则表达式包含转义符时使用原生字符串表示正则表达式就好。
接下来以匹配字符串s = 'abc\-123'为例讲解。
import re
s = 'abc\-123'
s1 = re.match('abc\\\\-123', s)
print("s1匹配结果:{}".format(s1.group()))
s1匹配结果:abc\-123
s2 = re.match(r'abc\\-123', s)
print("s2匹配结果:{}".format(s2.group()))
s2匹配结果:abc\-123
很明显我们需要注意两个地方,我们用'abc\\\\-123'和r'abc\\-123'都能完成的对字符串s的匹配,字符串'abc\\\\-123'匹配过程中如下:首先因为它不是原始字符串,字符串转义函数会对其转义得到正则表达式'abc\\-123',然后正则表达式'abc\\-123'又会被正则表达式转义函数转义为字符串'abc\-123',完成了对字符串s的匹配。原生字符串r'abc\\-123'匹配过程如下,由于是原生字符串所以不会被转义,直接打到正则表达式'abc\\-123',然后正则表达式'abc\\-123'又会被正则表达式转义函数转义为字符串'abc\-123'。所以两种情况都可以匹配成功。这里面提到字符串转义和正则表达式转义它们两个是有不同的,因为正则表达式的特殊字符和字符串特殊字符存在不同之处,如 * 在正则表达式中代表匹配前面的子表达式0次或多次,而在在字符串中不是特殊字符。你可以尝试理解下面这种情况,看看自己是否真正理解了上述过程:
import re
s = '*abc123'
s1 = re.match('\*abc123', s)
print("s1匹配结果:{}".format(s1.group()))
s1匹配结果:*abc123
s2 = re.match('\\*abc123', s)
print("s2匹配结果:{}".format(s2.group()))
s2匹配结果:*abc123
Re库主要函数介绍
函数 |
说明 |
re.match() |
从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none |
re.search() |
扫描整个字符串并返回第一个成功的匹配,匹配不成功返回None |
re.findall() |
扫描整个字符串并返回所有成功的匹配,返回的是一个列表,匹配不成功返回None |
re.sub() |
扫描整个字符串替换所有匹配成功的子串,返回替换后的字符串 |
re.compile() |
根据包含正则表达式的字符串创建模式对象,以便于多处使用 |
l re.match(pattern, string, flags=0)
样例:
import re
print(re.match('www', 'www.mingmenyun.com').group()) # 在起始位置匹配
print(re.match('com', 'www.mingmenyun.com')) # 不在起始位置匹配
运行结果为:
www
None
l re.search(pattern, string, flags=0)
样例:
import re
print(re.search('www', 'www.mingmenyun.com').group()) # 在起始位置匹配
print(re.search('com', 'www.mingmenyun.com').group()) # 不在起始位置匹配
print(re.search('我爱你', 'Python我爱你,爬虫我爱你').group()) # 不在起始位置匹配
运行结果:
www
com
我爱你
l re.findall(pattern, string, flags=0)
样例:
import re
print(re.findall('我爱你', 'Python我爱你,爬虫我爱你'))
运行结果:
['我爱你', '我爱你']
l re.sub(pattern, repl, string, count=0)
参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
样例:
import re
print(re.sub(r'\d', '', "大河12向东流34,天上332的星星1参23北5斗"))
运行结果:
大河向东流,天上的星星参北斗
l re.compile(pattern, flags=0)
样例:
import re
regex = re.compile('我爱你')
print(regex.findall('Python我爱你,爬虫我爱你'))
运行结果:
['我爱你', '我爱你']
re.match与re.search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
re.search与re.findall的区别:
re.search只返回找到的第一个匹配,而re.findall返回所有匹配的的结果。
匹配目标获取与匹配模式
获取匹配目标:
样例:
import re
s = 'Hello my QQ is 1428941524,welcome to contect me!'
result = re.match('^Hello.*\s(\d+),.*me!$', s)
print(result.group(1))
print(result.span())
运行结果:
1428941524
(0, 48)
如样例所示用()将想提取的信息括起来,group(1)代表第一个小括号内的内容,group(2)代表第二个...,这样便能提取出我们想要的信息啦。
匹配模式:
样例:
import re
s = '''Hello
my QQ is 1428941524,welcome to contect me!'''
result = re.match('^Hello.*\s(\d+),.*me!$', s, re.S)
print(result.group(1))
print(result.span())
运行结果:
1428941524
(0, 48)
该样例与获取目标样例的不同之处在于,字符串s变为了多和字符串,中间出现了换行,match函数中多了re.S。此时不加它的话程序出错。re.S就是定义匹配模式的,类似的匹配模式如下表所示:
匹配模式 |
作用 |
re.I |
忽略大小写 |
re.M |
多行模式,改变’^‘和'$'的行为 |
re.S |
.可以匹配任意模式 |
re.L |
使预定字符类 \w \W \b \B \s \S 取决于当前区域设定 |
re.U |
使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性 |
re.X |
详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释 |
贪婪匹配与非贪婪匹配
贪婪匹配:
import re
s = '''Hello
my QQ is 1428941524,welcome to contect me!'''
result = re.match('^Hello.*(\d+).*me!$', s, re.S)
print(result.group(1))
运行结果:
4
结果只匹配到了4,142894152都被.*匹配到了,.*会尽可能多的匹配字符这就是贪婪匹配,由于后面有\d所以至少要匹配到一个数字,这是咱们不愿意看到的,有什么解决办法吗?当然有下面介绍非贪婪匹配。
非贪婪匹配:
样例:
import re
s = '''Hello
my QQ is 1428941524,welcome to contect me!'''
result = re.match('^Hello.*?(\d+).*me!$', s, re.S)
print(result.group(1))
运行结果:
1428941524
非贪婪模式与贪婪模式的不同之处就在于在.*后加了一个?,非贪婪模式又称为最小匹配模式,就是说它会匹配到尽可能少的字符。
小结
本篇文章主要介绍了以下几点内容:
什么是正则表达式,正则表达式的常用操作符
Re库正则表达式表示方式介绍,这里面有个比较难理解的地方是字符串与正则表达式的双重转换
Re库主要函数介绍,这里主要介绍了re.match()、re.search()、re.findall()、re.sub()、re.compile()
匹配目标获取与匹配模式
贪婪匹配与非贪婪匹配
本次分享到此结束,目前我们已经学了requests库下载目标网站源码,正则表达提取文本信息,下次将分享如何使用chrome浏览器对想要爬取的网站进行分析。
·end·
—如果喜欢,快分享给你的朋友们吧—
我们一起愉快的玩耍吧
以上是关于小白学爬虫连载--正则表达式详细介绍的主要内容,如果未能解决你的问题,请参考以下文章