Python爬虫基础2-正则表达式

正则表达式

正则表达式表示一种字符组合规律,描述了一种字符串模式。如果一个字符串符合这种模式,就叫做匹配这个正则表达式。

在线测试 https://regexr.com

普通字符

包含所有可以直接对应匹配的可打印字符不可打印字符

不可打印字符:

  • \n 换行
  • \r 回车
  • \s 任何空白字符
  • \S 任何非空白字符
  • \t 制表符

特殊字符

限定符 * + ? {}

修饰表达式,表示该表达式可以重复的数量。

  • ? 表示0或1次
  • + 表示1次及以上
  • * 表示任意次
  • {n} 表示必须重复n次;{n,}表示至少重复n次;{m,n} 表示重复次数在m和n次之间

通配符 .

匹配任意字符。但是一般不包含换行。在python中如果要匹配换行需要用re.S作为flags

选择符|

匹配多种表达式中的一种即可。由于优先级很低,建议配合括号使用。

小括号 ( )

标记子表达式的位置。可以用来消除歧义,也可以暗示匹配到这里的子串可能会未来使用。

中括号 []

按照中括号中的内容设定,匹配单个字符。常见的有[A-Za-z0-9]。

特殊的简化:\w = [A-Za-z0-9_] 字母数字下划线 \W代表非字母数字下划线

定位符 ^ $ /b /B

^ 表示此处为字符串开头;$表示此处为字符串结尾。

在说字符串是否匹配某个正则表达式时,默认前后都有^和$

/b 匹配单词边界(开始和结束都有)

/B 匹配非单词边界

定位符并不实际占用字符的位置,而是表示前后字符需要所处的位置。

非贪婪匹配符 ?

默认匹配模式为贪婪匹配,在满足匹配的范围内,尽可能多的匹配字符。但是如果一个表达式后面加上?则表示非贪婪匹配,表示尽可能少地匹配字符。

转义字符 \

将后一个字符当做特殊字符或者原义字符处理。例如n表示字母n,但是\n表示换行;.表示任意字符,但是\.表示点本身。 \\ => \

其他

非捕获元 (?:) 小括号内的内容不会被捕获,其他和小括号的功能相同。

另外四个非捕获元。反向引用。

Python中使用正则表达式

引入包

import re

函数

re.match

re.match(pattern, string, flags=0) 从头开始匹配,一次。返回 Match 对象。

import re

pattern = r"123(.*?)abc(1+)234"
text = r"123yyyabc111234---------"

# 从头开始匹配,匹配到第一个就结束
match_obj = re.match(pattern, text)

print(match_obj.group(0)) # 123yyyabc111234 group(0)表示匹配到的整个正则表达式部分
print(match_obj.group(1)) # yyy group(1) 表示匹配到的第一个括号中捕获的内容
print(match_obj.group(2)) # 111 group(2) 表示匹配到的第二个括号中捕获的内容 以此类推

Match.group(num) group(1~n)对应正则表达式中用小括号括起来,捕获的内容。group(0)对应match匹配到和整个正则表达式匹配的内容;按照顺序取出。

flags 标志:

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

不同的flags可以用 | 来组合。比如re.I | re.S 表示既忽略大小写,.又可以匹配换行。

re.search(pattern,string, flags=0) 搜索,可以从任意位置开始匹配,一次。返回 Match 对象

import re

pattern = r"123(.*?)abc(1+)234"
text = r"2123yyyabc111234---------"

# 从任意位置匹配,查找到第一个就结束
# 如果没有查找到,match_obj为None
match_obj = re.search(pattern, text)

print(match_obj.group(0)) # 123yyyabc111234 group(0)表示匹配到的整个正则表达式部分
print(match_obj.group(1)) # yyy group(1) 表示匹配到的第一个括号中捕获的内容
print(match_obj.group(2)) # 111 group(2) 表示匹配到的第二个括号中捕获的内容 以此类推

findall

re.complie(pattern, flags) flag参数可选。编译为正则表达式 Pattern 对象

Pattern.findall(string) 查找所有匹配到的结果。可以加开始和结束位置参数。

import re

pattern_text = r"123(.*?)abc(1+)234"
text = r"2123YyyABC111234---------"

# 编译后,查找效率会变高 re.I表示忽略大小写
pattern = re.compile(pattern_text, flags=re.I)
result = pattern.findall(text)
print(result)

使用原生字符串

对于代码中的字符串,python会先进行一次转义处理。如果用在正则表达式中,re包对字符串会再进行一次转义处理,相当于进行两次处理。例如输入pattern = "\\n",re拿到时pattern变成"\n",再次转义变成一个换行。本来想匹配一个斜杠和n,却变成了匹配换行。必须使用"\\\\n"才能达到目的。

使用r””原生字符串,可以跳过第一步编译器的处理。例如上面例子中"\\\\n"r"\\n"是等价的。

特殊情况:r"\""被当做一个”来处理。

爬取豆瓣电影

import re
import requests

#0 变量准备
douban_url = r"https://movie.douban.com/top250"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
}

#1 访问得到网页源代码
response = requests.get(, headers=headers)
text = response.content.decode("utf-8")
print(text)

#2 正则表达式过滤信息
# 摘取(排名,电影名字,导演,评分)
movie = r"<em class=\"\">([0-9]+)</em>.*?<span class=\"title\">(.*?)</span>.*?<p class=\"\">\s*(.*?)&nbsp;&nbsp;&nbsp.*?<br>.*?property=\"v:average\">(.*?)</span>"
pattern = re.compile(movie, re.S)
result = pattern.findall(text)
print(result)

注意:

  1. 使用headers,否则会被豆瓣屏蔽
  2. 使用re.S的flag,让.可以匹配换行,适用于多行文本查找