爬虫系列 | 5、详解爬虫中正则的用法

731 阅读4分钟

通过requests库,我们可以轻易的获取到网页的源代码。但是如果想更精细化的提取我们想要的内容,就需要对内容进行解析了。

这个时候我们可以通过一个非常强大的工具来帮助我们 ---- 正则表达式

正则表达式:通过制定一些特殊的字符或者字符组合来过滤字符串,提取或者检索目标的内容。

正则匹配规则如下图所示,来源:CSDN

img

在Python中,re模块拥有全部的正则表达式的功能。下面介绍几个Re中常用的几个方

一、re.match

从字符串的起始位置开始匹配,如果是起始位置匹配成功返回相应字符,如果不是起始位置返回None

语法如下:

def match(pattern, string, flags=0):
  • pattern : 匹配的正则表达式

  • string :被匹配的字符串

  • flags :用于控制正则的匹配方式(如下表)

    修饰符描述
    re.I使匹配对大小写不敏感
    re.L做本地化识别(locale-aware)匹配
    re.M多行匹配,影响 ^ 和 $
    re.S使 . 匹配包括换行在内的所有字符
    re.U根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
    re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

匹配之后,会返回一个对象,可以通过group(num) 或者 groups() 获取对应字符串

import re

text = 'Hello World, Hi Python'

# 匹配Hello
m1 = re.match('Hello', text)
# 匹配Hi
m2 = re.match('Hi', text)
if m1:
    print(m1.group())
else:
    print('Hello 字符 匹配失败')

if m2:
    print(m2.group())
else:
    print('Hi 字符 匹配失败')

执行结果:

因为Hello字符串在,text中在起始位置所以匹配成功,而Hi字符不在起始位置,所以返回None

Hello
Hi 字符 匹配失败

在正则表达式中,通过 () 来表示要提取的内容。

在下面的例子中,flags=re.I, 代表着匹配对大小写不敏感(忽略大小写)

text = 'Hello Python'
# . 代表匹配任意除换行以外的字符, * 表示匹配前一个字符(.)0次或多次
m1 = re.match(r'H(.*) p(.*)', text, re.I)
# 匹配整个表达式的字符串
print(m1.group()) # 'Hello Python'
# 返回一个包含所有小组字符串的元组
print(m1.groups()) # ('ello', 'ython')
# 获取第一个元素(从1开始)
print(m1.group(1))  # 'ello'
print(m1.group(2)) # 'ython'

二、re.search()

扫描整个字符并返回第一个匹配成功的

为匹配方便,能用search的时候就不要用match。因为search是匹配整个字符串,直到找到第一个匹配到的字符,而match开头如果匹配不到直接就返回了None。

import re

text = "Nice to meet you Nice to meet all"

s1 = re.search('meet (.*) ', text)
s2 = re.search('meet (.*?) ', text)

print(s1.group())
print(s2.group())

输出结果:

meet you Nice to meet 
meet you 

这里需要注意的是 .*.*?

. 表示 匹配除换行符 \n 之外的任何单字符,*表示匹配前面的字符零次或多次。

默认情况下,Python是采用的贪婪模式,就是尽可能多的匹配更多的字符。

所以s1一直匹配到text字符串中最后一个空格。 也就是输出了meet you Nice to meet

如果加上?, 即.*? 则是表示懒惰匹配模式,就是尽可能少的匹配字符。所以s2遇到第一个空格之后就停止了匹配,所以输出meet you

三、re.findall()

在字符串中找到所有与正则匹配的字符串,返回一个列表。如果匹配失败,返回空列表

而match/search 只匹配一次

语法

def findall(pattern, string, flags=0):
import re

text = 'Hello123Python678'
# 匹配字符串中的所有数字
result = re.findall(r'\d+', text)
print(result) # ['123', '678']

四、re.finditer

与findall类似,唯一的区别是返回的是一个迭代器

findall返回的是一个列表

语法

def finditer(pattern, string, flags=0)
import re

text = 'Hello123Python678'
# 匹配字符串中的所有数字
result = re.finditer(r'\d+', text)
print(result) # <callable_iterator object at 0x02BAE700>
for i in result:
    print(i.group())

输出

<callable_iterator object at 0x00B7E640>
123
678

五、re.compile 函数

用于编译正则表达式,生成一个Patter对象,供match()、search()函数使用。

语法

def compile(pattern, flags=0):
  • 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 为了增加可读性,忽略空格和 # 后面的注释

pattern.search/match/findall(string, pos: int, endpos: int = ...)
  • string: 等待匹配的字符串

  • pos:可选参数,指定字符串的起始位置,默认为0

  • endpos:可选参数,指定字符串的结束位置,默认为字符串的长度

如下

import re

text = 'Hello123Python678'
pattern = re.compile(r'\d+')

f1 = pattern.findall(text)
# 从下标为6的地方开始匹配
f2 = pattern.findall(text, 6)
# 匹配到下标为8的地方 停止
f3 = pattern.findall(text, endpos=8)
print(f1) # ['123', '678']
print(f2) # ['23', '678']
print(f3) # ['12']

在这里插入图片描述