本篇博客我们将介绍正则表达式,它是处理字符串,如查找、替换等,解析HTML代码、数据清洗等操作的强大工具。
目录
1. 什么是正则表达式?
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”⽤来表达对字符串的⼀种过滤逻辑。
非Python独有,通过re模块实现。
2. 常见匹配模式
3. re.match
re.match 尝试从字符串的起始位置匹配一个模式,如果起始位置匹配不成功的话,match()就返回none。
re.match(pattern, string, flags=0)
- 最常规匹配
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$', content)
print(result)
print(result.group())
print(result.span()) #匹配范围
- 泛匹配
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
#匹配1234567
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld.*Demo$', content)#将目标用()扩起来 目标前后指明 确定范围
print(result)
print(result.group())
print(result.group(1)) #打印第一个()匹配的目标
print(result.span())
- 贪婪匹配
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$', content) #前面的1-6被.*匹配掉了 贪婪模式下.*匹配尽可能多 \d+至少一个数字
print(result)
print(result.group(1))
- 非贪婪模式
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$', content)#加上? 非贪婪模式 匹配尽可能少的字符
print(result)
print(result.group(1))
- 匹配模式
import re
#字符串包含换行符
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*?Demo$', content, re.S) #.不能匹配换行符 加上re.S可以匹配
print(result.group(1))
- 转义
import re
content = 'price is $5.00'
result = re.match('price is $5.00', content)
print(result)
import re
content = 'price is $5.00'
result = re.match('price is \$5\.00', content) #特殊字符前加转义字符
print(result)
- 小结
尽量使用泛匹配、使用括号得到匹配目标、尽量使用非贪婪模式、有换行符就用re.S。
4. re.search
re.search 扫描整个字符串并返回第一个成功的匹配。
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.match('Hello.*?(\d+).*?Demo', content)#只能从第一个字符开始匹配 如果第一个字符不匹配 就不会成功匹配
print(result)
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo', content)
print(result)
print(result.group(1))
为匹配方便,能用search就不用match.
- 匹配演练
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="邓丽君"><i class="fa fa-user"></i>但愿人长久</a>
</li>
</ul>
</div>'''
result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
print(result.group(1), result.group(2))
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>'''
result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S) #只返回第一个成功的匹配
if result:
print(result.group(1), result.group(2))
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>'''
result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html) #此时不能匹配换行符
if result: #所以第一个匹配的是第四个标签
print(result.group(1), result.group(2))
5. 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])
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>'''
#匹配所有歌名 形式不一 有的有换行有的无 有的有a标签有的无
#()表示一个整体 ?匹配0个或1个 可能有可能无
#\s*?可能有换行也可能无
results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>', html, re.S)
print(results)
for result in results:
print(result[1])
6. re.sub
替换字符串中每一个匹配的子串后返回替换后的字符串。
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('\d+', '', content)
print(content)
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('\d+', 'Replacement', content)
print(content)
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('(\d+)', r'\1 8910', content) #\1把第一个()中匹配到的字符串 拿过来
print(content)
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>'''
html = re.sub('<a.*?>|</a>', '', html) #把<a...> 或</a>替换为空''
print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
print(results)
for result in results:
print(result.strip())
7. re.compile
将一个正则表达式串编译成正则对象,以便于复用该匹配模式.
import re
content = '''Hello 1234567 World_This
is a Regex Demo'''
#便于复用 直接用pattern就好了 不需要再写一遍字符串
pattern = re.compile('Hello.*Demo', re.S) #把正则表达式字符串先编译成对象
result = re.match(pattern, content) #此时第一个参数是正则表达式对象
#result = re.match('Hello.*Demo', content, re.S) #与上面等价 此时第一个参数是正则表达式串
print(result)
'''
#还有一种写法是
pattern = re.compile('Hello.*Demo', re.S) #把正则表达式字符串先编译成对象
#直接用对象调用方法
result = pattern.match(content) #此时第一个正则表达式参数可以不用写
'''
8. 实战
import requests
import re
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.get('https://book.douban.com/',headers=headers)
print(response.status_code)
content = response.text
print(content)
#获取url 书名 作者 日期
'''
<div class="info">
<div class="title">
<a class="" href="https://book.douban.com/subject/33447868/?icn=index-latestbook-subject" title="精致的独处">精致的独处</a>
</div>
<div class="author">
[美]斯蒂芬妮·罗森布鲁姆
</div>
<div class="more-meta">
<h4 class="title">
精致的独处
</h4>
<p>
<span class="author">
[美]斯蒂芬妮·罗森布鲁姆
</span>
/
<span class="year">
2019-6
</span>
/
<span class="publisher">
未读·文艺家 北京联合出版公司
</span>
</p>
<p class="abstract">
斯蒂芬妮•罗森布鲁姆用一种全新的方式道出了独处的价值。
-
罗森布鲁姆将自己的观察、思考与心理学、社会学的研究结果相结合,以自我的亲身体验和艺术家、文学家们的生活为样本,剖析独处之于每个人的重要意义,回答什么是有益的独处,如何让独处有价值。
她以优雅的笔触记录她一年当中的旅行足迹,向我们展示了如何在一成不变的城市生活中,通过独处,梳理自己与外界...
</p>
</div>
</div>
'''
pattern = re.compile('<div class="info".*?title.*?href="(.*?)".*?more-meta.*?title">(.*?)</h4>.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</div>', re.S)
results = re.findall(pattern, content)
for result in results:
url, name, author, date = result
author = re.sub('\s', '', author)
date = re.sub('\s', '', date)
print(url, name, author, date)