八周内容笔记
day22
很多笔记内容都在代码块里
01-高阶函数练习题
简单的回忆了一下map和reduce
1.将下列每个学生及其成绩组合为一个字典,再转换为列表。
列表形式:[{‘name’:‘张三’, math:90},{‘name’:‘李四’, math:89},…]
names = ['张三', '李四', '小明', '小红']
math = [90, 89, 88, 99]
english = [98, 78, 66, 82]
chinese = [23, 98, 100, 72]
print(list(map(lambda x, y, m, n: {'name': x, 'math': y, 'english': m, 'chinese': n}, names, math, english, chinese)))
2.使用reduce求10的阶乘
from functools import reduce
list1 = [i for i in range(1, 11)]
print(reduce(lambda x, y: x * y, list1, 1))
02-有参装饰器
装饰器是真的有点绕
一个登录系统,判断某位用户是会员还是白嫖用户
def id_judge(kind):
def outter(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if result == '登录成功':
print('尊敬的VIP用户' if kind == 'VIP' else '万恶的白嫖用户', end=',')
return '登录成功'
else:
return '登录失败'
return wrapper
return outter
@id_judge('VIP')
def login(user, password):
if user == 'admin' and password == '123456':
return '登录成功'
else:
return '登录失败'
print(login('admin', '123456'))
装饰器的应用场景:
插入日志,性能测试,事务处理,web权限校验,Cache有效性测试等位置可以使用(web开发)。
装饰器优点:能够不改变原函数从而使其具有新功能。
缺点:不好理解,性能不太好
似乎数据分析不太用得上装饰器?
03-重试机制
import requests
from retrying import retry
# python中的retrying模块提供的retry方法,可以直接以语法糖的形式装饰给需要重试的函数
# @retry -> 这样的写法等于永久性的重试
# stop_max_attempt_number = 5最多重试五次
# wait_fixed=2000等待2000毫秒再重试
# wait_random_min=1000, wait_random_max=3000 -> 最少等待1000毫秒,最多等待3000毫秒,在这之间随机
@retry(stop_max_attempt_number = 5, wait_random_min=1000, wait_random_max=3000)
def requests_get(href):
print('正在请求或正在重试', href)
response = requests.get(url=href)
print(response)
URL_List = [
'https://www.baidu.com/',
'https://www.jd.com/',
'https://a123b.123/',
'https://www.taobao.com/'
]
for i in URL_List:
requests_get(i)
04-请求缓存
cache:缓存
requests-cache模块可以借助install_cache方法在本地留存请求网站的缓存,当有了这个网站的缓存以后,再次请求此网站,优先使用缓存下来的网页内容,缓存内容会以sqlite文件的形式保存在当前文件夹。
import requests
import requests_cache
requests_cache.install_cache(cache_name='cache_file')
# 如果网页更新了,我们需要重新加载缓存,先删除已存在缓存,再重新加载
# requests_cache.clear() -> 删除缓存
# requests_cache.clear()
URL = 'https://movie.douban.com/top250?start=0'
Headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.34'
}
response = requests.get(url=URL, headers=Headers)
print(response.status_code)
print(response.text)
day23
01-异常捕获
一、错误和异常
1.语法错误,编辑器直接提示某个位置有错误。
2.逻辑错误,程序在运行过程中产生的错误。
二、异常捕获
有些时候程序报了错必须要将bug解决掉;但是有些时候我们明知道程序可能会在某些地方产生错误,但是这个错误不影响正常的工作、程序的运行等,并且这个错误解决起来花费的人力、物力与解决这个bug产生的价值严重不匹配,我们选择性忽视掉bug的存在,就可以借助异常捕获来实现这个功能。
1.try…except语法
for i in range(-5, 6):
try:
print(10 / i)
print(1 + '2')
print('12345, 上山打老虎')
except ZeroDivisionError as err:
print(f'出错了,出错原因:{err}')
except Exception as err:
print(err)
异常捕获语法一:
try:
可能会报错的代码(注意:只要此处一报错,立马执行except)
except Exception as err:
Exception --> python中最大的异常类(所有异常原因的集合)
出错后执行的代码
except …:
出错后执行的代码
多个except可以报了什么类型的错误,执行相应的解决的代码。
2.异常捕获的else语句
try:
a = int(input('请输入一个整数:'))
b = int(input('请输入一个整数:'))
result = f'{a} / {b} = {a / b}'
except ZeroDivisionError as err:
print(f'报错了,报错原因:{err},0不能作为除数')
except ValueError as err:
print(f'报错了,报错原因:{err},输入错误')
else:
print(result)
异常捕获中,try中的代码是可能产生错误的代码,一般我们将额外的代码添加到else子句中。
3.finally子句
存在于finally下的代码,无论程序是否出错都会被执行
file = open('./01-异常捕获.py', 'r', encoding='utf-8')
try:
result = file.write('写入测试内容')
except Exception as err:
print('文件操作失败')
finally:
file.close()
02-重试机制添加异常捕获
import requests
from retrying import retry
@retry(stop_max_attempt_number=10)
def requests_get(link):
response = requests.get(url=link)
print(f'访问{link}成功,访问状态码{response.status_code}')
URL_List = [
'https://www.baidu.com/',
'https://jd.com/',
'https://a123b.123/',
'https://www.taobao.com/'
]
for i in URL_List:
try:
requests_get(i)
except Exception as err:
print(f'访问{i}出错,出错原因{err}')
# 为什么添加异常捕获,上方重试了10次却只打印了一次错误
# retry方法自带异常捕获,直到最后一次重试结束才会将最终报错抛出来
03-迭代器
一、什么是迭代?
迭代在python中是一个非常强大的功能,它可以用于访问字符串、列表、集合、字典、元组等容器中的元素,还可以节省内存。
迭代是通过for循环遍历这些容器中的元素的过程,所以我们也可以称能够使用for循环的容器为可迭代对象,还有一个东西也可以被for循环遍历,它叫做迭代器。
二、什么是迭代器(iter)?
迭代器是可迭代对象的一个子集,它可以记住遍历的位置。
三、迭代器的性质
1.可以进行遍历。
2.打印迭代器无法查看其中的元素,也无法使用len方法统计迭代器中元素个数。
3.如果要获取迭代器中的元素,就必须按照顺序一个一个的取元素。
4.某个元素被从迭代器中取出以后,那么迭代器中就不会再有这个元素
四、如何创建迭代器?
# 1.使用iter方法将容器转为迭代器。
# 2.创建一个生成器。(迭代器包含生成器,生成器一定是迭代器,但是迭代器不一定是生成器)
str1 = 'abcde'
a = iter(str1)
print(a, type(a))
# 返回:<str_iterator object at 0x00000221C00697C0> <class 'str_iterator'>
# print(len(a)) # TypeError: object of type 'str_iterator' has no len()
五、获取迭代器中的元素
print(next(a)) #a
print(next(a)) #b
for i in a:
print(i) #c、d、e
# print(next(a)) #StopIteration -> 停止迭代
这个迭代器就是一次性的,迭代器中元素取完,迭代器中就没有元素,失去利用价值,迭代器中元素取完,自动销毁迭代器。
day24
01-生成器
一、什么是生成器(generator)?
生成器一定是迭代器,但是迭代器不一定是生成器。
能生成迭代器的并且使用yield关键字的函数被称为生成器。
二、生成器的性质
a.生成器返回的是一个迭代器。
b.在调用生成器函数时,函数体并不执行,只是返回一个生成器对象。
c.在对生成器对象使用next方法或者循环遍历时,生成器函数才真正执行。
三、生成器的使用
1.验证在调用生成器函数时,函数体并不执行,只是返回一个生成器对象。
def func_1():
print('我是一个生成器函数')
yield
result = func_1()
print(result)
# 返回:<generator object func_1 at 0x000001E19AECCC10>
2.空值生成器产生的数据的个数和数值
# 生成器能产生多少数据取决于函数体内有多少个yield会被执行。
def func_2():
yield 100
yield 200
if 10 > 20:
yield 300
return 400
yield 500
result = func_2()
print(result)
# 返回:<generator object func_1 at 0x0000022982C89660>
# <generator object func_2 at 0x0000022982C89510>
print(next(result)) #100
print(next(result)) #200
# print(next(result)) #StopIteration: 400
3.生成器产生数据的原理(生成器内部代码如何执行,执行顺序?)
def func_3():
print('#########')
yield 100
print('*********')
yield 200
print('+++++++++')
yield 300
result = func_3()
print(result)
print(next(result))
print(next(result))
print(next(result))
# 返回:<generator object func_3 at 0x000001CF6C5D9660>
# #########
# 100
# *********
# 200
# +++++++++
# 300
02-生成器和迭代器对比
一、生成器和迭代器的区别
1.迭代器是访问容器的一种方式,也就是说,容器已经出现。我们只是从容器中copy了一份副本,将这个副本转为迭代器,而生成器是我们通过代码生成的。
2.迭代器在开发中很难被用到,生成器使用频率高很多。
二、为什么使用生成器?
python的生成器提供了延迟操作,在需要的时候才执行产生结果。
1.节省资源消耗:和声明容器不同,容器一产生就占用了内存,但是生成器不使用时几乎不占用内存。
2.使用的时候,生成器是随用随生成,用完立即释放,不占用内存。
三、return和yield区别
1.相同点:return和yiled都返回函数的结果。
2.不同点:return一执行,函数立即结束,yield是让函数变成生成器,不迭代时,函数被冻结;迭代时,函数再被唤醒,按照迭代次数返回相应数量的元素。
03-生成器练习题
写一个生成器,可以创建python学生的学号。例如:python1001、python1002、python1003等,一直到python1999。
# 自己写的,只能一次性生成全部,不能做到随用随取,说到底还是没吃透
def creat():
list = [i for i in range(1, 1000)]
for i in list:
str1 = 'python' + str(1000 + i)
print(str1)
yield
# result = creat()
print(creat())
print(next(creat()))
# 老师写的
def stu_id(num):
for i in range(1001, num+1):
yield f'python{i}'
result = stu_id(1999)
# 获取200个学生的学号
for i in range(200):
print(next(result))
# 再取一个
print(next(result))
# 取完剩下的所有
for i in result:
print(i)
04-python模块基本认知
一、什么是模块
模块,又叫做库;python中存在很多模块,模块就是实现了某一个或者某一类功能代码的集合。
二、python中模块分类
模块主要分两类:内置模块(安装python时自带的)、三方模块
三方模块其实也分成两种:自定义模块(我们在本地创建的)、其他人发布的模块(需要安装的)
三、常用的一些模块
内置模块
random:随机模块
time:时间模块
os:包含很多操作系统指令的模块
re:正则表达式模块
等
四、其他人发布的模块
pygame:常用的游戏模块
flask、django:后端开发的框架
requests:发送请求的模块
scrapy:世界排名第一的最流行的爬虫框架
seleium、playwright:web自动化测试框架
BeautifulSoup4、lxml:网页解析框架
等
五、自定义模块:我们自己根据实际需求开发的模块,通常是对某段逻辑或某些函数的防撞,可以供我们使用(重复调用)。
05-python导入模块
python提供了很多种导包方式,不同情况下可以择优选择。为什么要导包?内置模块、三方模块不导包无法使用。
1.import模块1, 模块2, 模块3…
这种导包方式,会将模块中所有的成员(变量、函数、类等)全部导入到你的程序中会造成性能低下,不仅如此,想使用某个方法还需要使用模块名.方法名的形式。
import random, time
print(random.randint(1, 100))
print(time.altzone)
2.from 模块名 import *
等价于import 模块,只是在调用某个方法时,不需要再模块名.方法名
from time import *
print(sleep(1))
3.from 模块名 import 方法1, 方法2, 方法3…
性能最好,需要什么方法,就只导入什么方法,不需要的方法没有导入不会使程序中方法、变量等冗余。
from os import listdir
# listdir根据指定的路径,查看该路径下的所有子文件和子文件夹。默认当前文件夹。
print(listdir())
4.import 模块名 as 别名
我需要用到某个模块下面的很多方法,但是模块名比较长,可以给模块名设置别名,使用简短的别名进行方法调用。
import random as rd
print(rd.randint(1, 2))
5.from 模块名 import 方法 as 别名
有些模块中的某些方法名字很长,我需要多次调用这个方法,但是又不想写特别长的名字,就可以给这个方法也设置个别名。
from random import randint as ri
print(ri(100, 200))
使用频率比较:1、3 > 4、5 > 2
07-transfer_module
自定义模块
# 随意的定义一些内容
def twoSum(x, y):
return x + y
c = 50
# 上方代码是实现的功能
# 下方代码是功能的测试
# 能不能不对外展示程序的测试部分?能
if __name__ == '__main__':
a = 10
b = 20
print(twoSum(a, b))
print(a, b)
注意:name和main两侧的两条下划线被markdown用上了,不知道怎么给他拿出来
if name == ‘main’:的作用?
导包时,被导包的模块中的所有的print都会被执行,防止这种情况发生,将不应该执行的代码全部放入到if name == ‘main’:中,另一个代码中,调用此模块,处于if name == ‘main’:中的代码就不会被调用到。
一个py文件就是一个模块,py文件名就是模块名
调用自定义模块
import define_module
# 能够将整个模块中的所有的成员导入
from define_module import twoSum, c
print(c)
print(twoSum(100, 200))
from define_module import a, b
print(a, b)
# 返回:ImportError: cannot import name 'a' from 'define_module' (D:\Qianfeng01\day24\define_module.py)
虽然a,b可以被调用到,但是不能使用,a,b已经是私有化的变量了
08-反反爬虫手段
1.写爬虫,一定要添加伪装:User-Agent(UA)
2.休眠:time.sleep(),防止访问过于频繁,被封ip
3.封ip之后,可以换手机热点,手机每次开关飞行模式,ip地址会发生变化
4.封ip之后,使用代理ip
5.随机UA
6.fake-useragent 模块,可以随时更换随机的UA
09-豆瓣电影爬虫调用自定义的请求模块
自定义模块
import requests
from random import choice
def fake_UA():
global ua_list
with open('./UserAgent.txt', 'r', encoding='utf-8') as f:
ua_list = eval(f.read())
fake_UA()
def requests_get(link:str):
# print(ua_list)
Headers = {'User-Agent': choice(ua_list)}
response = requests.get(url=link, headers=Headers)
return response.text if response.status_code == 200 else response.status_code
if __name__ == '__main__':
# URL = 'https://taobao.com/'
# print(requests_get(URL))
result = fake_UA()
print(result, type(result))
调用自定义模块实现爬虫功能
from requests_func import requests_get
import time
from random import randint
from bs4 import BeautifulSoup
for i in range(0, 10):
print(f'---------这是第{i + 1}页----------')
URL = f'https://movie.douban.com/top250?start={i * 25}&filter='
# 调用自定义模块
result = requests_get(URL)
soup = BeautifulSoup(result, 'html.parser')
lilist = soup.select('html > body > div#wrapper ol > li')
# print(lilist)
for i in lilist:
# 电影标题
movieTitle = i.select('li > div.item > div.info > div.hd > a > span.title')
movieList = [i.text for i in movieTitle]
movieTitle = ''.join(movieList)
# 电影评分
movieScore = i.select_one('li div.bd > div.star > span.rating_num').text
# # 电影评论人数
commPeople = i.select_one('li div.bd > div.star > span:nth-child(4)').text
# 中心思想
middIdea = i.select_one('li div.bd > p.quote > span.inq')
middIdea = middIdea.text if middIdea != None else ''
print(movieTitle, movieScore, commPeople, middIdea)
# 每一页爬取完毕,休眠一下,防止我们被检测到
# sleep:休眠,强制等待几秒钟
time.sleep(randint(1, 3))
10-random模块
random模块是python提供一系列随机方法的模块
from random import *
# 1.randint()
# 返回区间[a, b]内随机整数
print(randint(10, 11)) #10、11
# 2.randrange()
# 相当于从range方法产生的序列中随机抽取一个元素(int)
print(randrange(10, 11)) #10
# 3.choice()
# 从非空容器中随机选取一个元素
print(choice([1, 2, 3])) #1、2、3
# 4.choices()
# 从非空容器中随机选取k个元素,k默认为1,choices是有放回的抽取
print(choices([1, 2, 3, 4], k=5)) #[2, 3, 1, 1, 2]
# 5.sample()
# 从有序容器中无放回的抽取k个元素,k无默认值
print(sample([1, 2, 3, 4], k=4)) #[1, 3, 2, 4]
# 6.shuffle()
# 将有序可变的容器中元素的位置打乱(洗牌)
list1 = [6, 7, 8, 9]
shuffle(list1)
print(list1) #[8, 6, 7, 9]
# 7.random()
# 从区间(0.0, 1.0)范围中随机选取一个浮点数(左闭右开区间)
print(random()) #0.5776464281608823
# 8.uniform()
# 从[a, b]范围随机返回一个浮点数
print(uniform(1, 10)) #6.030000853904442
# 爬虫的休眠中,其实uniform比randint更合适
随机生成长度为4的包含数字、字母的验证码
# 自己写的
list1 = [chr(i) for i in range(48, 58)] + [chr(i) for i in range(65, 91)] + [chr(i) for i in range(97, 123)]
str = ''
for i in range(4):
str += choice(list1)
print(str)
# 老师写的
list1 = [chr(i) for i in range(48, 58)] + [chr(i) for i in range(65, 91)] + [chr(i) for i in range(97, 123)]
print(''.join(choices(list1, k=4)))
11-pip模块常用指令
pip:python的包管理工具
1.获取pip帮助
pip help
2.安装模块
pip install 模块名
3.安装指定版本的模块
pip install 模块名==版本号
4.卸载模块
pip uninstall 模块名
5.列举已安装的模块
pip list
版本号的规范模式:A.B.C
A:大版本,软件整体升级
B:中版本,功能性更新
C:小版本,修复bug,提升稳定性
6.查看哪些模块有新的版本可以更新
pip list -o
7.模块升级
a.重新指定安装什么版本的模块
pip install tqdm==4.65.0
b.指定升级模块
pip install -U 模块名
需要特别注意的是,如果你升级的是pip包管理工具,在windows系统下,还要添加–user命令,以表示提供管理员权限
pip install -U pip --user所以,pip包管理工具只要能用,绝不升级
8.批量导出已安装过的模块
pip freeze > requirements.txt
9.批量安装已导出的模块
pip install -r requirements.txt
10.查看某个已安装的模块的信息
pip show 模块名