常见的匹配模式
\w 匹配字母数字及下划线
\W 匹配f非字母数字下划线
\s 匹配任意空白字符,等价于[\t\n\r\f]
\S 匹配任意非空字符
\d 匹配任意数字
\D 匹配任意非数字
\A 匹配字符串开始
\Z 匹配字符串结束,如果存在换行,只匹配换行前的结束字符串
\z 匹配字符串结束
\G 匹配最后匹配完成的位置
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串的开头
$ 匹配字符串的末尾
. 匹配任意字符,除了换行符,re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
[....] 用来表示一组字符,单独列出:[amk]匹配a,m或k
[^...] 不在[]中的字符:[^abc]匹配除了a,b,c之外的字符
* 匹配0个或多个的表达式
+ 匹配1个或者多个的表达式
? 匹配前面的子表达式零次或一次。当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。
{n} 精确匹配n前面的表示
{m,m} 匹配n到m次由前面的正则表达式定义片段,贪婪模式
a|b 匹配a或者b
() 匹配括号内的表达式,也表示一个组
Python中的正则表达式工具封装在re模块中
re.match
该方法尝试在字符串的起始位置开始匹配一个模式,如果不是起始位置开始,函数返回None
比较详细的匹配
import re
content= "hello 123 4567 World_This is a regex Demo"
result = re.match('^hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content) #加了$结束符,只能完全匹配content,不然就是None
print(result)
print(result.group()) #获取匹配的结果
print(result.span()) #获取匹配字符串的长度
content= "12123hello 123 4567 World_This is a regex Demo"
print(result) #None,不是从起始位置匹配
泛匹配
由于 . 表示任意字符,然后 * 表示匹配任意个表达式(包括零个),所有用 .* 可以简化掉匹配模式中不重要的部分
import re
content= "hello 123 4567 World_This is a regex Demo"
result = re.match("^hello.*Demo$",content)
print(result)
print(result.group())在这里插入图片描述
print(result.span())
匹配目标
有的时候目的不是匹配一个字符串,而是匹配上一个字符串后获取里面的目标,这时需要用到括号()
import re
content= "hello 1234567 World_This is a regex Demo"
result = re.match('^hello\s(\d+)\sWorld.*Demo$',content) #()中的内容是目标内容,获取目标的前提是re.match能匹配上
print(result)
print(result.group())
print(result.group(1)) #当匹配模式中有多个括号时,1表示第一个目标,不是0
print(result.span())
默认贪婪匹配
在正则匹配中,默认是采用贪婪匹配机制,比如 .* 会尽可能的匹配最多的字符
import re
content= "hello 1234567 World_This is a regex Demo"
result= re.match('^hello.*(\d+).*Demo',content)
print(result)
print(result.group(1)) #这里的结果是7,因为.*把123456都匹配过去了
如果想获取1234567,就在表达式*后面加个 ?,表示是非贪婪的
result= re.match('^he.*?(\d+).*Demo',content)
换行问题
当匹配的内容存在换行问题,需要用re.S来匹配换行的内容
import re
content= """hello 1234567 World_This is a regex Demo
huanhang"""
result = re.match('^hello\s(\d+)\sWorld.*?huanhang$',content,re.S) #如果不加re.S,返回None
print(result)
print(result.group())
print(result.span())
转义
当匹配的内容存在特殊字符时,需要进行转义
import re
在这里插入图片描述
content= "price is $5.00"
result = re.match('price is \$5\.00',content)
print(result)
print(result.group())
re.search
re.search扫描整个字符串,返回第一个匹配的结果
import re
content = "extra things hello 123455 world_this is a Re Extra things"
result = re.search("hello.*?(\d+).*?Re",content)
print(result)
print(result.group())
print(result.group(1))
re.findall匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re.findall搜索字符串,以列表形式返回所有匹配结果
import re
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
print(result)
print(result[0], result[1], result[2])
re.sub
把模式匹配成功的子串替换成目标字符串
import re
content = "Extra things hello 123455 World_this is a regex Demo extra things"
content = re.sub('\d+','',content)
print(content) #Extra things hello World_this is a regex Demo extra things
有的时候不想替换,而是补充内容,可以利用\1来表示匹配到的字符串
import re
content = "Extra things hello 123455 World_this is a regex Demo extra things"
content = re.sub('(\d+)',r'\1 7890',content) #不能少了r
print(content) #Extra things hello 123455 7890 World_this is a regex Demo extra things
re.compile
将正则表达式编译成正则表达式对象,方便复用正则表达式
import re
content= """hello 12345 world_this
123 fan
"""
pattern =re.compile("hello.*fan",re.S)
result = re.match(pattern,content)
print(result)
print(result.group())
豆瓣书籍实战
目标链接:https://book.douban.com
目标:获取该网页的所有书籍的封面图片,并以书籍的名字保存图片
#encoding=utf-8
import requests
import re
import os
root = "./douban"
url = "https://book.douban.com"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"
}
response = requests.get(url, headers=header) #得加header
# print(response.status_code)
# print(response.content.decode("utf-8"))
content = response.content.decode("utf-8")
#把div、a这些标签也写出来是为了更准确的定位,不然假如网页有不需要的img,则会把不需要的img一直到需要的img那一大段都截下来
#比如func = '<img src.*?(http.*?jpg).*?alt="(.*?)".*?>'
#content = "<img src="http**没有用.jpg">\n<div class="cover">\n<a hrep=***>\n<img src="http://有用的.jpg" alt="xxx">"
#截取出来的是 http**没有用.jpg">\n<div class="cover">\n<a hrep=***>\n<img src="http://有用的.jpg
func = '<div class="cover">\s*?<a .*?>\s*?<img src.*?(http.*?jpg).*?alt="(.*?)".*?>'
results = re.findall(func, content, re.S)
for result in results:
print(result[0])
print(result[1])
path = os.path.join(root, result[1] + '.jpg')
with open(path, 'wb') as f:
response = requests.get(result[0], headers=header)
f.write(response.content)
结果:
注意:在Ubuntu上,有的图片打不开,因为下载的图片原本应该是png的格式,但他直接改后缀成jpg了,在Windows上能看(不是我改的,而是网页提供的就是改过了的)