欢迎大家关注公众号【哈希大数据】
【小白学爬虫连载(5)】--Beautiful Soup库详解
【小白学爬虫连载(10)】--如何用Python实现模拟登陆网站
小白学爬虫系列(2) 中介绍了如何用Requests获取网页内容,可是HTML文档中的内容比较繁杂,如何提取出我们需要的信息呢?本篇文章为大家介绍一个用于文本信息提取的强有力的工具——正则表达式
一、什么是正则表达式
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个字符串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某种条件的子串等。——菜鸟教程
正则表达式在文本处理中十分常用,可以用于查找、替换、匹配一组字符串。接下来介绍几个正则表达式经典的实例:
由实例可以看出正则表达式的语由字符和操作符构成,正则表达式的常用操作符如下表所示:
二、Re库正则表达式表示介绍
正则表达式不是Python独有的,Python中re标准库,提供正则表达式的各种处理,接下来我们初步认识一下这个库。
首先re库可采用string和raw string(原生字符串)两种类型表示正则表达式,建议大家使用原生字符串。什么是原生字符串呢?在一般字符串'abc\tdef'前面加一个r,便成为了原生字符串。它的作用是使转义符\不起作用,字符串原样输出。比如:
s1 = r'abc\tdef'
print(s)
abc def
print(s1)
abc\tdef
原生字符串s1并没有把\t识别为制表符。同时大家要特别注意的是由于正则表达式使用反斜杠来转义特殊字符,而python自身处理字符串时,反斜杠也是用于转义字符,这样就产生了一个双重转换的问题。这个地方稍微有些复杂,不想深究可跳过下面不同字体的部分,大家只需注意当正则表达式包含转义符时使用原生字符串表示正则表达式就好。
接下来以匹配字符串s = 'abc-123'为例讲解。
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次或多次,而在在字符串中不是特殊字符。你可以尝试理解下面这种情况,看看自己是否真正理解了上述过程:
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(pattern, string, flags=0)样例:
print(re.match('www', 'www.mingmenyun.com').group()) # 在起始位置匹配
print(re.match('com', 'www.mingmenyun.com')) # 不在起始位置匹配
运行结果为:
www
None
re.search(pattern, string, flags=0)样例:
print(re.search('www', 'www.mingmenyun.com').group()) # 在起始位置匹配
print(re.search('com', 'www.mingmenyun.com').group()) # 不在起始位置匹配
print(re.search('我爱你', 'Python我爱你,爬虫我爱你').group()) # 不在起始位置匹配
运行结果:
www
com
我爱你
re.findall(pattern, string, flags=0)样例:
print(re.findall('我爱你', 'Python我爱你,爬虫我爱你'))
运行结果:
['我爱你', '我爱你']
re.sub(pattern, repl, string, count=0)
参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
样例:
print(re.sub(r'\d', '', "大河12向东流34,天上332的星星1参23北5斗"))
运行结果:
大河向东流,天上的星星参北斗
re.compile(pattern, flags=0)样例:
regex = re.compile('我爱你')
print(regex.findall('Python我爱你,爬虫我爱你'))
运行结果:
['我爱你', '我爱你']
re.match与re.search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
re.search与re.findall的区别:
re.search只返回找到的第一个匹配,而re.findall返回所有匹配的的结果。
三、匹配目标获取与匹配模式
获取匹配目标:
样例:
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)代表第二个...,这样便能提取出我们想要的信息啦。
匹配模式:
样例:
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就是定义匹配模式的,类似的匹配模式如下表所示:
四、贪婪匹配与非贪婪匹配
贪婪匹配:
样例:
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所以至少要匹配到一个数字,这是咱们不愿意看到的,有什么解决办法吗?当然有下面介绍非贪婪匹配。
非贪婪匹配:
样例:
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浏览器对想要爬取的网站进行分析。