《零基础学Python》——极客时间——学习笔记
2021/7/19 9:35:55
本文主要是介绍《零基础学Python》——极客时间——学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
第二章 Python基础语法
Python程序的书写规则
基础数据类型
类型判断
type()
强制类型转换
目标类型(要转换的数据)
变量的定义和常用操作
习题
题目:
练习一 变量的定义和使用
- 定义两个变量分别为美元和汇率
- 通过搜索引擎找到美元兑人民币汇率
- 使用Python计算100美元兑换的人民币数量并用print( )进行输出
代码:
第三章 序列
序列的概念
案例
概念
代码
字符串的定义和使用
字符串的常用操作
序列的基本操作
成员关系操作符
连接操作符
重复操作符
元组的定义和常用操作
元组中数字大小的比较
单个数字:
两个数字:
可当成是两个数字的叠加
120 < 220,故而结果为False。
列表和元组的区别
- 列表是中括号[],元组是小括号()
- 列表中的内容可变更,元组中的内容不可变更
fliter的功能
格式:
filter(lambda x: x < b, a)
取出a中小于b的元素
展示取出的元素
list(filter(lambda x: x < b, a))
例子:
统计取出元素的个数:
格式:
len (list (filter(lambda x: x < b, a)))
取出a中小于b的元素的个数
例子:
实现生肖查找功能
列表的定义和常用操作
基本操作:
- 增加一个元素
- 移除一个元素
习题
练习一 字符串
题目:
- 定义一个字符串Hello Python 并使用print( )输出
- 定义第二个字符串Let‘s go并使用print( )输出
- 定义第三个字符串"The Zen of Python" – by Tim Peters 并使用print( )输出
代码:
练习二 字符串基本操作
题目:
- 定义两个字符串分别为 xyz 、abc
- 对两个字符串进行连接
- 取出xyz字符串的第二个和第三个元素
- 对abc输出10次
- 判断a字符(串)在 xyz 和 abc 两个字符串中是否存在,并进行输出
代码:
练习三 列表的基本操作
- 定义一个含有5个数字的列表
- 为列表增加一个元素 100
- 使用remove()删除一个元素后观察列表的变化
- 使用切片操作分别取出列表的前三个元素,取出列表的最后一个元素
练习四 元组的基本操作
题目:
- 定义一个任意元组,对元组使用append() 查看错误信息
- 访问元组中的倒数第二个元素
- 定义一个新的元组,和 1. 的元组连接成一个新的元组
- 计算元组元素个数
代码:
第四章 条件与循环
条件语句
语法
代码
for循环
用途:
经常用for循环遍历序列
代码:
while循环
用法
通常和if条件判断语句连用
break语句
功能:
终止当前循环
continue语句
功能:
跳过本次循环
总结
for语句中的if嵌套
用for循环实现的判断星座:
while循环语句中的if嵌套
习题
练习一 条件语句的使用
题目:
- 使用if语句判断字符串的长度是否等于10,根据判断结果进行不同的输出
- 提示用户输入一个1-40之间的数字,使用if语句根据输入数字的大小进行判断,如果输入的数字在 1-10,11-20,21-30,31-40,分别进行不同的输出
代码:
练习二 循环语句的使用
题目:
- 使用for语句输出1-100之间的所有偶数
- 使用while语句输出1-100之间能够被3整除的数字
代码:
第五章:映射与字典
字典的定义和常用操作
定义和添加元素
生肖与星座案例完善
代码:
chinese_zodiac = "猴鸡狗猪鼠牛虎兔龙蛇马羊" # 定义字符串类型,存储12生肖 zodiac_name = (u"魔羯座", u"水瓶座", u"双鱼座", u"白羊座", u"金牛座", u"双子座", u"巨蟹座", u"狮子座", u"处女座", u"天秤座", u"天蝎座", u"射手座") zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22), (7, 23), (8, 23), (9, 23), (10, 23), (11, 23), (12, 23),) # 定义字典 cz_num = {} z_num = {} # 初始化关键字 for i in chinese_zodiac: cz_num[i] = 0 # 将chinese_zodiac关键字依次赋值为0 for i in zodiac_name: z_num[i] = 0 # 将zodiac_name关键字依次赋值为0 while True: # 用户输入出生年份、月份和日期 year = int(input('请输入年份:')) month = int(input('请输入月份:')) day = int(input('请输入日期:')) n = 0 while zodiac_days[n] < (month, day): if month == 12 and day > 23: break n += 1 # 输出生肖和星座 print('您的星座是:%s' % (zodiac_name[n])) print('%s 年的生肖是 %s' % (year, chinese_zodiac[year % 12])) # 将值赋给初始化的字典 cz_num[chinese_zodiac[year % 12]] += 1 # 用户当前的生肖, 出现一次就加一,生肖的名字对应的值加一 z_num[zodiac_name[n]] += 1 # 用户当前的星座,出现一次就加一,星座的名字对应的值加一 # 输出生肖和星座的统计信息 for each_key in cz_num.keys(): # .keys() 取出字典中所有的key print('生肖 %s 有 %d 个' % (each_key, cz_num[each_key])) for each_key in z_num.keys(): print('星座 %s 有 %d 个' % (each_key, z_num[each_key]))
结果:
请输入年份:2018 请输入月份:1 请输入日期:3 您的星座是:魔羯座 2018 年的生肖是 狗 生肖 猴 有 0 个 生肖 鸡 有 0 个 生肖 狗 有 1 个 生肖 猪 有 0 个 生肖 鼠 有 0 个 生肖 牛 有 0 个 生肖 虎 有 0 个 生肖 兔 有 0 个 生肖 龙 有 0 个 生肖 蛇 有 0 个 生肖 马 有 0 个 生肖 羊 有 0 个 星座 魔羯座 有 1 个 星座 水瓶座 有 0 个 星座 双鱼座 有 0 个 星座 白羊座 有 0 个 星座 金牛座 有 0 个 星座 双子座 有 0 个 星座 巨蟹座 有 0 个 星座 狮子座 有 0 个 星座 处女座 有 0 个 星座 天秤座 有 0 个 星座 天蝎座 有 0 个 星座 射手座 有 0 个 请输入年份:2021 请输入月份:3 请输入日期:25 您的星座是:白羊座 2021 年的生肖是 牛 生肖 猴 有 0 个 生肖 鸡 有 0 个 生肖 狗 有 1 个 生肖 猪 有 0 个 生肖 鼠 有 0 个 生肖 牛 有 1 个 生肖 虎 有 0 个 生肖 兔 有 0 个 生肖 龙 有 0 个 生肖 蛇 有 0 个 生肖 马 有 0 个 生肖 羊 有 0 个 星座 魔羯座 有 1 个 星座 水瓶座 有 0 个 星座 双鱼座 有 0 个 星座 白羊座 有 1 个 星座 金牛座 有 0 个 星座 双子座 有 0 个 星座 巨蟹座 有 0 个 星座 狮子座 有 0 个 星座 处女座 有 0 个 星座 天秤座 有 0 个 星座 天蝎座 有 0 个 星座 射手座 有 0 个 请输入年份:
列表推导式与字典推导式
习题
练习一 字典的使用
题目:
- 定义一个字典,分别使用a、b、c、d作为字典的关键字,值为任意内容
- 为该字典增加一个元素‘c’:'cake’后,将字典输出到屏幕
- 取出字典中关键字为d的值
代码:
练习二 集合的使用
题目:
- 将字符串hello中每个字符赋值给一个集合,将这个集合输出到屏幕’
代码:
第六章 文件的输入输出
文件的内建函数
文件的常用操作
代码:
# # 将小说的主要人物记录在文件中 # # # 写入文件 的 基本流程:open() -> write() -> close() # file1 = open('name.txt', 'w') # 打开的文件名称为"name.txt",模式为"写入模式" 并将其赋值给一个变量 # # file1.write(u'诸葛亮') # 写入人物 # file1.close() # 关闭并保存 # # # 读取文件 的 基本流程:open() -> read() -> close() # file2 = open('name.txt') # mode默认为“mode=r”——只读模式 # print(file2.read()) # file2.close() # # # 写入一个新人物 # file3 = open('name.txt', 'a') # file3.write('刘备') # file3.close() # # 读取多行中的一行 # file4 = open('name.txt') # print(file4.readline()) # # # 读取每一行同时进行操作(以行的方式读取,逐行操作) # file5 = open('name.txt') # for line in file5.readlines(): # readlines 逐行读取 # print(line) # print('=====') # 进行一个操作,操作完成后回到文件的开头,然后再次对文件进行操作 file6 = open('name.txt') file6.tell() # 告诉用户“文件指针”在哪 # 指针的功能:当没有进行人为操作时,程序会记录当前操作的位置,然后继续向后进行操作 print('当前文件指针的位置 %s' % file6.tell()) print('当前读取到了一个字符,字符的内容是 %s' % file6.read(1)) # 只读取文件的 1个字符 print('当前文件指针的位置 %s' % file6.tell()) # 需求:操作完成后,向回到文件的开头,再次进行操作 # 操纵指针 # 第一个参数:偏移位置(偏移量) 第二个参数:0——表示从文件开头偏移 1——表示从当前位置偏移 2——表示从文件结尾偏移 file6.seek(0) # file6.seek(5, 0) 从文件开头 向后偏移 5个位置 print('我们进行了seek操作') print('当前文件指针的位置 %s' % file6.tell()) # 又一次读取一个字符 print('当前读取到了一个字符,字符的内容是 %s' % file6.read(1)) # 只读取文件的 1个字符 print('当前文件指针的位置 %s' % file6.tell()) file6.close()
结果:
当前文件指针的位置 0 当前读取到了一个字符,字符的内容是 a 当前文件指针的位置 1 我们进行了seek操作 当前文件指针的位置 0 当前读取到了一个字符,字符的内容是 a 当前文件指针的位置 1
练习一 文件的创建和使用
题目:
- 创建一个文件,并写入当前日期
- 再次打开这个文件,读取文件的前4个字符后退出
代码:
# 1. 创建一个文件,并写入当前日期 import datetime now = datetime.datetime.now() # now变量 存储 现在的时间 new_file = open('date.txt', 'w') new_file.write(str(now)) new_file.close() # 2. 再次打开这个文件,读取文件的前4个字符后退出 again_file = open('date.txt') print(again_file.read(4)) # 打印 读取的4个字符 print(again_file.tell()) # 文件指针,提示 读取了 4个字符 again_file.close()
结果:
2021 4
第七章 错误和异常
异常的检测和处理
常见错误
1. NameError
2. SyntaxError
3. IndexError
4. KeyError
5. ValueError
6. AttributeError
7. ZeroDivisionError
8. TypeError
捕获所有错误
except Exception
异常处理
except可捕获多个异常
格式:
注意:
多个错误,需用圆括号括起来作为一个参数。
捕获成功后显示额外错误信息
注意:一般在调试程序时使用
手动抛出异常
Python raise用法
finally
不管是否产生错误都要去执行。
总结
习题
练习一 异常
题目:
- 在Python程序中,分别使用未定义变量、访问列表不存在的索引、访问字典不存在的关键字观察系统提示的错误信息
- 通过Python程序产生IndexError,并用try捕获异常处理
代码:
第八章 函数
函数的定义和常用操作
无函数版:
函数版:
完整版:
import re def find_main_characters(character_name): with open('sanguo.txt', encoding='UTF-8') as f: data = f.read().replace("\n", "") name_num = re.findall(character_name,data) return character_name, len(name_num) name_dict = {} with open('name.txt') as f: for line in f: names = line.split('|') for n in names: char_name, char_number = find_main_characters(n) name_dict[char_name] = char_number weapon_dict = {} with open('weapon.txt', encoding="UTF-8") as f: # 默认按行读取 i = 1 for line in f: if i % 2 == 1: weapon_name, weapon_number = find_main_characters(line.strip('\n')) # 读取 删除'\n'的 该行内容 weapon_dict[weapon_name] = weapon_number i = i + 1 name_sorted = sorted(name_dict.items(), key=lambda item: item[1], reverse=True) print(name_sorted[0:10]) weapon_sorted = sorted(weapon_dict.items(), key=lambda item: item[1], reverse=True) print(weapon_sorted[0:10])
结果:
函数的可变长参数
关键字参数
作用:
当没有按顺序写入参数时调用。
优点:
- 可以不用按顺序写入参数
- 更明确输入的参数究竟是什么含义
代码:
可变长参数
函数的变量作用域
全局变量
函数的迭代器与生成器
迭代器
功能
取列表当中每一个元素,对每一个元素依次进行处理,这种方法叫做迭代,能实现这种方法的函数,叫迭代器
两种函数(方法)
iter()和next()
生成器
定义
自己制作的迭代器叫生成器。
带yield的迭代器
自定义的迭代器
代码1:
for i in range(10, 20, 0.5): print(i)
会报错,range()函数不允许令float数作为其步长。
代码2:
# 实现一个支持小数步长增长的range def frange(start, stop, step): x = start while x < stop: yield x # yield 运行到yield时会进行暂停,并记录当前的位置,当再次调用next()时,它会通过当前位置再去返回一个值 x += step for i in frange(10, 20, 0.5): print(i)
结果:
10 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 16.5 17.0 17.5 18.0 18.5 19.0 19.5
Lambda表达式
作用
简化函数。
代码:
def true(): return True # 等于 def true():return True # 等于 lambda: True
def add(x, y): return x + y # 等于 def add(x, y):return x + y # 等于 lambda x, y:x + y # 参数是 x,y 返回是 x+y
lambda返回的是lambda的表达式:
<function at 0x0000015D077E20D0>
用途
代码1:
lambda x: x <= (month, day) # 参数是:x,返回的是:x <= (month, day) # 转换成函数 def find(x): return x <= (month, day)
代码2:
lambda item: item[1] # 参数是:item,返回的是:item[1] # 转换成函数 def find2(item): # 传入一个字典元素,取字典的值 return item[1] adict = {'a': '123', 'b': '456'} for i in adict.items(): print(find2(i)) # 取字典的值
Python 字典(Dictionary) items() 函数的用法。
Python内建函数
filter
功能:
filter(function, sequence)
过滤 sequence 中满足funciton的数
代码:
a = [1, 2, 3, 4, 5, 6, 7] b = list(filter(lambda x: x > 2, a)) # 过滤 a 中 满足 大于2的数 print(b)
结果:
[3, 4, 5, 6, 7]
必须转化成list,否则lambda不会被执行
map
功能:
map(function, sequence)
对sequence中的值依次按function处理
代码1:
c = [1, 2, 3] map(lambda x: x, c) # 将 c 中的值 依次 返回 x d = list(map(lambda x: x, c)) print(d) map(lambda x: x + 1, c) # 将 c 中的值 依次+1 返回 e = list(map(lambda x: x + 1, c)) print(e)
结果:
[1, 2, 3] [2, 3, 4]
代码2:
a = [1, 2, 3] b = [4, 5, 6] map(lambda x, y: x + y, a, b) c = list(map(lambda x, y: x + y, a, b)) print(c)
结果:
[5, 7, 9]
对应项依次相加输出。
reduce
功能:
reduce(function, sequence[, initial])
把序列的元素依次和初始值按照函数的方式做运算。
代码:
from functools import reduce total = reduce(lambda x, y: x + y, [2, 3, 4], 1) # 1 和 列表中第一个元素 按照 func 进行操作 print(total) # ((1+2)+3)+4
结果:
10
zip
功能一:纵向整合
代码:
exchange = zip((1, 2, 3), (4, 5, 6)) for i in exchange: print(i) # 进行了纵向整合,类比线性代数中的“矩阵转换”
结果:
(1, 4) (2, 5) (3, 6)
(1, 2, 3)
(4, 5, 6)
(1, 4)
(2, 5)
(3, 6)
功能二:字典中 key 和 value 对调
代码:
dicta = {'a': '123', 'b': '456'} dictb = zip(dicta.values(), dicta.keys()) # ('a', 'b'), ('1', '2') --> ('a', '1'), ('b', '2') print(dictb) print(dict(dictb)) # 需将其类型强制转换为 dict
结果:
<zip object at 0x0000016A531F7E40> {'123': 'a', '456': 'b'}
闭包的定义
闭包
定义:
外部函数中的变量被内部函数引用,就叫做 “闭包”
代码:
def func(): a = 1 b = 2 return a + b def sum(a): def add(b): return a + b # 返回的是int # 返回 内部函数的函数名称 return add # 返回的是function,add是内部函数的函数名称,引用add的函数 num1 = func() num2 = sum(2) # num2 相当于 sum外部函数 里面的 内部函数add print(num2(4)) # 将 num2 当成函数去调用(相当于add()),传入第二个参数 # print(type(num1)) --- int # print(type(num2)) --- function
结果:
6
add 是 函数名称或函数的引用
add() 是 函数的调用
计数器
功能:
实现一个计数器counter,每次调用它计数就会+1
代码1:
# 实现一个计数器counter,每次调用它计数就会+1 def counter(): cnt = [0] # 定义一个列表,只有一个元素为0 def add_one(): cnt[0] += 1 # 每次调用函数计数器就+1 return cnt[0] # 返回增加后的值 return add_one # 返回内部函数 num1 = counter() # 将 counter()函数 返回结果 赋值给 变量num1 print(num1) # 输出 num1 这个函数 相当于 add_one print(num1()) # 输出 add_one 这个函数的调用 print(num1()) print(num1()) print(num1()) print(num1())
结果:
1 2 3 4 5
代码2:
# 实现一个计数器counter,按指定初始值,每次调用它计数就会+1 def counter(FIRST=0): # 若没传入参数,则默认以0开始 cnt = [FIRST] # 定义一个列表,只有一个元素为FIRST def add_one(): cnt[0] += 1 # 每次调用函数计数器就+1 return cnt[0] # 返回增加后的值 return add_one # 返回内部函数 num5 = counter(5) num10 = counter(10) print(num5()) print(num5()) print(num5()) print(num10()) print(num10())
结果:
6 7 8 11 12
闭包的使用
案例:数学运算
闭包写法:
# a * x + b = y # 欲保证a, b不变,仅x变化时,可使用闭包 def a_line(a, b): def arg_y(x): return a * x + b return arg_y # a = 3, b = 5 # x = 10, y = ? # x = 20, y = ? line1 = a_line(3, 5) # line1 相当于 arg_y print(line1(10)) # line1(10) 相当于 arg_y(10) print(line1(20)) # line1(20) 相当于 arg_y(20) # 求另一条直线 # a = 5, b = 10 line2 = a_line(5, 10) print(line2(10)) print(line2(20))
结果:
35 65 60 110
外部函数是不变的量,内部函数是可变的量。
普通函数写法:
def func1(a,b,x): return a * x + b
每次均需传入a, b, x三值,不够简洁优雅
lambda写法:
def a_line2(a, b): return lambda x: a * x + b # a = 3, b = 5 # x = 10, y = ? # x = 20, y = ? new_line1 = a_line2(3, 5) print(new_line1(10)) print(new_line1(20))
更简洁优雅!
闭包和函数的区别
- 函数传递变量,闭包传递函数;
- 闭包比函数调用的参数更少;
- 闭包的代码更优雅。
装饰器的定义
描述:
想给函数增加一些功能,但又不想在函数内部添加相应的代码,就可以用“装饰器”。
time库
sleep()方法
功能:运行时停几秒
import time time.sleep(3) # 停3s
time()方法
功能:
统计1970年1月1日到现在的时间。
代码:
import time print(time.time()) # 1970年1月1日到现在走了多少秒
结果:
1611718601.273848
案例
统计函数运行时间:
# 统计函数运行了多长时间 def i_can_sleep(): time.sleep(3) start_time = time.time() i_can_sleep() stop_time = time.time() print('函数运行了 %s 秒' % (stop_time - start_time))
装饰器
功能:
将重复性的事情只做一次。
闭包和装饰器的区别:
- 闭包传入的是变量,内部函数引用的也是变量
- 装饰器传入的是函数,内部函数引用的也是函数
代码:
def timer(func): def wrapper(): start_time = time.time() func() stop_time = time.time() print("运行时间是 %s 秒" % (stop_time - start_time)) return wrapper # 统计函数运行了多长时间 @timer # 语法糖,timer——装饰函数 i_can_sleep——被装饰函数,额外代码封装在装饰函数内 def i_can_sleep(): time.sleep(3) i_can_sleep() # 相当于 num = timer(i_can_sleep()) num()
结果:
运行时间是 3.0005228519439697 秒
装饰器的使用
对带参数的函数增加装饰器
代码:
# 对带参数的函数增加装饰器 def tips(func): def nei(a, b): print('start') func(a, b) print('stop') return nei # 实现加法 @tips def add(a, b): print(a + b) # 实现减法 @tips def sub(a, b): print(a - b) print(add(4, 5)) print(sub(4, 5))
结果:
start 9 stop None start -1 stop None
装饰器带参数
代码1:
# 装饰器带参数 # 针对不同的函数装饰器有所变化——为装饰器带上参数 def new_tips(argv): def tips(func): def nei(a, b): print('start %s' % argv) func(a, b) print('stop') return nei return tips @new_tips('add') def add(a, b): print(a + b) @new_tips('sub') def sub(a, b): print(a - b) print(add(4, 5)) print(sub(4, 5))
结果:
start add 9 stop None start sub -1 stop None
代码2:
# 装饰器不仅取参数,亦可取函数名 def new_tips(argv): def tips(func): def nei(a, b): print('start %s %s' % (argv, func.__name__)) # 输出函数的名称 func(a, b) print('stop') return nei return tips @new_tips('add_module') def add(a, b): print(a + b) @new_tips('sub_module') def sub(a, b): print(a - b) print(add(4, 5)) print(sub(4, 5))
结果:
start add_module add 9 stop start sub_module sub -1 stop
装饰器的好处
- 调用函数时,不用重复编写相应的修饰代码,可以放在装饰器内;
- 装饰器代码易复用——@装饰器名称。
习题
练习一 定义装饰器,用于打印函数执行的时间
- 统计函数开始执行和结束执行的时间
- 扩展练习:为装饰器传入超时时间,函数执行超过指定时间后退出
代码:
# 1. 统计函数开始执行和结束执行的时间 import time def timer(func): def nei(): print('start time %s' % time.time()) func() print('end time %s' % time.time()) return nei @timer def i_can_sleep(): time.sleep(3) i_can_sleep()
结果:
start time 1612241463.787381 end time 1612241466.787973
练习二 定义装饰器,实现不同颜色显示执行结果的功能
- 向装饰器传递参数,通过传递的参数获取到输出的颜色
- 被装饰函数的print( )输出根据装饰器得到的颜色进行输出
代码:
# 1. 向装饰器传递参数,通过传递的参数获取到输出的颜色 # 2. 被装饰函数的print( )输出根据装饰器得到的颜色进行输出 import sys def make_color(code): def decorator(func): if (code == 0): s = 'white' return func(s) elif (code == 1): s = 'black' return func(s) else: print('wrong') return decorator @make_color(0) def color_func(s): print('颜色是:%s' % s)
结果:
颜色是:white
自定义上下文管理器
代码:
fd = open('name.txt') try: for line in fd: print(line) finally: fd.close() # 上下文管理器 # 使用with就不用写finally了,因为当其出现异常时,with会自动调用finally来将文件关闭(后面详细讲) with open('name.txt') as f: for line in f: print(line)
结果:
諸葛亮|關羽|劉備|曹操|孫權|關羽|張飛|呂布|周瑜|趙雲|龐統|司馬懿|黃忠|馬超 諸葛亮|關羽|劉備|曹操|孫權|關羽|張飛|呂布|周瑜|趙雲|龐統|司馬懿|黃忠|馬超
总结
习题
练习一 函数
- 创建一个函数,用于接收用户输入的数字,并计算用户输入数字的和
- 创建一个函数,传入n个整数,返回其中最大的数和最小的数
- 创建一个函数,传入一个参数n,返回n的阶乘
代码:
# 1. 创建一个函数,用于接收用户输入的数字,并计算用户输入数字的和 def func1(): two_num = input('请输入两个数字,用空格做分隔:') # 检查用户输入是否合法 func2(two_num) # print(type(two_num)) num1, *_, num2 = two_num print('%s 和 %s 之和是:' % (num1, num2)) print(int(num1) + int(num2)) def func2(check_number): pass func1() # 2. 创建一个函数,传入n个整数,返回其中最大的数和最小的数 def func3(*nums): print('最大的数是: %s' % max(nums)) print('最小的数是: %s' % min(nums)) func3(1, 5, 8, 32, 654, 765, 4, 6, 7) # 3. 创建一个函数,传入一个参数n,返回n的阶乘 def func4(n): if n == 0 or n == 1: return 1 else: return n * func4(n - 1) num = input('请输入要阶乘的数:') print('%s 的阶乘结果是:%s' % (num, func4(num)))
第九章 模块
模块的定义
重命名模块
将长的模块名重命名,从而简化名称。
import time as t # 重命名模块 t.time() # 引用time文件中的函数
不写模块名称的方法:
from time import sleep # 不推荐此写法,害怕导致重命名 sleep()
自定义模块及其调用
自己的模块:
def print_me(): print('me') # print_me() 一般很少有直接调用的,一般都是函数的定义
调用模块:
import mymod # 导入是不加 .py 后缀名 mymod.print_me() # 将此文件中的 函数 引用进来
习题
练习一 模块
- 导入os模块,并使用help(os)查看os模块的帮助文档
# 1. 导入os模块,并使用help(os)查看os模块的帮助文档 import os print(help(os))
第十章 语法规范
PEP8编码规范
课上相关说明:
https://www.python.org/dev/peps/pep-0008/ pycharm 安装PEP8 cmd窗口输入:pip install autopep8 Tools→Extends Tools→点击加号 Name:Autopep8(可以随便取) - Tools settings: - Programs:`autopep8` (前提是你已经安装了哦) - Parameters:`--in-place --aggressive --aggressive $FilePath$` - Working directory:`$ProjectFileDir$` - 点击Output Filters→添加,在对话框中的:Regular expression to match output中输入:`$FILE_PATH$\:$LINE$\:$COLUMN$\:.*`
如不成功,请参照下文:
pycharm设置autopep8
第十一章 面向对象编程
类与实例
面向过程编程
特点:
- 根据程序执行的顺序从上到下去编写相应的函数
代码:
# 面向过程 user1 = {'name': 'tom', 'hp': 100} user2 = {'name': 'jerry', 'hp': 80} def print_role(rolename): print('name is %s , hp is %s' % (rolename['name'], rolename['hp'])) print_role(user1)
面向对象编程
定义:
不同对象相同特征的提取,提取出来的东西就叫做类。
代码:
# 面向对象 class Player(): # 定义一个类 类名开头要用 大写字母 def __init__(self, name, hp): # __init__ 是一个特殊的方法,在类实例化之后,它会自动执行 self.name = name # self 表示 Player 这个类进行了实例化之后,这个实例的本身 self 相当于 java的this吗 self.hp = hp def print_role(self): # 定义一个方法 print('%s: %s' % (self.name, self.hp)) user1 = Player('tom', 100) # 类的实例化 user2 = Player('jerry', 90) user1.print_role() user2.print_role() # 注意:在一个类中,所有的函数(方法)第一个参数一定要带着 self
注意:
- 在一个类中,所有的函数(方法)第一个参数一定要带着 self
- 类名开头要用 大写字母
如何增加类的属性和方法
增加一个属性和方法
代码:
# 面向对象 class Player(): def __init__(self, name, hp, occu): self.name = name self.hp = hp self.occu = occu # 增加一个职业属性 def print_role(self): print('%s: %s %s' % (self.name, self.hp, self.occu)) def updateName(self, newname): # 创建一个改名的方法 self.name = newname user1 = Player('tom', 100, 'war') # 类的实例化 user2 = Player('jerry', 90, 'master') user1.print_role() user2.print_role() user1.updateName('wilson') user1.print_role() class Monster(): '定义怪物类' pass
类的封装
类的属性不想让别人访问到。
- 在类的属性前面加两个下划线"__"
代码:
# 面向对象 class Player(): def __init__(self, name, hp, occu): self.__name = name self.hp = hp self.occu = occu # 增加一个职业属性 def print_role(self): print('%s: %s %s' % (self.__name, self.hp, self.occu)) def updateName(self, newname): # 创建一个改名的方法 self.__name = newname user1 = Player('tom', 100, 'war') # 类的实例化 user2 = Player('jerry', 90, 'master') user1.print_role() user2.print_role() user1.updateName('wilson') user1.print_role()
结果:
name is tom , hp is 100 tom: 100 war jerry: 90 master wilson: 100 war wilson: 100 war
这样类的属性就不会被类的实例访问到。
只能通过方法去改变类的属性。
类的继承
继承
代码:
# 猫科动物 猫 猫 继承了 猫科动物 所使用的方法 # 猫科动物 就叫做 猫 的 父类 猫 就叫做 猫科动物 的 子类 class Monster(): '定义怪物类' def __init__(self, hp=100): # 初始化时已经有生命值了 self.hp = hp def run(self): print('移动到某个位置') class Animals(Monster): # 子类继承父类 子类括号内写入父类名字 '普通怪物' def __init__(self, hp=10): self.hp = hp class Boss(Monster): 'Boss类怪物' pass # 父类 a1 = Monster(200) print(a1.hp) a1.run() # 子类 a2 = Animals(1) print(a2.hp) a2.run()
子类可以调用父类中的属性和方法。
super
作用:
在父类中初始化的属性,子类不用重复初始化。
代码:
class Animals(Monster): # 子类继承父类 子类括号内写入父类名字 '普通怪物' def __init__(self,hp=10): super().__init__(hp) # Animals中的hp不用再进行初始化了,父类已经初始化完成了
子类方法和父类方法重名
子类调用时,子类的方法会把父类同名的方法覆盖掉。
多态
重名方法只有在实际使用时,才知道调用它的是子类还是父类的方法,说明这个方法在运行时有多种状态,这个特性被称作“多态”。
判断类的继承关系
代码:
# 判断类的继承关系 print('a1的类型是 %s' % type(a1)) print('a2的类型是 %s' % type(a2)) print('a2的类型是 %s' % type(a3)) print(isinstance(a2, Monster)) # 判断a2是否为Monster的子类,若是,则输出True,若否,则输出False
结果:
a1的类型是 <class '__main__.Monster'> a2的类型是 <class '__main__.Animals'> a2的类型是 <class '__main__.Boss'> True
额外知识
元组、列表、字符串等形式都是“class”
# 元组、列表、字符串等形式都是“class” print(type(tuple)) print(type(list)) print(type('123'))
<class 'type'> <class 'type'> <class 'str'>
所有对象都继承object这样一个父类
# 所有对象都继承object这样一个父类 print(isinstance(tuple, object)) print(isinstance(list, object)) print(isinstance('123', object))
True True True
总结
- 类是描述具有相同属性和方法这样一个对象的集合;
- 封装性、继承性、多态性;
- 类需要实例化才能使用。
类的使用-自定义with语句
功能:
- 自动处理异常
- 异常和面向对象结合起来
自定义with方法:
代码:
class Testwith(): def __enter__(self): # 开始时调用 print('run') def __exit__(self, exc_type, exc_val, exc_tb): # 结束时调用 if exc_tb is None: # 如果exc_tb没有异常的话,它的值就是None 判断是否为空用“is None” print('正常结束') else: print('has error %s' % exc_tb) # 类和抛出异常结合 # 用with简化异常的编写 with Testwith(): print('Test is running') raise NameError('testNameError') # 手动抛出异常
结果:
run Test is running has error <traceback object at 0x000002016D762B80> Traceback (most recent call last): File "D:\Python\pythonProject\with_test.py", line 15, in <module> raise NameError('testNameError') # 手动抛出异常 NameError: testNameError
重点:
- with可以简化抛出异常的编写(try…catch…)
第十二章:多线程编程
多线程编程的定义
进程:
程序运行的状态
多线程编程:
同时有大量的请求过来,我们需要对这些请求进行处理,这些处理的方法就是多线程编程。
没有线程运行
代码:
def myThread(arg1, arg2): print('%s %s' %(arg1, arg2) for i in range(1, 6, 1): t1 = myThread(i, i + 1)
结果:
1 2 2 3 3 4 4 5 5 6
多线程方法运行
代码:
import threading def myThread(arg1, arg2): print('%s %s' %(arg1, arg2) for i in range(1, 6, 1): # t1 = myThread(i, i + 1) t1 = threading.Thread(target = myThread, args = (i, i + 1)) t1.start() # 运行多线程程序
结果:
1 2 2 3 3 4 4 5 5 6
引入sleep()暂停多线程:
代码:
import threading import time def myThread(arg1, arg2): print('%s %s' %(arg1, arg2) time.sleep(1) for i in range(1, 6, 1): # t1 = myThread(i, i + 1) t1 = threading.Thread(target = myThread, args = (i, i + 1)) t1.start() # 运行多线程程序
结果:
1 2 2 3 3 4 4 5 5 6
程序直接全部打印出所有内容,运行完等了1s才结束。
把当前线程运行状态进行显示:
import threading import time from threading import current_thread # 当前线程运行的状态,进行显示 def myThread(arg1, arg2): print(current_thread().getName(), 'start') # 将当前线程的名字做标志 第一个:线程的名称;第二个:想要添加的注释 print('%s %s' % (arg1, arg2)) time.sleep(1) # 程序没有等待1s,直接输出,说明程序是 并行的 在运行的 print(current_thread().getName(), 'stop') for i in range(1, 6, 1): # t1 = myThread(i, i + 1) # 没有线程 t1 = threading.Thread(target=myThread, args=(i, i + 1)) # 第一个参数:函数名;第二个参数:传入的参数 产生5个新的线程 t1.start() # 运行多线程程序 print(current_thread().getName(), 'end') # 主程序结束之后,线程才结束 先“MainThread end”后“stop” # 主线程先结束,Thread1-5后结束
结果:
Thread-1 start 1 2 Thread-2 start 2 3 Thread-3 start 3 4 Thread-4 start 4 5 Thread-5 start 5 6 MainThread end Thread-1 stop Thread-3 stop Thread-2 stop Thread-4 stop Thread-5 stop
主程序结束之后,线程才结束 先“MainThread end”后“stop”。
线程之间的同步
有一个线程运行时,可以等待另一个线程结束。
代码:
# 实现 先“stop”后“end” import threading from threading import current_thread # 方法名非常时使用 # threading.Thread().run() # 线程中的函数调用 # 继承 threading.Thread() 然后 重写 run() --- 多态性 class Mythread(threading.Thread): # 继承时不加括号 def run(self): # 重新实现run()方法 # 1. 获取当前线程的名称——判断是否进行 线程的等待 print(current_thread().getName(), 'start') print('run') print(current_thread().getName(), 'stop') t1 = Mythread() t1.start() # Thread先结束,main后结束 t1.join() print(current_thread().getName(), 'end') # 打印主线程的显示结果
结果:
Thread-1 start run Thread-1 stop MainThread end
经典的生产者和消费者问题
当程序运行时,会不断制造大量数据,同时用户会对数据进行一系列的消耗,这个过程就是生产者和消费者问题。(类比水槽的注水与放水)
队列
同步不同线程之间的数据。
代码:
# 队列的实现 import queue q = queue.Queue() # 产生一个队列 q.put(1) # 向队列中增加一个数据 q.put(2) q.put(3) q.get() # 读取队列 按照加入的顺序进行读取
代码实现
代码1:
from threading import Thread, current_thread # 可以实现多个生产者和消费者并行的去生产和消费 import time # 休眠 import random # 产生随机数据 from queue import Queue # 导入队列库 queue = Queue(5) # 定义队列的长度 class ProducerThread(Thread): def run(self): name = current_thread().getName() # 获取生产者的线程的名字 nums = range(100) global queue # 定义一个队列的全局变量 while True: num = random.choice(nums) # 随机选择一个数字 queue.put(num) # 将随机选择的数字放入到队列当中 print('生产者 %s 生产了数据 %s' % (name, num)) t = random.randint(1, 3) # 随机的休眠时间 time.sleep(t) # 令生产者休眠 print('生产者 %s 睡眠了 %s 秒' % (name, t)) class ConsumerThread(Thread): def run(self): name = current_thread().getName() # 获取消费者的线程名称 global queue while True: num = queue.get() # 在队列中取得想要的数字 queue.task_done() # 封装好了 线程等待和同步的代码 print('消费者 %s 消耗了数据 %s' % (name, num)) # 随机的休眠时间 t = random.randint(1, 5) # 随机等待几秒 time.sleep(t) print('消费者 %s 睡眠了 %s 秒' % (name, t)) # 一个生产者和两个消费者 p1 = ProducerThread(name='p1') p1.start() c1 = ConsumerThread(name='c1') c1.start()
结果:
生产者 p1 生产了数据 74 消费者 c1 消耗了数据 74 生产者 p1 睡眠了 1 秒 生产者 p1 生产了数据 82 生产者 p1 睡眠了 1 秒 生产者 p1 生产了数据 67 消费者 c1 睡眠了 3 秒 消费者 c1 消耗了数据 82 生产者 p1 睡眠了 1 秒 生产者 p1 生产了数据 28 生产者 p1 睡眠了 1 秒 生产者 p1 生产了数据 75
代码2:
from threading import Thread, current_thread # 可以实现多个生产者和消费者并行的去生产和消费 import time # 休眠 import random # 产生随机数据 from queue import Queue # 导入队列库 queue = Queue(5) # 定义队列的长度 class ProducerThread(Thread): def run(self): name = current_thread().getName() # 获取生产者的线程的名字 nums = range(100) global queue # 定义一个队列的全局变量 while True: # 经过随机的休眠时间,往队列里添加随机的数字 num = random.choice(nums) # 随机选择一个数字 queue.put(num) # 将随机选择的数字放入到队列当中 print('生产者 %s 生产了数据 %s' % (name, num)) t = random.randint(1, 3) # 随机的休眠时间 time.sleep(t) # 令生产者休眠 print('生产者 %s 睡眠了 %s 秒' % (name, t)) class ConsumerThread(Thread): def run(self): name = current_thread().getName() # 获取消费者的线程名称 global queue while True: # 经过随机的时间,往队列里提取随机的数字 num = queue.get() # 在队列中取得想要的数字 queue.task_done() # 封装好了 线程等待和同步的代码 print('消费者 %s 消耗了数据 %s' % (name, num)) # 随机的休眠时间 t = random.randint(1, 5) # 随机等待几秒 time.sleep(t) print('消费者 %s 睡眠了 %s 秒' % (name, t)) # # 一个生产者和两个消费者 (生产慢消费快) # p1 = ProducerThread(name='p1') # p1.start() # c1 = ConsumerThread(name='c1') # c1.start() # 三个生产者和两个消费者 (生产快消费慢) p1 = ProducerThread(name='p1') p1.start() p2 = ProducerThread(name='p2') p2.start() p3 = ProducerThread(name='p3') p3.start() c1 = ConsumerThread(name='c1') c1.start() c2 = ConsumerThread(name='c2') c2.start() # 队列满时,生产者就不再去生产数据,待消费者消耗之后再进行生产
结果:
生产者 p1 生产了数据 70 生产者 p2 生产了数据 33 生产者 p3 生产了数据 95 消费者 c1 消耗了数据 70 消费者 c2 消耗了数据 33 消费者 c1 睡眠了 1 秒 消费者 c1 消耗了数据 95
第十三章 标准库
Python标准库的定义
Python标准库官方文档
重点掌握:
- Text Processing Services
- Data Types
- Generic Operating System Services
- Internet Data Handling
- Development Tools
- Debugging and Profiling
正则表达式库re
匹配
代码:
import re # 匹配 p = re.compile('a') # 定义一个要匹配的字符串 print(p.match('a')) # 被匹配的字符串 可以成功匹配 print(p.match('b')) # 不能匹配上 # 匹配一串有规律的字符 # 引入一些特殊的字符(表示字符的重复等规律),这种特殊的字符被称作“元字符” p = re.compile('cat') print(p.match('caaaaat')) # 匹配不成功,为None # 正则表达式的好处:把一些特殊的功能,用特殊的符号来表示 p = re.compile('ca*t') # 重复a用*a代替 print(p.match('caaaaat')) # 匹配成功
结果:
<re.Match object; span=(0, 1), match='a'> None None <re.Match object; span=(0, 7), match='caaaaat'>
正则表达式的元字符
常用元字符
元字符 | 功能 |
---|---|
. | 匹配任意的单个字符 |
^ | 匹配以什么样的内容做开头的字符串 |
$ | 匹配以什么样的内容做结尾的字符串 |
* | 匹配前面的字符出现0次到多次 |
+ | 匹配前面的字符出现1次到多次 |
? | 匹配前面的字符出现0次到1次 |
{m} | 表示前面的字符要出现指定的次数为m次 |
{m,n} | 示前面的字符要出现指定的次数为m~n次 |
[] | 表示中括号内的任意一个字符匹配成功即可 |
表示字符选择左边或者是右边,通常和括号用在一起(常和()搭配使用) | |
\d | 表示匹配的内容是一串数字 相当于 [1234567890]+ 或 [0-9]+ 中的一个数字 |
\D | 表示匹配的内容不包含数字 |
\s | 表示匹配的是一个字符串(a-z) |
() | 进行分组 |
^$ | 表示这一行是空行,匹配文本时,有一行是空行,什么都不包括 |
.*? | 不使用贪婪模式 |
. 元字符
功能:
匹配任意的单个字符
代码:
import re p = re.compile('.') print(p.match('c')) print(p.match('d')) # 匹配三个字符 p = re.compile('...') print(p.match('abc'))
结果:
<re.Match object; span=(0, 1), match='c'> <re.Match object; span=(0, 1), match='d'> <re.Match object; span=(0, 3), match='abc'>
^ 和 $ 元字符
功能:
^:匹配以什么样的内容做开头的字符串
$:匹配以什么样的内容做结尾的字符串
代码:
# ^ 以什么样的内容做开头 $ 以什么样的内容做结尾(从后向前进行匹配) # 搜索:表示从开头进行搜索。 import re p = re.compile('^jpg') # 匹配以jpg开头的字符串 print(p.match('jpg')) p = re.compile('jpg$') # 匹配以jpg结尾的字符串 匹配到所有以"jpg"为扩展名的文件 print(p.match('jpg'))
结果:
<re.Match object; span=(0, 3), match='jpg'> <re.Match object; span=(0, 3), match='jpg'>
* 元字符
功能:
匹配前面的字符出现0次到多次。
代码:
# * 匹配前面的字符出现0次到多次 import re p = re.compile('ca*t') print(p.match('ct')) # 匹配出现0次的cat —— 成功 print(p.match('caaaaaat')) # 匹配出现多次的cat —— 成功
结果:
<re.Match object; span=(0, 2), match='ct'> <re.Match object; span=(0, 8), match='caaaaaat'>
+ 和 ? 元字符
功能:
+:匹配前面的字符出现1次到多次
?:匹配前面的字符出现0次到1次
代码:
# + 匹配前面的字符出现1次到多次 # ? 匹配前面的字符出现0次到1次 import re p = re.compile('c?t') print(p.match('t')) # 匹配出现0次的c print(p.match('ct')) # 匹配出现1次的c q = re.compile('c+t') print(q.match('ct')) # 匹配出现1次的c print(q.match('cccct')) # 匹配出现多次的c
结果:
<re.Match object; span=(0, 1), match='t'> <re.Match object; span=(0, 2), match='ct'> <re.Match object; span=(0, 2), match='ct'> <re.Match object; span=(0, 5), match='cccct'>
{m} 元字符
功能:
表示前面的字符要出现指定的次数为m次
代码:
import re p = re.compile('ca{4}t') # 匹配出现4次的a print(p.match('caaaat'))
<re.Match object; span=(0, 6), match='caaaat'>
{m,n} 元字符
功能:
表示前面的字符要出现指定的次数为m~n次
代码:
import re p = re.compile('ca{4,6}t') # 匹配出现4~6次的a print(p.match('caaaaat'))
结果:
<re.Match object; span=(0, 7), match='caaaaat'>
[] 元字符
功能:
表示中括号内的任意一个字符匹配成功即可。
代码:
# [] 表示中括号内的任意一个字符匹配成功即可 import re p = re.compile('c[bcd]t') # 表示bcd任意一个字符匹配成功即可 print(p.match('cat')) # 匹配失败 print(p.match('cbt')) # 匹配成功 print(p.match('cct')) # 匹配成功 print(p.match('cdt')) # 匹配成功
结果:
None <re.Match object; span=(0, 3), match='cbt'> <re.Match object; span=(0, 3), match='cct'> <re.Match object; span=(0, 3), match='cdt'>
| 元字符
功能:
表示字符选择左边或者是右边,通常和括号用在一起(常和()搭配使用)
\d 元字符
功能:
表示匹配的内容是一串数字 相当于 [1234567890]+ 或 [0-9]+ 中的一个数字
\D 元字符
功能:
表示匹配的内容不包含数字
\s 元字符
功能:
表示匹配的是一个字符串(a-z)
() 元字符
功能:
进行分组
代码:
# () 进行分组 # 提取年月日份 # 2018-03-04 # (2018)-(03)-(04) # (2018)-(03)-(04).group() 提取其中的某一组 # 匹配不同内容,但长相很相似 # 2018-03-04 # 2018-04-12 # 希望提取2018-03或2018-04 # (03|04) 只提取03或04
^$ 元字符
功能:
表示这一行是空行,匹配文本时,有一行是空行,什么都不包括
.*? 元字符
功能:
不使用贪婪模式
代码:
# .*? 不使用贪婪模式 # 贪婪模式 # abcccccd # abc* # 会匹配到d前面所有的c *匹配时,会尽可能长的进行匹配 # # 非贪婪模式 # abcccccd # abc*? # # 只匹配第一个匹配上的内容,编写网页的内容匹配上非常常用 # <img /img> # <img /img>
正则表达式分组功能实例
代码:
# 利用正则实现分组功能 # 出现的字符和我们想要的字符是不是相符的 import re p = re.compile('.{3}') # 匹配三个任意字符 相当于 '...' print(p.match('bat')) # 匹配年月日,之后取出年、月、日 # q = re.compile('....-..-..') # 如果是判断数字而且是连续的情况 q = re.compile('\d-\d-\d') q = re.compile(r'\d-\d-\d') # r 告诉python程序 后面的内容 原样输出 不要进行转义 q = re.compile(r'(\d)-(\d)-(\d)') # ()把想要取出的部分进行分组 q = re.compile(r'(\d+)-(\d+)-(\d+)') # 增加加号,因为数字可能出现多次 匹配的内容:连续的数字(05和5都能匹配上) print(q.match('2018-05-10')) print(q.match('2018-05-10').group()) # 取出某一部分 .group() 取出所有的部分 print(q.match('2018-05-10').group(1)) # 取出某一部分 .group(1) 取出第一个括号包括的内容 print(q.match('2018-05-10').group(2)) # 取出某一部分 .group(2) 取出第二个括号包括的内容 print(q.match('2018-05-10').groups()) # 全取出来 year, month, day = q.match('2018-05-10').groups() # 赋给变量 print(year, month, day) # 希望在正则匹配时,不让特殊符号进行转义 print('\nx\n') print(r'\nx\n')
结果:
<re.Match object; span=(0, 3), match='bat'> <re.Match object; span=(0, 10), match='2018-05-10'> 2018-05-10 2018 05 ('2018', '05', '10') 2018 05 10 x \nx\n Process finished with exit code 0
正则表达式库函数match与search的区别
match
代码:
# match # 匹配的字符串必须和正则一一对应,匹配之前,要清楚知道字符串是以什么样的形式出现的 import re p = re.compile(r'(\d+)-(\d+)-(\d+)') print(p.match('aa2018-05-10bb').group(2)) # 匹配失败 无法进行分组,进而无法进行匹配 print(p.match('2018-05-10').group())
结果:
Traceback (most recent call last): File "D:\Python\pythonProject\43.py", line 129, in <module> print(p.match('aa2018-05-10bb').group(2)) # 匹配失败 无法进行分组,进而无法进行匹配 AttributeError: 'NoneType' object has no attribute 'group'
search
代码:
import re p = re.compile(r'(\d+)-(\d+)-(\d+)') # search # 不完全进行匹配 不要求把元字符和输入的内容完全匹配 print(p.search('aa2018-05-10bb')) # 不断搜索匹配,直到能够匹配成功 只要包含了相应的正则表达式,就能匹配成功
结果:
<re.Match object; span=(2, 12), match='2018-05-10'>
match和search各自的用法
- search经常用作在函数里面搜索指定的字符串
- match经常完全匹配之后进行分组
正则表达式库替换函数sub()的实例
功能:
进行字符串的替换。
代码:
# sub # 功能:进行字符串的替换 # sub(arg1, arg2, arg3) arg1:要匹配的内容+匹配规则(元字符) arg2:目标替换内容 arg3:替换的字符串 # 将#后面的内容替换成空的 import re phone = '123-456-789 # 这是电话号码' p2 = re.sub(r'#.*$', '', phone) # arg1:匹配#后面多个任意内容,并以之结尾 arg2:目标替换为‘’空字符串 arg3:替换的字符串为phone print(p2) # 将中间的-也替换掉 p3 = re.sub(r'\D', '', p2) # 将所有非数字字符替换成空的 print(p3)
代码:
<re.Match object; span=(2, 12), match='2018-05-10'> 123-456-789 123456789
重点:
- match和search只能match和search 到第一个匹配上的字符
- findall 可以匹配多次
日期与时间函数库
time模块
作用:
日期和时间的查看。
代码:
import time # 日期和时间的查看 print(time.time()) # 1970.1.1 至今的秒数 print(time.localtime()) # 年月日 print(time.strftime('%Y-%m-%d %H:%M:%S')) # 以特定格式输出年月日(自定义格式) print(time.strftime('%Y%m%d'))
结果:
1612482375.7951758 time.struct_time(tm_year=2021, tm_mon=2, tm_mday=5, tm_hour=7, tm_min=46, tm_sec=15, tm_wday=4, tm_yday=36, tm_isdst=0) 2021-02-05 07:46:15 20210205
datatime模块
作用:
日期和时间的修改。
代码:
# datatime # 1. 日期和时间的修改 # 获取10min之后的时间 import datetime print(datetime.datetime.now()) # 取现在的时间 newtime = datetime.timedelta(minutes=10) # 10min后的时间 timedelta——偏移量 print(datetime.datetime.now() + (newtime)) # 现在的时间 + 偏移量 # 2. 获取指定日期的指定之后的时间 # 2018-5-27之后的10天 one_day = datetime.datetime(2008, 5, 27) new_date = datetime.timedelta(days=10) print(one_day + new_date)
结果:
2021-02-05 08:48:36.233056 2021-02-05 08:58:36.233056 2008-06-06 00:00:00
数学相关库
random
功能:
根据限定条件,取随机数
代码:
import random # 根据限定条件,取随机数 r = random.randint(1, 5) # 1~5随机整数 print(r) s = random.choice(['aa', 'bb', 'cc']) # 随机字符串 print(s)
结果:
1 aa
使用命令行对文件和文件夹操作
文件与目录操作库
os.path库
代码:
功能:
文件和目录访问。
# 文件和目录访问 import os # 1. 根据相对路径. 来获取当前的绝对路径 jd = os.path.abspath('.') print(jd) # 根据相对路径. 来获取上一级的绝对路径 last_jd = os.path.abspath('..') print(last_jd) # 2. 判断文件是否存在 isExise = os.path.exists('/Python') # 括号内是对应的目录 print(isExise) # 3. 判断是否是文件 isFile = os.path.isfile('/Python') print(isFile) # 判断是否是目录 isDir = os.path.isdir('/Python') print(isDir) # 4. 路径拼接 dirJoint = os.path.join('/tmp/a/', 'b/c') # 后面跟着需要连接的路径 print(dirJoint)
结果:
D:\Python\pythonProject D:\Python True False True /tmp/a/b/c
pathlib库
代码:
from pathlib import Path # 1. 获取相对路径的. 对应的绝对路径 p = Path('.') # 先将. 封装成Path这种类型 print(p.resolve()) # 得到相对路径对应的绝对路径 相当于 os.path.abspath('.') # 2. 列举当前路径下的所有目录 —— 列表推导式 # 3. 判断是否是目录 p.is_dir() # 4. 新建一个目录(重点) q = Path('/Python/a/b/c/d/e') # 注意要用斜杠'/' 格式不能错 Path.mkdir(q, parents=True) # 建立目录 # arg1:建立的路径 arg2:自动创建上一层目录 parents=True 让自动创建 parents=False 不让自动创建 Path.rmdir('/Python/a/b/c/d/e') # 删除指定目录,非空目录无法删除
结果:
D:\Python\pythonProject Process finished with exit code 0
第十四章 机器学习库
机器学习的一般流程与NumPy安装
通用处理步骤
数据采集:
- 调查问卷
- 网络信息的采集
数据预处理:
- 单位统一
- 格式调整
数据清洗:
- 数据的缺失值和异常值的删减
- 得到优质数据
数据建模:
- 结合想要做的事情,设计相应的算法
- 把数据喂给机器
- 机器通过数据和算法得到结果
- 结果通过测试,算法可行,建立成模型
数据测试:
- 利用模型,完成自动驾驶、图像分类、语音预测等功能
NumPy库
功能:
进行数据预处理。
NumPy的数组与数据类型
代码:
import numpy as np # 根据输入数据的类型自动进行转换 arr1 = np.array([2, 3, 4]) # 定义一个列表 print(arr1) # 这个列表已经经过了numpy的封装,计算效率要远远高于自带的列表 print(arr1.dtype) # 整型 arr2 = np.array([1.2, 2.3, 3.4]) print(arr2) print(arr2.dtype) # 数学计算:列表累加 print(arr1 + arr2)
结果:
[2 3 4] int32 [1.2 2.3 3.4] float64 [3.2 5.3 7.4]
NumPy数组和标量的计算
代码:
import numpy as np # 标量运算 arr = np.array([1.2, 2.3, 3.4]) print(arr * 10) # 定义二维数组(矩阵) data = [[1, 2, 3], [4, 5, 6]] # 两个列表嵌套在一个列表中 # 通过列表转换为numpy的二维矩阵 arr2 = np.array(data) print(arr2) print(arr2.dtype) # 使二维矩阵全部为0或1 one = np.zeros(10) # 定义了一个一维的,长度为10的数组,且将数值初始化为0 print(one) two = np.zeros((3, 5)) # 定义了一个二维的,3×5的数组,且将数值初始化为0 print(two) # 使矩阵内容均为1 all_one = np.ones((4, 6)) # 定义了一个二维的,4×6的数组,且将数值初始化为1 print(all_one) # 使矩阵内容均为“空值” all_empty = np.empty((2, 3, 2)) # 定义了一个三维的,2×3×2的数组,且将数值初始化为"空值" print(all_empty) # 结果为随机值(因为空值对程序运算不安全)
结果:
[12. 23. 34.] [[1 2 3] [4 5 6]] int32 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [[0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.] [0. 0. 0. 0. 0.]] [[1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.]] [[[0. 0.] [0. 0.] [0. 0.]] [[0. 0.] [0. 0.] [0. 0.]]]
NumPy数组的索引和切片
代码:
# 切片操作 import numpy as np arr = np.arange(10) print(arr) print(arr[5]) print(arr[5:8]) # 对切片直接赋值 arr[5:8] = 10 print(arr) # 重新赋值但不改变原有数值 arr_slice = arr[5:8].copy() # 副本 arr_slice[:] = 15 # [:] 表示从第一个元素到最后一个元素全都进行了赋值 print(arr) print(arr_slice)
结果:
[0 1 2 3 4 5 6 7 8 9] 5 [5 6 7] [ 0 1 2 3 4 10 10 10 8 9] [ 0 1 2 3 4 10 10 10 8 9] [15 15 15]
pandas安装与Series结构
pandas功能:
数据预处理和数据清洗。
代码:
from pandas import Series, DataFrame import pandas as pd # 把数据自动或按照自定义的方式进行对齐显示 # 可以很灵活的处理缺失的数据(基于大部分熟知的平均值进行填充或指定的值) # 连接操作 # pandas的一维数组的相关操作 obj = Series([4, 5, 6, -7]) # 对numpy的array进行了封装 print(obj) # 好处:前面自动添加了索引,从而更方便访问到数据 # 取出索引 pandas的索引可以重复 print(obj.index) # 取出数值 print(obj.values) # 哈希运算(字典中的key不可重复) # 经过一个简单字符 经过哈希运算后 得到唯一一个复杂的字符 # 'a' --> 'asdfasdfasdfasd' # 哈希算法相同,得到的结果均一样 # 哈希值的内部存储形式——链接形式 {'a': 1, 'b': 2, 'c': 3} # 1. 将abc分别映射成一串较为复杂的字符,存储在内存中 # a -> asdhfljasdf # b -> askldjfaisddf # c -> dofjwoifjife # 字典中的key可以是:int float string tuple等 # 字典中的key不可以是:list, set # 因为他们可以重新赋值 {['a']: 1}
结果:
0 4 1 5 2 6 3 -7 dtype: int64 RangeIndex(start=0, stop=4, step=1) [ 4 5 6 -7] Traceback (most recent call last): File "D:\Python\pythonProject\pandas_test.py", line 29, in <module> {['a']: 1} TypeError: unhashable type: 'list'
Series的基本操作
代码:
import pandas as pd from pandas import Series # 对pandas中的一维数组(Series)的操作 obj2 = Series([4, 7, -5, 3], index=['d', 'b', 'c', 'a']) # 手动指定索引 print(obj2) # 对索引赋值 obj2['c'] = 6 print(obj2) # 查看索引是否在Series中 print('a' in obj2) print('f' in obj2) # 字典转化为Series sdata = {'beijing': 35000, 'shanghai': 71000, 'guangzhou': 16000, 'shenzhen': 5000} obj3 = Series(sdata) print(obj3) # 修改Series的索引 obj3.index = ['bj', 'gz', 'sh', 'sz'] print(obj3)
结果:
d 4 b 7 c -5 a 3 dtype: int64 d 4 b 7 c 6 a 3 dtype: int64 True False beijing 35000 shanghai 71000 guangzhou 16000 shenzhen 5000 dtype: int64 bj 35000 gz 71000 sh 16000 sz 5000 dtype: int64
Dataframe的基本操作
代码:
from pandas import Series, DataFrame # 类似于 电子表格 # 生成dataframe # 传入等长的列表 或 numpy的数组 # 利用字典 ,字典内用等长列表方式创建一个DataFrame data = {'city': ['shanghai', 'shanghai', 'shanghai', 'beijing', 'beijing'], 'year': [2016, 2017, 2018, 2017, 2018], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9]} # 将字典赋给DataFrame frame = DataFrame(data) print(frame) # 按指定顺序排序 frame2 = DataFrame(data, columns=['year', 'city', 'pop']) # 按year city pop 显示 print(frame2) # 提取一维数据(二维 -> 一维) print(frame2['city']) print(frame2.year) # 增加一列 frame2['new'] = 100 print(frame2) # 利用计算生成新列 # city 是 beijing 新列为True 不是 beijing 新列为False frame2['cap'] = frame2.city == 'beijing' print(frame2) # 字典嵌套 pop = {'beijing': {2008: 1.5, 2009: 2.0}, 'shanghai': {2008: 2.0, 2009: 3.6} } frame3 = DataFrame(pop) print(frame3) # 行列互换(行列式的转置) print(frame3.T) # 重新索引(对当前的索引重新修改) obj4 = Series([4.5, 7.2, -5.3, 3.6], index=['b', 'd', 'c', 'a']) obj5 = obj4.reindex(['a', 'b', 'c', 'd', 'e']) print(obj5) # NaN代表空值 # 过滤缺失值 # 统一填充空值 obj6 = obj4.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0) print(obj6) # 统一填充空值为相邻元素的值 # 填充当前值上面的或下面的值 obj7 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) obj7_new = obj7.reindex(range(6)) print(obj7_new) # 利用前面的值进行填充 obj7_newf = obj7.reindex(range(6), method='ffill') print(obj7_newf) # 利用后面的值进行填充 obj7_newb = obj7.reindex(range(6), method='bfill') print(obj7_newb) # 把缺失的数据删除 from numpy import nan as NA # 从numpy导入一个缺失值并将其重命名为NA data = Series([1, NA, 2]) print(data) print(data.dropna()) # 删除 缺失值 # DataFrame 的删除缺失数据 data2 = DataFrame([[1., 6.5, 3], [1., NA, NA], [NA, NA, NA]]) print(data2) print(data2.dropna()) # 出现NA的行列均会被删除 # 删除全是缺失值的一行,而有部分缺失值的一行进行保留 print(data2.dropna(how='all')) data2[4] = NA print(data2) # 删除全是缺失值的一列,而有部分缺失值的一列进行保留 print(data2.dropna(axis=1, how='all')) # 填充方法:fillna 把缺失值全部填充为0 data2.fillna(0) # 修改的只是data2的副本 print(data2.fillna(0)) print(data2.fillna(0, inplace=True)) # 对data2直接进行修改 print(data2)
结果:
city year pop 0 shanghai 2016 1.5 1 shanghai 2017 1.7 2 shanghai 2018 3.6 3 beijing 2017 2.4 4 beijing 2018 2.9 year city pop 0 2016 shanghai 1.5 1 2017 shanghai 1.7 2 2018 shanghai 3.6 3 2017 beijing 2.4 4 2018 beijing 2.9 0 shanghai 1 shanghai 2 shanghai 3 beijing 4 beijing Name: city, dtype: object 0 2016 1 2017 2 2018 3 2017 4 2018 Name: year, dtype: int64 year city pop new 0 2016 shanghai 1.5 100 1 2017 shanghai 1.7 100 2 2018 shanghai 3.6 100 3 2017 beijing 2.4 100 4 2018 beijing 2.9 100 year city pop new cap 0 2016 shanghai 1.5 100 False 1 2017 shanghai 1.7 100 False 2 2018 shanghai 3.6 100 False 3 2017 beijing 2.4 100 True 4 2018 beijing 2.9 100 True beijing shanghai 2008 1.5 2.0 2009 2.0 3.6 2008 2009 beijing 1.5 2.0 shanghai 2.0 3.6 a 3.6 b 4.5 c -5.3 d 7.2 e NaN dtype: float64 a 3.6 b 4.5 c -5.3 d 7.2 e 0.0 dtype: float64 0 blue 1 NaN 2 purple 3 NaN 4 yellow 5 NaN dtype: object 0 blue 1 blue 2 purple 3 purple 4 yellow 5 yellow dtype: object 0 blue 1 purple 2 purple 3 yellow 4 yellow 5 NaN dtype: object 0 1.0 1 NaN 2 2.0 dtype: float64 0 1.0 2 2.0 dtype: float64 0 1 2 0 1.0 6.5 3.0 1 1.0 NaN NaN 2 NaN NaN NaN 0 1 2 0 1.0 6.5 3.0 0 1 2 0 1.0 6.5 3.0 1 1.0 NaN NaN 0 1 2 4 0 1.0 6.5 3.0 NaN 1 1.0 NaN NaN NaN 2 NaN NaN NaN NaN 0 1 2 0 1.0 6.5 3.0 1 1.0 NaN NaN 2 NaN NaN NaN 0 1 2 4 0 1.0 6.5 3.0 0.0 1 1.0 0.0 0.0 0.0 2 0.0 0.0 0.0 0.0 None 0 1 2 4 0 1.0 6.5 3.0 0.0 1 1.0 0.0 0.0 0.0 2 0.0 0.0 0.0 0.0
层次化索引
代码:
# 层次化索引 # 多层次索引 # Series——一维数据 DataFrame——二维数据 from pandas import Series, DataFrame import numpy as np data3 = Series(np.random.randn(10), index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]]) print(data3) # 提取索引b下边的数据 print(data3['b']) # 提取多个索引 print(data3['b':'c']) # Series转化成DataFrame 一维数据转化成二维数据 print(data3.unstack()) # DataFrame转化成Series 二维数据转化成一维数据 print(data3.unstack().stack())
结果:
a 1 0.254799 2 1.096555 3 0.283251 b 1 1.009634 2 -0.643421 3 1.774040 c 1 0.550576 2 -0.687114 d 2 0.308054 3 0.788189 dtype: float64 1 1.009634 2 -0.643421 3 1.774040 dtype: float64 b 1 1.009634 2 -0.643421 3 1.774040 c 1 0.550576 2 -0.687114 dtype: float64 1 2 3 a 0.254799 1.096555 0.283251 b 1.009634 -0.643421 1.774040 c 0.550576 -0.687114 NaN d NaN 0.308054 0.788189 a 1 0.254799 2 1.096555 3 0.283251 b 1 1.009634 2 -0.643421 3 1.774040 c 1 0.550576 2 -0.687114 d 2 0.308054 3 0.788189 dtype: float64
Matplotlib的安装与绘图
代码:
import matplotlib.pyplot as plt import numpy as np # # 绘制简单的曲线 # plt.plot([1, 3, 5], [4, 8, 10]) # x轴 y轴 # plt.show() # 显示曲线 # # # 绘制numpy中的数据 # x = np.linspace(-np.pi, np.pi, 100) # x的定义域为 -3.14~3.14,中间间隔100个元素 # plt.plot(x, np.sin(x)) # 横坐标:x值 纵坐标:sinx值 # plt.show() # # # 绘制多条曲线 # x = np.linspace(-np.pi * 2, np.pi * 2, 100) # 定义域为: -2pi 到 2pi # plt.figure(1, dpi=50) # 创建图表 dpi:精度(绘画图形的详细程度)精度越高,图片产生的体积越大,画的图越清晰 # for i in range(1, 5): # 画四条线 # plt.plot(x, np.sin(x / i)) # # plt.show() # # # 绘制直方图 # plt.figure(1, dpi=50) # 创建图表1, dpi代表图片精细度, dpi越大文件越大, 杂志要300以上 # data = [1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 4] # plt.hist(data) # 只要传入数据,直方图就会统计数据出现的次数 # # plt.show() # # # 绘制散点图 # x = np.arange(1, 10) # y = x # fig = plt.figure() # 创建图表 # plt.scatter(x, y, c='r', marker='o') # c = 'r' 表示散点的颜色为红色,marker 表示指定散点的形状为圆形 # plt.show() # pandas 和 matplotlib 结合 # pandas读取数据——matplotlib绘图 import pandas as pd # # iris = pd.read_csv("./iris_training.csv") # print(iris.head()) # 显示iris前五行信息 # # # 基于前两列绘制散点图 # iris.plot(kind='scatter', x='120', y='4') # 散点图 x轴 y轴 # # # 没啥用,只是让pandas的plot()方法在pyCharm上显示 # plt.show() # 封装matplotlib库的库 import seaborn as sns import warnings # 忽略警告 warnings.filterwarnings("ignore") # 当产生warnings时,进行ignore iris = pd.read_csv("./iris_training.csv") # 设置样式 sns.set(style="white", color_codes=True) # 设置绘制格式为散点图 # sns.jointplot(x="120", y="4", data=iris, size=5) # distplot绘制曲线 # sns.distplot(iris['120']) # 绘制120对应的散点图 # 没啥用,只是让pandas的plot()方法在pyCharm上显示 # plt.show() # 基于不同分类,对点进行不同颜色的划分 # FacetGrid 一般绘图函数 # hue 彩色显示分类0/1/2 # plt.scatter 绘制散点图 # add_legend() 显示分类的描述信息 # sns.FacetGrid(iris, hue="virginica", size=5).map(plt.scatter, "120", "4").add_legend() # hue 基于virginica不同取值,对散点不同颜色绘制 # 显示第3、4列相应的信息 sns.FacetGrid(iris, hue="virginica", size=5).map(plt.scatter, "setosa", "versicolor").add_legend() # 没啥用,只是让pandas的plot()方法在pyCharm上显示 plt.show()
结果:
机器学习分类的原理
工作原理:
特征值与对应的分类结果数据输入到机器学习算法中——得到模型——测试模型——输入新值进行预测
Tensorflow的安装
根据特征值分类的模型和代码
第十五章 爬虫
网页数据的采集与urllib库
代码:
# 获取网页 from urllib import request url = 'http://www.baidu.com' # http协议 # 解析url response = request.urlopen(url, timeout=1) # timeout 设置超时时间(超过1s没打开就放弃打开网页) print(response.read().decode('utf-8')) # 直接读会读出乱码,需要解析需要编码的格式为utf-8
网页常见的两种请求方式get和post
代码:
# 请求网页两种方式 from urllib import parse # parse用来处理post数据 from urllib import request # GET方式 # 输入网址时,后面跟着要传给网页的参数 # 把要传给网页服务器的信息,写在url地址内 # httpbin.org/get?a=123&bb=456 告诉服务器要给它传给a和b两个值 之后服务器会显示出来 # 好处:往服务器传递数据时很简单;坏处:传输数据大小的限制 response = request.urlopen('http://httpbin.org/get', timeout=1) # 后面没有data参数的为get方式 print(response.read()) # POST方式 # 提交用户名,密码时,用post提交 在网页中输入完用户名和密码没有在url地址栏出现 data = bytes(parse.urlencode({'word': 'hellp'}), encoding='utf8') # 用data封装数据 response2 = request.urlopen('http://httpbin.org/post', data=data) # data=data 指定要传输的数据 print(response2.read().decode('utf-8')) import urllib import socket # 套接字库(网络超时一般发生于此) # 超时情况 try: response3 = request.urlopen('http://httpbin.org/get', timeout=0.1) except urllib.error.URLError as e: if isinstance(e.reason, socket.timeout): # 判断error的错误是否是超时引起的 print('TIME OUT')
结果:
b'{\n "args": {}, \n "headers": {\n "Accept-Encoding": "identity", \n "Host": "httpbin.org", \n "User-Agent": "Python-urllib/3.8", \n "X-Amzn-Trace-Id": "Root=1-601f3179-477c6caf31b7d3e6394fe965"\n }, \n "origin": "1.50.125.140", \n "url": "http://httpbin.org/get"\n}\n' { "args": {}, "data": "", "files": {}, "form": { "word": "hellp" }, "headers": { "Accept-Encoding": "identity", "Content-Length": "10", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "Python-urllib/3.8", "X-Amzn-Trace-Id": "Root=1-601f317a-116916d86dd759e02cda01f4" }, "json": null, "origin": "1.50.125.140", "url": "http://httpbin.org/post" } TIME OUT
HTTP头部信息的模拟
# url伪装成浏览器去请求网页信息 from urllib import request, parse url = 'http://httpbin.org/post' headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Cache-Control": "max-age=259200", "Host": "httpbin.org", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36", "X-Amzn-Trace-Id": "Root=1-601f3d71-47afea5509bb17d15ab795ec" } dict = { 'name': 'value' } data = bytes(parse.urlencode(dict), encoding='utf8') req = request.Request(url=url, data=data, headers=headers, method='POST') response = request.urlopen(req) print(response.read().decode('utf-8'))
{ "args": {}, "data": "", "files": {}, "form": { "name": "value" }, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Cache-Control": "max-age=259200", "Content-Length": "10", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36", "X-Amzn-Trace-Id": "Self=1-601f3dee-7861d78308a6c5be459b26a8;Root=1-601f3d71-47afea5509bb17d15ab795ec" }, "json": null, "origin": "1.50.125.140", "url": "http://httpbin.org/post" }
requests库的基本使用
# get请求 import requests url = 'http://httpbin.org/get' data = {'key': 'value', 'abc': 'xyz'} # 传递给服务器的数据 # .get是使用get方式请求url,字典类型的data不用进行额外处理 response = requests.get(url, data) print(response.text) # post请求 url = 'http://httpbin.org/post' data = {'key': 'value', 'abc': 'xyz'} # .post表示为post方法 response = requests.post(url, data) # 返回类型为json格式 print(response.json())
结合正则表达式爬取图片链接
import requests import re content = requests.get('http://www.cnu.cc/discoveryPage/hot-人像').text print(content) # <div class="grid-item work-thumbnail"> # <a href="(http://www.cnu.cc/works/244938)" class = "thumbnail" target="_blank"> # <div class="title">( Fashion kids | 复古童年 )</div> # <div class="author">LynnWei </div> # <a href="(.*?)" .*?title">( .*? )</div> pattern = re.compile(r'<a href="(.*?)".*?title">(.*?)</div>', re.S) results = re.findall(pattern, content) print(results) # 显示的是 列表中的元组 形式 # 把列表中每个元素取出来 for result in results: url, name = result print(url, re.sub('\s', '', name)) # \s匹配空白字符 \n等特殊符号全能被\s匹配上,进而替换成空值''
Beautiful Soup的安装和使用
# 无需编写正则,也可以匹配html语言 html_doc = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ from bs4 import BeautifulSoup # 将网页的内容导入进去 soup = BeautifulSoup(html_doc, 'lxml') # 用lxml格式解析html # 处理为标准的html格式 print(soup.prettify()) # 找到title标签 print(soup.title) # title标签里的内容 print(soup.title.string) # 找到p标签 print(soup.p) # 找到p标签class的名字 print(soup.p['class']) # 找到第一个a标签 print(soup.a) # 找到所有的a标签 print(soup.find_all('a')) # 找到id为link3的标签 print(soup.find(id="link3")) # 找到所有<a>标签的链接 for link in soup.find_all('a'): print(link.get('href')) # 找到文档中所有的文本内容 print(soup.get_text())
使用爬虫爬取新闻网站
# requests 抓取文字 beautiful soup 进行处理 from bs4 import BeautifulSoup import requests # 告诉网站我们是一个合法的浏览器 headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8", "Connection": "close", "Cookie": "_gauges_unique_hour=1; _gauges_unique_day=1; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1", "Referer": "http://www.infoq.com", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER" } url = 'https://www.infoq.com/news/' # 取得网页完整内容 def craw(url): response = requests.get(url, headers=headers) print(response.text) # craw(url) # 取得新闻标题 def craw2(url): response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, 'lxml') for title_href in soup.find_all('div', class_='news_type_block'): print([title.get('title') for title in title_href.find_all('a') if title.get('title')]) craw2(url) # 翻页 for i in range(15, 46, 15): url = 'http://www.infoq.com/cn/news/' + str(i) # print(url) craw2(url)
使用爬虫爬取图片链接并下载图片
# 通过requests实现图片的批量下载 # 获取图片的链接地址 from bs4 import BeautifulSoup import requests import os import shutil headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8", "Connection": "close", "Cookie": "_gauges_unique_hour=1; _gauges_unique_day=1; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1", "Referer": "http://www.infoq.com", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER" } url = 'http://www.infoq.com/presentations' # 下载图片 # Requests 库封装复杂的接口,提供更人性化的 HTTP 客户端,但不直接提供下载文件的函数。 # 需要通过为请求设置特殊参数 stream 来实现。当 stream 设为 True 时, # 上述请求只下载HTTP响应头,并保持连接处于打开状态, # 直到访问 Response.content 属性时才开始下载响应主体内容 def download_jpg(image_url, image_localpath): response = requests.get(image_url, stream=True) if response.status_code == 200: with open(image_localpath, 'wb') as f: response.raw.deconde_content = True shutil.copyfileobj(response.raw, f) # 取得演讲图片 def craw3(url): response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, 'lxml') for pic_href in soup.find_all('div', class_='items__content'): for pic in pic_href.find_all('img'): imgurl = pic.get('src') dir = os.path.abspath('.') filename = os.path.basename(imgurl) imgpath = os.path.join(dir, filename) print('开始下载 %s' % imgurl) download_jpg(imgurl, imgpath) # craw3(url) # 翻页 j = 0 for i in range(12, 37, 12): url = 'http://www.infoq.com/presentations' + str(i) j += 1 print('第 %d 页' % j) craw3(url)
这篇关于《零基础学Python》——极客时间——学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-24Python编程基础详解
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程
- 2024-11-17在FastAPI项目中添加一个生产级别的数据库——本地环境搭建指南
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器
- 2024-11-16四种数据科学Web界面框架快速对比:Rio、Reflex、Streamlit和Plotly Dash
- 2024-11-14获取参数学习:Python编程入门教程