正则表达式是通过特殊的字符序列,实现字符串的检索、替换、匹配验证。在爬虫时,使用正则表达式可以方便我们快速提取到HTML中的信息
书写规则
项目 | Value |
---|---|
[abc] | abc中的一个 |
[a-z] | a-z中的一个 |
[0-9] | 0-9中的一个 |
[a-f0-5] | a-f或0-5中的一个 |
[ab][de][12] | 每个[]取一个,连起来 |
match()
从字符串的开头开始对整个字符串进行匹配,一但开头匹配不成功就报错,如果不匹配,返回None
import re
content = 'id:5874268 zwdashuaige'
ret = re.match('id:\w{7}',content)
print(ret.group())
#print(ret)
输出结果:
id:5874268
#<re.Match object; span=(0, 10), match='id:5874268'>
我们写定义了一个字符串content,包含字母、空格、数字、冒号。然后通过’id:\w{7}'来匹配这个字符串,id是匹配的开头,\w’表示匹配字母、数字、下划线,{7}表示匹配7个字符
import re
content = 'id:5874268 zwdashuaige'
ret = re.match('\w{2}:\d{7}\s\w+',content)
print(ret.group())
输出结果:
id:5874268 zwdashuaige
但这些用\w \d都非常麻烦,我们可以直接用万能匹配的方式 .* ,分别表示匹配任意字符(除换行符)和无限个字符,结合在一起就是匹配任意个字符
import re
content = 'id:5874268 zwdashuaige'
ret = re.match('id.*e',content)
print(ret.group())
输出结果
id:5874268 zwdashuaige
匹配到的都是引号内的内容,如果我们只要部分内容,可以用把想要的内容放在括号内,括号()代表开始和结束的位置,同时每个括号代表一个分组,用group(1)、group(2)······的方式传递
import re
content = 'id:5874268 zwdashuaige'
ret = re.match('id.*(\d+)\szw.*?(\w+)',content)
print(ret.group(1))
print(ret.group(2))
输出结果:
8
dashuaige
这里会涉及到贪婪匹配的概念,在贪婪匹配下,.*会匹配尽可能多的字符,所以导致(\d+)只匹配到了一个数字8。这种情况下, 我们可以使用非贪婪匹配. *?,所有的非贪婪匹配加个?就行了。 如上述代码
match()还有个参数,可以扩展匹配的范围,不加参数匹配的范围只有一行内容
例如:
import re
content = '''id:5874268
zwdashuaige'''
ret = re.match('id.*shuaige',content,re.S)
print(ret.group())
输出结果:
id:5874268
zwdashuaige
search()
从左到右扫描整个字符串,返回第一个与模式匹配成功的内容
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="邓丽君"><i class="fa fa-user"></i>但愿人长久</a>
</li>
</ul>
</div>'''
result = re.findall('singer="(\w+).*>(\w+)</a>', html)
print(result)
输出结果:
[('任贤齐', '沧海一声笑'), ('齐秦', '往事随风'), ('beyond', '光辉岁月'), ('陈慧琳', '记事本'), ('邓丽君', '但愿人长久')]
sub
sub()可以用来替换文本,先匹配要替换的字符串,再用另一字符串将它替换,通过count参数来指定替换次数
import re
content = '''zwid5874268 zwdashuaige'''
ret = re.sub('id(\d+)','666',content)
print(ret)
输出结果:
zw666 zwdashuaige
compile()
conmpile() 可以将正则字符串编译成正则表达式对象,以便在后面的匹配中重复使用
import re
content1 = '2019-01-01 12:00'
content2 = '2019-01-02 12:30'
content3 = '2019-01-03 13:00'
pattern = re.compile('(\d+)-(\d+)-(\d+)\s.*')
result_1 = re.match(pattern, content1)
result_2 = re.match(pattern, content2)
result_3 = re.match(pattern, content3)
print('Year:' + result_1.group(1) + ' Month:' + result_1.group(2) + ' Day:' + result_1.group(3))
print('Year:' + result_2.group(1) + ' Month:' + result_2.group(2) + ' Day:' + result_2.group(3))
print('Year:' + result_3.group(1) + ' Month:' + result_3.group(2) + ' Day:' + result_3.group(3))
输出结果:
import re
content1 = '2019-01-01 12:00'
content2 = '2019-01-02 12:30'
content3 = '2019-01-03 13:00'
pattern = re.compile('(\d+)-(\d+)-(\d+)\s.*')
result_1 = re.match(pattern, content1)
result_2 = re.match(pattern, content2)
result_3 = re.match(pattern, content3)
print('Year:' + result_1.group(1) + ' Month:' + result_1.group(2) + ' Day:' + result_1.group(3))
print('Year:' + result_2.group(1) + ' Month:' + result_2.group(2) + ' Day:' + result_2.group(3))
print('Year:' + result_3.group(1) + ' Month:' + result_3.group(2) + ' Day:' + result_3.group(3))
实战
import re
import requests
url = 'https://read.douban.com/provider/all'
# 请求头部伪装
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
}
response = requests.get(url, headers=headers)
text = response.text
# 正则表达式匹配
result_list = re.findall(r'<div class="name">(.*?)</div>', text, re.DOTALL)
# 输出结果
for result in result_list:
print(result)
部分结果:
安徽文艺出版社
博集天卷
百花洲文艺出版社
北京阅览文化传播有限公司
八光分文化
重庆大学出版社
读客文化
电子工业出版社
······