爬虫入门(三):掌握常用正则表达式

当获取到页面的内容之后,怎么样提取想要的文字呢?正则表达式就是一个很好用的工具。在很多编程语言里面都有正则表达式的概念。正则表达式比较常见的是对字符串操作,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。除了提取文字外,比较常见的还有判断是不是email,是不是手机号等功能。

re模块

Python使用\作为转义字符,匹配的时候很容易少写反斜杠等问题。Python中re 模块提供了正则表达式的支持,可以很好的解决这个问题。
举个例子:
不使用re

s = 'lzc\\dev' # Python的字符串
# 对应的正则表达式字符串变成:
# 'lzc\dev'

使用re模块

s = r'lzc\dev' # Python的字符串
# 对应的正则表达式字符串是不变的
# 'lzc\dev'

主要函数:

函数名 语法 描述
compile re.compile(string[,flag]) 用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用
match re.match(pattern, string[, flags]) 从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话(也可以指定起始位置),match()就返回none
search re.search(pattern, string[, flags]) 扫描整个字符串并返回第一个成功的匹配
split re.split(pattern, string[, maxsplit]) 按照能够匹配的子串将字符串分割后返回列表
findall re.findall(pattern, string[, flags]) 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
finditer re.finditer(pattern, string[, flags]) 在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回
sub re.sub(pattern, repl, string[, count]) 用于替换字符串中的匹配项
subn re.subn(pattern, repl, string[, count]) 跟 sub 方法的行为类似,也用于替换

compile

pattern=re.compile(pattern[, flag])compile函数用来生成一个pattern对象,pattern 是一个字符串形式的正则表达式,flag 是一个可选参数,表示匹配模式,比如re.I表示忽略大小写,还有比较常用的re.S表示. 并且包括换行符在内的任意字符(. 不包括换行符)。通常 pattern要跟re模块的方法结合使用。

import re
pattern = re.compile(r'\d+')  # 用于匹配至少一个数字

re.match

re.match(pattern, string[, flags])
结合pattern使用,我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。pattern是要匹配的正则表达式,string是要匹配的字符串,flags是标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等

#!/usr/bin/python
#coding:utf-8

import re
pattern1 = re.compile(r'\d+') # 用于匹配至少一个数字
pattern2 = re.compile(r'([a-z])', re.I)   # re.I 表示忽略大小写

m1 = pattern1.match('lzc123')
m2 = pattern2.match('lzc123') 
print m1 # None
print m2.groups() # ('l',)

m3 = pattern1.match('1lzc23') 
m4 = pattern1.match('123lzc')
print m3 # <_sre.SRE_Match object at 0x104801ac0>  (返回一个 Match 对象)
print m3.group() # 1
print m4.group() # 123

re.search

re.search(pattern, string, flags=0)
用法跟match差不多。re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

import re

matchObj = re.match(r'lzc', 'Is lzc handsome?', re.M|re.I)
if matchObj:
	print matchObj.group()
else: 
	print 'no match'	
# no match


searchObj = re.search(r'lzc', 'Is lzc handsome?', re.M|re.I)
if searchObj:
	print searchObj.group()
else:
	print 'no search'
# lzc

re.split

re.split(pattern, string[, maxsplit=0, flags=0])
split 方法按照能够匹配的子串将字符串分割后返回列表。这里的maxsplit表示分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。

import re

r = re.split('(\W+)', 'lzc,is,handsome.') 
r2 = re.split(r'is', 'lzcishandsome') 
print r # ['lzc', ',', 'is', ',', 'handsome', '.', '']
print r2 # ['lzc', 'handsome']

findall

findall(string[, pos[, endpos]])
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。string 是要匹配的字符串,pos :是可选参数,指定字符串的起始位置,默认为 0。endpos :也是可选参数,指定字符串的结束位置,默认为字符串的长度。注意这里和match、search有区别:match 和 search 是匹配一次 ,findall 匹配所有。

import re

pattern = re.compile(r'\d+')   # 查找数字
result1 = pattern.findall('lzc1 is2 very3 handsome')
result2 = pattern.findall('lzc11isvery22handsome333', 0, 12)
print(result1) # ['1', '2', '3']
print(result2) # ['11', '2']

finditer

re.finditer(pattern, string, flags=0)
这个用法和 findall 差不多,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。这个平时用的不太多

import re

it = re.finditer(r"\d+","1lzc23is45handsome6666") 
for match in it: 
    print (match.group())

# 1
# 23
# 45
# 6666

sub

re.sub(pattern, repl, string, count=0, flags=0)
repl表示替换的字符串,也可为一个函数,string是要被查找替换的原始字符串,count是模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

import re
 
string = "lzc-number111 # 这是我的名字"
# 删除字符串中的注释 
str1 = re.sub(r'#.*$', "", string)
print str1 # lzc-number111
# 删除非数字的字符串 
str2 = re.sub(r'\D', "", string)
print str2 # 111

subn

subn(repl, string[, count])
subn 方法跟 sub 方法的用法差不多,也用于替换。

import re

def add(m):
    # Convert.
    v = int(m.group(0))
    # Add 2.
    return str(v + 1)
# Call re.subn.
result = re.subn("\d+", add, "1 2 3 4 5")
print("Result string:", result[0]) # ('Result string:', '2 3 4 5 6')
print("Number of substitutions:", result[1]) # ('Number of substitutions:', 5)

贪婪模式与非贪婪模式

从字面上就可以猜到:贪婪模式,就是在整个表达式匹配成功的前提下,尽可能多的匹配,有多少就匹配多少。而非贪婪模式,就是在整个表达式匹配成功的前提下,尽可能少的匹配,就是找到一个想要的就行了,至于还有没有就不管了。Python中默认是贪婪模式的。如果想要非贪婪模式,则要用到?。看一个常见的用法(.*?)
(.*) : 代表匹配除换行符之外的所有字符。
(.*?): 其中?代表非贪婪模式,也就是说只匹配符合条件的最少字符
举个例子:

import re
content = 'lzc<div>is</div>handsome<div>test</div>haha'
pattern1 = re.compile(r'<div>(.*)</div>')
result1 = pattern1.findall(content)
print result1 # ['is</div>handsome<div>test']

pattern2 = re.compile(r'<div>(.*?)</div>')
result2 = pattern2.findall(content)
print result2 # ['is', 'test']

小结

正则表达式非常强大,多多练习,多看资料才能用好它,发挥它真正的实力。

comments powered by Disqus