1 正则表达式简介
正则表达式(处理字符串强大的工具,有特定的语法结构) 功能:实现字符串的检索,替换,匹配验证
2 常用匹配方法
match() 从字符串起始位置匹配正则表达式,如果匹配,就返回匹配成功结果如果不匹配,就返回None。 参数1 正则表达式 参数2 要匹配的字符串
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}',content)
print(result)
print(result.group())#输出匹配的内容
print(result.span())#输出匹配的范围
41
Hello 123 4567 World_This
(0, 25)
匹配目标 从字符串中提取一部分内容 可以使用()
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\s(\d+)\sWorld',content)
print(result)
print(result.group())
print(result.group(1))
print(result.group(2))
print(result.span())
Hello 123 4567 World
123
4567
(0, 20)
通用匹配 . 匹配任意字符 除换行符
* 匹配前面的字符无限次
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$',content)
print(result)
print(result.group())
Hello 123 4567 World_This is a Regex Demo
贪婪与非贪婪
# 贪婪模式,.*会匹配尽可能多的字符,直到剩下一个数字7和(\d+)匹配
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$',content)
print(result)
print(result.group(1))
7
贪婪匹配下,. 会尽可能多的匹配字符 使用.? 拒绝贪婪模式 尽可能少匹配字符
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$',content)
print(result)
print(result.group(1))
1234567
3 修饰符
import re
content = '''Hello 1234567 World_This
is a Regex Demo'''
result = re.match('^He.*?(\d+).*?Demo$',content) # 匹配不了换行符,在每一行内进行匹配
print(result.group(1))
AttributeError: 'NoneType' object has no attribute 'group'
. 匹配换行符之外的任意字符 添加修饰符 re.S (使.匹配包括换行符在内的所有字符)
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))
1234567
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配 ,影响^和$
re.S 使.匹配包括换行符在内的所有字符
re.U 根据Unicode字符集解析字符 影响 \w \W \b \B
网页匹配 常用 re.S re.L
4 转义匹配
.匹配除换行符以外的任意字符 如果目标字符串里面包含.
import re
content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com',content)
print(result)
遇到正则匹配模式的特殊字符 在前面加反斜杠转义
4.1 search()
search()匹配整个字符串 返回第一个成功匹配的结果 匹配失败 返回None match() 从字符串起始位置匹配正则表达式
import re
content = 'Auto Hello 1234567 World_This is a Regex Demo'
result = re.match('He.*?(\d+).*Demo',content)
print(result)#返回None
import re
content = 'Auto Hello 1234567 World_This is a Regex Demo'
result = re.search('He.*?(\d+).*Demo',content)
print(result)
None
4.1.1 实例:
利用search方法 提取 html文档中 齐秦 往事随风
查看文件 html.txt
import re
html = '''
'''result = re.search('li.*?active.*?singer="(.*?)">(.*?)',html,re.S)
print(result)
print(result.group(1))
print(result.group(2))
(.*?)',html,re.S)
print(result)
[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风'), ('/4.mp3', 'beyond', '光辉岁月'), ('/5.mp3', '陈慧琳', '记事本'), ('/6.mp3', '邓丽君', '但愿人长久')]
遍历 依次获取每组内容
for results in result:
print(results)
('/2.mp3', '任贤齐', '沧海一声笑')
('/3.mp3', '齐秦', '往事随风')
('/4.mp3', 'beyond', '光辉岁月')
('/5.mp3', '陈慧琳', '记事本')
('/6.mp3', '邓丽君', '但愿人长久')
对应索引依次取出
for results in result:
print(results[0],results[1],results[2])
/2.mp3 任贤齐 沧海一声笑
/3.mp3 齐秦 往事随风
/4.mp3 beyond 光辉岁月
/5.mp3 陈慧琳 记事本
/6.mp3 邓丽君 但愿人长久
4.3 sub()
参数1 规则 参数2 规则 参数3 字符串
strs = '34iaU8hw9kcj2k3O0jc7oqqw8W'
去掉所有数字
import re
strs = '34iaU8hw9kcj2k3O0jc7oqqw8W'
strs = re.sub('\d+','',strs)
print(strs)
iaUhwkcjkOjcoqqwW
获取html文本 所有li节点的歌名
import re
html = '''
'''results = re.findall('
\s*?()?(\w+)()?\s*?',html,re.S)for result in results:
print(result[1])
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久
利用sub方法 去掉a节点 再用findall方法提取
import re
html = '''
'''html = re.sub('|','',html) # 用参数2来替换参数1
# print(html)
results = re.findall('
(.*?)',html,re.S)# print(results)
for result in results:
print(result.strip())#去掉字符串两边的空格或者换行符
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久
4.4 compile()
compile() 将正则字符串编译成正则表达式对象 以便复用 也可以传入修饰符 例如re.S 相当于做了一层封装
import re
str1 = '2016-12-25 12:00'
str2 = '2017-12-17 11:55'
str3 = '2018-12-23 15:00'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern,'',str1)
result2 = re.sub(pattern,'',str2)
result3 = re.sub(pattern,'',str3)
print(result1,result2,result3)
2016-12-25 2017-12-17 2018-12-23
5 正则匹配规则
模式
描述
\w
匹配字母、数字、下划线
\W
匹配非字母、数字、下划线
\s
匹配任意空白字符,等价于[\t\n\r\f]
\S
匹配任意非空字符
\d
匹配任意数字,等价于[0-9]
\D
匹配任意非数字的字符
\A
匹配字符串开头
\Z
匹配字符串结尾,如果存在换行,只匹配到换行前的结束字符串
\z
匹配字符串结尾,如果存在换行,同时还会匹配换行符
\G
匹配最后匹配完成的位置
\n
匹配一个换行符
\t
匹配一个制表符
^
匹配一行字符串的开头
$
匹配一行字符串的结尾
.
匹配任意字符,除换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符串
[...]
用来表示一组字符,单独列出 例如[amk] 匹配a,m或k
[^...]
不在[]中的字符 例如[^abc] 匹配除了a,b,c之外的字符
*
匹配0个或多个表达式
+
匹配1个或多个表达式
?
匹配0个或1个前面的表达式定义的片段,非贪婪模式
{n}
精确匹配n个前面的表达式
{n,m}
匹配n到m次由前面表达式定义的片段,贪婪模式
a|b
匹配a或b
( )
匹配括号内的表达式,也表示一个组
6 实战
利用requests库和正则表达式 抓取猫眼电影TOP100
分析
offset 代表偏移量 如果为n 电影序号为n+1~n+10 每页显示10个
获取100 分开请求10次 offset 分别为0 10 20...90 利用正则提取相关信息
抓取页面
import requests
#爬取第一页 页面信息
def get_one_page(url):
header = {
"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16",
}
response = requests.get(url,headers=header)
if response.status_code == 200:#判断是否请求成功
return response.text
return None
def main():
url = 'http://maoyan.com/board/4'
html = get_one_page(url)#调用请求函数
print(html)
main()
分析页面
电影信息对应节点为
提取排名 class 为 board-index i节点内 正则
.*?board-index.*?>(.*?)电影图片 查看为第二个img链接
.*?board-index.*?>(.*?).*?data-src="(.*?)"电影名字 p节点 class 为name
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?)主演
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?)发布时间
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?)评分
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*?定义分析页面的方法 parse_one_page()
import requests
import re
def get_one_page(url):
header = {
"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16",
}
response = requests.get(url,headers=header)
if response.status_code == 200:
return response.text
return None
def parse_one_page(html):
pattern = re.compile(
'
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*?',re.S)
items = re.findall(pattern,html)
print(items)
# 定义一个main函数 调用get_one_page 发送请求 打印结果
def main():
url = 'http://maoyan.com/board/4'
html = get_one_page(url)
# print(html)
parse_one_page(html)
main()
将匹配结果遍历 生成字典,单页面电影提取
import requests
import re
import json
# 请求页面
def get_one_page(url):
header = {
"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16",
}
response = requests.get(url,headers=header)
if response.status_code == 200:
return response.text
return None
#解析页面
def parse_one_page(html):# html为网页源码
pattern = re.compile(
'
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*?',re.S)#定义规则
items = re.findall(pattern,html)#查找整个页面
# print(items)
#遍历结果生成字典
for item in items:
yield {
'index':item[0],
'image': item[1],
'title': item[2].strip(),
'actor': item[3].strip()[3:] if len(item[3]) > 3 else'',
'time': item[4].strip()[5:] if len(item[4]) > 5 else '',
'score': item[5].strip()+item[6].strip()
}
#返回一个生成器 yield
#写入文件
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
print(type(json.dumps(content)))
f.write(json.dumps(content,ensure_ascii=False)+'\n')
# 定义一个main函数 调用get_one_page 发送请求 打印结果
def main():
url = 'http://maoyan.com/board/4'
html = get_one_page(url)
# print(html)
for item in parse_one_page(html):#遍历生成器
write_to_file(item)
main()
分页爬取 定义一个main函数 调用get_one_page 发送请求 打印结果
def main(offset):
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
# print(html)
for item in parse_one_page(html):#遍历生成器
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
main(offset = i *10)