正则表达式基础
元字符
B站教学视频: 正则表达式元字符基本使用
量词
贪婪匹配和惰性匹配
惰性匹配如下两张图,而 .* 就表示贪婪匹配,即尽可能多的匹配到符合的字符串,如果使用贪婪匹配,那么结果就是图中的情况三
python中re模块
re模块的常用方法
import re
# findall(正则表达式, 待匹配的字符串) -> 符合正则表达式的内容(以列表的形式返回)
# 含义:匹配字符串中所有符合正则表达式的内容(以列表的形式返回)
res_findall = re.findall(r"\d+", "中国移动:10086,中国联通:10010")
print(res_findall) # ['10086', '10010']
# re.finditer(正则表达式, 待匹配的字符串) -> 符合正则表达式的内容(以迭代器的形式返回)
# 含义:匹配字符串中所有符合正则表达式的内容(以迭代器的形式返回)
res_finditer = re.finditer(r"\d+", "中国移动:10086,中国联通:10010")
print(res_finditer) # <callable_iterator object at 0x000001CB2875B340>
for item in res_finditer:
"""
下面两行输出语句的输出结果如下:
<re.Match object; span=(5, 10), match='10086'>
10086
<re.Match object; span=(16, 21), match='10010'>
10010
item 中还有其他的方法,如item.start()/item.end()分别表示
匹配到的字符串在原字符串中的起始索引和结束索引
"""
print(item) # 得到match对象
print(item.group()) # 得到匹配的字符串
# re.search(正则表达式, 待匹配的字符串) -> 符合正则表达式的内容(返回match对象)
# 含义:匹配字符串中第一个匹配到的符合正则表达式的内容(返回match对象)
res_search = re.search(r"\d+", "中国移动:10086,中国联通:10010")
print(res_search) # <re.Match object; span=(5, 10), match='10086'>
print(res_search.group()) # 10086
# 上述三种方法都是全文匹配,而match是从头开始匹配
# re.match(正则表达式, 待匹配的字符串) -> 符合正则表达式的第一个字符串内容(返回match对象)
# 含义:从待匹配的字符串的第一个字符开始匹配,将匹配到的第一个结果返回,返回的是match对象
res_match = re.match(r"\d+", "中国移动:10086,中国联通:10010")
print(res_match) # None,字符串开头不是数字,所以等于匹配不成功,结果为空
# print(res_match.group()) # 报错
res_match = re.match(r"\d+", "10086,中国联通:10010")
print(res_match) # <re.Match object; span=(0, 5), match='10086'>
print(res_match.group()) # 10086
# 预加载
# 应用场景:在爬虫中,想要从网页中匹配到想要的内容,匹配的正则表达式可能会很复杂,
# 而又多次的使用到该正则表达式,则可以预加载正则表达式
# 如下,好处就是该正则可以反复使用
obj = re.compile(r"\d+")
res1 = obj.findall("中国移动:10086,中国联通:10010")
res2 = obj.finditer("中国移动:10086,中国联通:10010")
res3 = obj.search("中国移动:10086,中国联通:10010")
res4 = obj.match("中国移动:10086,中国联通:10010")
分组匹配
s = """
<div class="jay">周杰伦</div>
<div class="jj">林俊杰</div>
"""
# (?P<name>.*?) 分组匹配(P为大写),相当于把括号中的.*?匹配到的内容给变量name
# 然后通过item.group('name')获取到name的值
# 只要把想要单独获取的内容按以上形式:(?P<xxx>正则表达式) 即可获取
# re.S 的作用就是让 . 也可以匹配到换行符
# flags 是re模块中compile、match、findall等方法的一个参数,具体用法可以百度
obj = re.compile(r'<div class=".*?">(?P<name>.*?)</div>', re.S)
res = obj.finditer(s)
print(res) # <callable_iterator object at 0x0000020F2E89AEC0>
for item in res:
"""
输出结果如下:
<re.Match object; span=(5, 31), match='<div class="jay">周杰伦</div>'>
<div class="jay">周杰伦</div>
周杰伦
<re.Match object; span=(36, 61), match='<div class="jj">林俊杰</div>'>
<div class="jj">林俊杰</div>
林俊杰
"""
print(item) # <re.Match object; span=(5, 31), match='<div class="jay">周杰伦</div>'>
print(item.group()) # <div class="jay">周杰伦</div>
print(item.group('name')) # 周杰伦
注:关于re模块方法中的flags参数作用,可以百度一下
案例——豆瓣top250(re解析版)
B站视频教程:爬取豆瓣top250电影
import requests
import re
import csv
url = "https://movie.douban.com/top250"
headers = {
"User-Agent": "xxx(写上自己电脑的)"
}
resp = requests.get(url, headers=headers)
# print(resp.text) # 没加headers之前结果为空,说明网站有一些反扒机制
pattern = (r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>.*?'
r'导演: (?P<director>.*?) .*?主演: (?P<performer>.*?)...<br>.*?'
r'<span class="rating_num" property="v:average">(?P<score>\d.\d)</span>')
obj = re.compile(pattern, re.S)
res = obj.finditer(resp.text)
# 把获取到的数据存入CSV文件,方便以后对数据进行操作
# 关于CSV文件,请百度
f = open('data.csv', mode='w', encoding='utf-8')
csv_writer = csv.writer(f) # 表示向文件写入数据
for i in res:
# print(i.group('name'))
# print(i.group('director'))
# print(i.group('performer'))
# print(i.group('score').strip())
dic = i.groupdict() # 将数据以字典形式返回
# print(dic)
# 将字典的值按行写入文件,文件中的每一行就是一部电影的信息
# csv文件中,每一行数据以逗号分隔每个值
csv_writer.writerow(dic.values())
f.close()
resp.close()
print("数据解析完成!")
部分csv文件内容如下: