Datawhale | python基础 | Day5】正则表达式/OS/daterime/http请求
以下学习资源来自菜鸟教程: http://www.runoob.com/python3/python3-reg-expressions.html
1、正则表达式re
- 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
- re 模块使 Python 语言拥有全部的正则表达式功能。
- compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
- re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
1.1 常用函数
- re.match:re.match(pattern, string, flags=0)
尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。- pattern 匹配的正则表达式
- string 要匹配的字符串
- flags 标志位,用于控制正则表达式的匹配方式,如是否区分大小写以及多行匹配等等
- 匹配成功re.match方法返回一个匹配的对象,否则返回None。
- 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
- group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
- groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re
print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配
"""
运行结果:
(0, 3)
None
"""
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print ("matchObj.group() : ", matchObj.group())
print ("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
else:
print ("No match!!")
"""
运行结果:
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
"""
- re.search: re.search(pattern, string, flags=0)
扫描整个字符串并返回第一个成功的匹配,参数与match相同
import re
print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
"""
运行结果:
(0, 3)
(11, 14)
"""
line = "Cats are smarter than dogs";
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print ("searchObj.group() : ", searchObj.group())
print ("searchObj.group(1) : ", searchObj.group(1))
print ("searchObj.group(2) : ", searchObj.group(2))
else:
print ("Nothing found!!")
"""
运行结果:
searchObj.group() : Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter
"""
- re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配 - re.sub:re.sub(pattern, repl, string, count=0)
用于替换字符串中的匹配项- pattern : 正则中的模式字符串
- repl : 替换的字符串,也可为一个函数
- string : 要被查找替换的原始字符串
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
import re
phone = "2004-959-559 # 这是一个电话号码"
# 删除注释
num = re.sub(r'#.*$', "", phone)
print ("电话号码 : ", num)
# 移除非数字的内容
num = re.sub(r'\D', "", phone)
print ("电话号码 : ", num)
"""
运行结果:
电话号码 : 2004-959-559
电话号码 : 2004959559
"""
# ----repl 参数是一个函数-----
# 将匹配的数字乘于 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
"""
运行结果:
A46G8HFD1134
"""
- compile:re.compile(pattern[, flags])
函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。- pattern : 一个字符串形式的正则表达式
- flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
- re.I 忽略大小写
- re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
- re.M 多行模式
- re.S 即为’ . ‘并且包括换行符在内的任意字符(’ . '不包括换行符)
- re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
- re.X 为了增加可读性,忽略空格和’ # '后面的注释
import re
pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写
m = pattern.match('Hello World Wide Web')
print(m) # 匹配成功,返回一个 Match 对象
print(m.group(0)) # 返回匹配成功的整个子串
print(m.span(0)) # 返回匹配成功的整个子串的索引
print(m.group(1)) # 返回第一个分组匹配成功的子串
print(m.span(1)) # 返回第一个分组匹配成功的子串的索引
print(m.group(2)) # 返回第二个分组匹配成功的子串
print(m.span(2)) # 返回第二个分组匹配成功的子串
print(m.groups()) # 等价于 (m.group(1), m.group(2), ...)
# m.group(3) # 不存在第三个分组
"""
运行结果:
<re.Match object; span=(0, 11), match='Hello World'>
Hello World
(0, 11)
Hello
(0, 5)
World
(6, 11)
('Hello', 'World')
"""
- findall:findall(string[, pos[, endpos]])
- 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
- match 和 search 是匹配一次 findall 匹配所有。
- string 待匹配的字符串。
- pos 可选参数,指定字符串的起始位置,默认为 0。
- endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
print(result1)
print(result2)
"""
运行结果:
['123', '456']
['88', '12']
"""
- re.finditer:re.finditer(pattern, string, flags=0)
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
import re
it = re.finditer(r"\d+","12a32bc43jf3")
for match in it:
print (match.group() )
"""
运行结果:
12
32
43
3
"""
2、os模块
os 模块提供了非常丰富的方法用来处理文件和目录。
常用方法见链接:http://www.runoob.com/python3/python3-os-file-methods.html
#OS模块
#os模块就是对操作系统进行操作,使用该模块必须先导入模块:
import os
#getcwd() 获取当前工作目录(当前工作目录默认都是当前文件所在的文件夹)
result = os.getcwd()
print(result)
#chdir()改变当前工作目录
os.chdir('/home/sy')
result = os.getcwd()
print(result)
open('02.txt','w')
#操作时如果书写完整的路径则不需要考虑默认工作目录的问题,按照实际书写路径操作
open('/home/sy/下载/02.txt','w')
#listdir() 获取指定文件夹中所有内容的名称列表
result = os.listdir('/home/sy')
print(result)
#mkdir() 创建文件夹
#os.mkdir('girls')
#os.mkdir('boys',0o777)
#makedirs() 递归创建文件夹
#os.makedirs('/home/sy/a/b/c/d')
#rmdir() 删除空目录
#os.rmdir('girls')
#removedirs 递归删除文件夹 必须都是空目录
#os.removedirs('/home/sy/a/b/c/d')
#rename() 文件或文件夹重命名
#os.rename('/home/sy/a','/home/sy/alibaba'
#os.rename('02.txt','002.txt')
#stat() 获取文件或者文件夹的信息
#result = os.stat('/home/sy/PycharmProject/Python3/10.27/01.py)
#print(result)
#system() 执行系统命令(危险函数)
#result = os.system('ls -al') #获取隐藏文件
#print(result)
#环境变量
'''
环境变量就是一些命令的集合
操作系统的环境变量就是操作系统在执行系统命令时搜索命令的目录的集合
'''
#getenv() 获取系统的环境变量
result = os.getenv('PATH')
print(result.split(':'))
#putenv() 将一个目录添加到环境变量中(临时增加仅对当前脚本有效)
#os.putenv('PATH','/home/sy/下载')
#os.system('syls')
#exit() 退出终端的命令
#os模块中的常用值
#curdir 表示当前文件夹 .表示当前文件夹 一般情况下可以省略
print(os.curdir)
#pardir 表示上一层文件夹 ..表示上一层文件夹 不可省略!
print(os.pardir)
#os.mkdir('../../../man')#相对路径 从当前目录开始查找
#os.mkdir('/home/sy/man1')#绝对路径 从根目录开始查找
#name 获取代表操作系统的名称字符串
print(os.name) #posix -> linux或者unix系统 nt -> window系统
#sep 获取系统路径间隔符号 window ->\ linux ->/
print(os.sep)
#extsep 获取文件名称和后缀之间的间隔符号 window & linux -> .
print(os.extsep)
#linesep 获取操作系统的换行符号 window -> \r\n linux/unix -> \n
print(repr(os.linesep))
#导入os模块
import os
#以下内容都是os.path子模块中的内容
#abspath() 将相对路径转化为绝对路径
path = './boys'#相对
result = os.path.abspath(path)
print(result)
#dirname() 获取完整路径当中的目录部分 & basename()获取完整路径当中的主体部分
path = '/home/sy/boys'
result = os.path.dirname(path)
print(result)
result = os.path.basename(path)
print(result)
#split() 将一个完整的路径切割成目录部分和主体部分
path = '/home/sy/boys'
result = os.path.split(path)
print(result)
#join() 将2个路径合并成一个
var1 = '/home/sy'
var2 = '000.py'
result = os.path.join(var1,var2)
print(result)
#splitext() 将一个路径切割成文件后缀和其他两个部分,主要用于获取文件的后缀
path = '/home/sy/000.py'
result = os.path.splitext(path)
print(result)
#getsize() 获取文件的大小
#path = '/home/sy/000.py'
#result = os.path.getsize(path)
#print(result)
#isfile() 检测是否是文件
path = '/home/sy/000.py'
result = os.path.isfile(path)
print(result)
#isdir() 检测是否是文件夹
result = os.path.isdir(path)
print(result)
#islink() 检测是否是链接
path = '/initrd.img.old'
result = os.path.islink(path)
print(result)
#getctime() 获取文件的创建时间 get create time
#getmtime() 获取文件的修改时间 get modify time
#getatime() 获取文件的访问时间 get active time
import time
filepath = '/home/sy/下载/chls'
result = os.path.getctime(filepath)
print(time.ctime(result))
result = os.path.getmtime(filepath)
print(time.ctime(result))
result = os.path.getatime(filepath)
print(time.ctime(result))
#exists() 检测某个路径是否真实存在
filepath = '/home/sy/下载/chls'
result = os.path.exists(filepath)
print(result)
#isabs() 检测一个路径是否是绝对路径
path = '/boys'
result = os.path.isabs(path)
print(result)
#samefile() 检测2个路径是否是同一个文件
path1 = '/home/sy/下载/001'
path2 = '../../../下载/001'
result = os.path.samefile(path1,path2)
print(result)
#os.environ 用于获取和设置系统环境变量的内置值
import os
#获取系统环境变量 getenv() 效果
print(os.environ['PATH'])
#设置系统环境变量 putenv()
os.environ['PATH'] += ':/home/sy/下载'
os.system('chls')
3、datetime模块
学习材料:http://www.runoob.com/python/python-date-time.html
- Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能。
- Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间。
- 时间间隔是以秒为单位的浮点小数。
- 每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示。
- Python 的 time 模块下有很多函数可以转换常见日期格式。如函数time.time()用于获取当前时间戳。
- 我们可以使用 time 模块的 strftime 方法来格式化日期
- python中时间日期格式化符号:
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身
import time
import datetime
print(time.time() )#时间戳显示为1508228106.49
print(time.strftime('%Y-%m-%d %H:%M:%S')) #以字符串的形式格式化出来显示 最常用的,显示出来为2017-10-17 16:15:06
print(time.mktime(time.localtime())) #以时间戳的形式
print(time.localtime()) #时间戳
print(time.gmtime()) #以元祖的形式显示
print(time.asctime()) #显示出来为Tue Oct 17 16:15:06 2017
print(time.strftime('%A'))
print(datetime.datetime.now()) #显示为2017-10-17 16:16:55.733000 与datetime.today显示一样,显示当前时间
now1 = datetime.datetime.now()
print(now1.isocalendar()) #显示为(2017, 42, 2) 代表2017年的第42周星期2
print(now1.isoweekday()) #显示周几
print(datetime.datetime.now() - datetime.timedelta(days=5) )#显示计算日期时间差
"""
运行结果:
1548838851.989318
2019-01-30 17:00:51
1548838851.0
time.struct_time(tm_year=2019, tm_mon=1, tm_mday=30, tm_hour=17, tm_min=0, tm_sec=51, tm_wday=2, tm_yday=30, tm_isdst=0)
time.struct_time(tm_year=2019, tm_mon=1, tm_mday=30, tm_hour=9, tm_min=0, tm_sec=51, tm_wday=2, tm_yday=30, tm_isdst=0)
Wed Jan 30 17:00:51 2019
Wednesday
2019-01-30 17:00:51.989844
(2019, 5, 3)
3
2019-01-25 17:00:51.990019
"""
starttime = datetime.datetime.now()
time.sleep(3) #延迟150秒 可以写自己的程序所用时间
endtime = datetime.datetime.now()
print((endtime - starttime).seconds) #计算时间差 单位为秒
time_difference = (endtime - starttime).seconds #int类型
hours = time_difference / 3600
minutes = time_difference / 60
seconds = time_difference % 60
finall_time = '经过了' + str(hours) + '小时' + str(minutes) + '分钟' + str(seconds) + '秒' #int转化为str
print(finall_time)
"""
运行结果:
3
经过了0.0008333333333333334小时0.05分钟3秒
"""
i = datetime.datetime.now()
print ("当前的日期和时间是 %s" % i)
print ("ISO格式的日期和时间是 %s" % i.isoformat() )
print ("当前的年份是 %s" %i.year)
print ("当前的月份是 %s" %i.month)
print ("当前的日期是 %s" %i.day)
print ("dd/mm/yyyy 格式是 %s/%s/%s" % (i.day, i.month, i.year) )
print ("当前小时是 %s" %i.hour)
print ("当前分钟是 %s" %i.minute)
print ("当前秒是 %s" %i.second)
"""
运行结果:
当前的日期和时间是 2019-01-30 17:12:28.257517
ISO格式的日期和时间是 2019-01-30T17:12:28.257517
当前的年份是 2019
当前的月份是 1
当前的日期是 30
dd/mm/yyyy 格式是 30/1/2019
当前小时是 17
当前分钟是 12
当前秒是 28
"""
4、http请求
- python内置了urllib包来处理http请求,主要是一下几个模块:
- urllib.error 处理异常模块
- urllib.parse 解析url模块
- urllib.request 请求url模块
- urllib.response 响应模块
- urllib.robotparser 解析 robots.txt文件
- 打开url或者对象
urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
4.1 get请求
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib
# import urllib2 # python3中没有 urllib2 用urllib.request替代
# get请求
resu = urllib.request.urlopen('https://www.baidu.com', data=None, timeout=10)
data = resu.read().decode()
#打开文件
fo = open('test.txt','a+',encoding = 'utf-8') # 打开文件 这里网络数据流的编码需要和写入的文件编码一致
fo.write(data) # 写入文件
fo.close() # 关闭文件
fo = open('test.txt','r',encoding = 'utf-8')
print(fo.read())
"""
运行结果:
<html>
<head>
<script>
location.replace(location.href.replace("https://","http://"));
</script>
</head>
<body>
<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html><html>
<head>
<script>
location.replace(location.href.replace("https://","http://"));
</script>
</head>
<body>
<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>
"""
4.2 post请求
import urllib
import json
url = 'http://www.daily.com/ABC/ABC/ABC'
values = {
"abc":"XXXXX",
"efg":"XXXXX"
}
headers = {'Content-Type': 'application/json'} # 设置请求头 告诉服务器请求携带的是json格式的数据
request = urllib.request.Request(url=url, headers=headers, data=json.dumps(values).encode(encoding='UTF8')) # 需要通过encode设置编码 要不会报错
response = urllib.request.urlopen(request) # 发送请求
logInfo = response.read().decode() # 读取对象 将返回的二进制数据转成string类型
print(logInfo)
5、任务打卡
- 请用户输入一个时间,输出选项所对应的现在时间,告诉用户这两个时间相隔的天数,小时数,分钟数和秒数。
from datetime import datetime,timedelta
time1 = datetime.strptime(input('请输入yyyy-mm-dd hh:mm:ss格式的时间:'),'%Y-%m-%d %H:%M:%S')
time2 = datetime.now()
timediff = time2-time1
print('您输入的时间距离现在:{}天{}小时{}分钟{}秒'.format(timediff.days,(timediff.seconds)//(60*60),((timediff.seconds)%(60*60))//60,((timediff.seconds)%(60*60))%60))
"""
运行结果:
请输入yyyy-mm-dd hh:mm:ss格式的时间:2019-01-29 00:00:00
您输入的时间距离现在:1天19小时28分钟52秒
"""
- 请用户输入电话及邮箱,判断用户输入是否合法。
import re
pattern1_1 = re.compile(r'^1\d{10}$')
pattern1_2 = re.compile(r'(^\d{3,4})(\W|_)*(\d{7,8})$')
while True:
num = input('请输入您的电话号码:')
if len(num) == 11 and re.match(pattern1_1,num):
print('格式正确!您输入的手机号为:{}'.format(num))
break
elif re.match(pattern1_2,num):
print('格式正确!您输入的固定电话为:{}'.format(num))
break
else:
print('号码输入有错,请重新输入。')
continue
pattern2 = re.compile(r'^[A-Za-z0-9_-]+@[A-Za-z0-9_-]+\.com$')
while True:
mail = input('请输入您的电子邮箱地址,形如 xxxxxxx@xxx.com:')
if re.match(pattern2,mail):
print('格式正确!您输入的邮箱是:{}'.format(mail))
break
else:
print('邮箱输入有错,请重新输入。')
continue
"""
运行结果:
请输入您的电话号码:13925918987
格式正确!您输入的手机号为:13925918987
请输入您的电子邮箱地址,形如 xxxxxxx@xxx.com:dawei@hxj.com
格式正确!您输入的邮箱是:dawei@hxj.com
"""
- 对http://www.baidu.com 进行请求,并用正则化匹配图片内容。将百度图标爬取下来保存至本地。
import re
import ssl
import urllib.request
from PIL import Image
import matplotlib.pyplot as plt
response = urllib.request.urlopen("http://www.baidu.com")
response = response.read()
response = response.decode('utf-8') #python3
reg = r'src="(.+?\.png)"' #正则表达式,得到图片地址
imgre = re.compile(reg) #re.compile() 可以把正则表达式编译成一个正则表达式对象.
imglist = re.findall(imgre,response) #re.findall() 方法读取response 中包含 imgre(正则表达式)的数据
x = 0
for imgurl in imglist:
imgurl='https:'+imgurl
urllib.request.urlretrieve(imgurl,'%s.png' % x)
x += 1
img_open = Image.open('0.png')
plt.imshow(img_open)
plt.show()
运行结果如下: