主题
生成器和协程和正则表达式
一、生成器
1. 推导式
python
l1 = [i*2 for i in range(10)]
s1 = {i*2 for i in range(10)}
d1 = {i:i*2 for i in range(10)}2. 生成器
python
# 创建生成器
# 生成器表达式
t1 = (i ** 2 for i in range(10))
# 函数式生成器 - yield
def fn():
for i in range(5):
yield i
# 生成器函数的执行结果:yield后的结果
# 函数执行到yield暂停,函数再次执行时从上次暂停的位置继续执行
# 生成器使用方法
# 1.next(生成器)
# 2.for i in 生成器 # 生成器是一个可迭代对象
# 注:生成器(generator)在遍历时会“消耗”其中的元素,一旦遍历完成,生成器就 exhausted(耗尽)了,无法再次从头开始迭代。二、协程
1. 使用步骤
- async 定义协程函数
- await 让出控制权(不能单独使用)
- 定义一个入口函数
- 创建多个协程任务(asyncio.creat_task)(参数传递要做的事)需要一个入口函数
- 并发执行
- 启动事件循环(执行入口函数)(asyncio.run)
2. 示例
python
import asyncio
import time
# async 定义协程函数
async def read_file():
print('开始读')
# await 让出控制权(不能单独使用)
# 使用asyncio里面的sleep来实现等待耗时模拟
await asyncio.sleep(2)
print('读完了')
async def write_file():
print('开始写')
# await 让出控制权(不能单独使用)
# 使用asyncio里面的sleep来实现等待耗时模拟
await asyncio.sleep(2)
print('写完了')
# 定义一个入口函数
async def main():
# 创建多个协程任务(asyncio.create_task)(参数传递要做的事)需要一个入口函数
task1 = asyncio.create_task(read_file())
task2 = asyncio.create_task(write_file())
# 并发执行
await task1
await task2
# 启动事件循环(执行入口函数)(asyncio.run)
asyncio.run(main())3. 网络请求的协程使用
python
# 一般不用,过时了
import asyncio
import httpx
# 异步客户端
async_client = httpx.AsyncClient()
async def get_dat():
res = await async_client.get('https://fishpi.cn/')
print(res.text)
asyncio.run(get_dat())三、网络请求
1. 网络请求
python
# 网络请求:使用python代码发出网络请求获取数据
# 包:httpx
import httpx
# 创建用于网络请求的客户端
client = httpx.Client()
# 通过client.get方法发送网络请求,用变量接受服务器返回的数据
response = client.get('https://fishpi.cn/top/checkin')
# 打印响应数据(.text)
print(response.text)
# 注:
# .text 把内容转成文字
# .json 保留字典内容
# .content 保留二进制内容2. 百度爬取图片
python
# 图片爬虫:
# 文件读写
# 文件保存
# 网络请求
# 获取图片地址:找到百度图片地址 调用url获取图片集合信息(Fetch/XHR->acjson) 找到单个图片地址(data->images->thumburl) 调用地址获取图片数据 保存图片数据
# 要用headers模拟浏览器
# 示例:
import time
import httpx
client = httpx.Client()
word = input('请输入图片关键字:')
info = client.get(
url=f'https://image.baidu.com/search/acjson?tn=resultjson_com&word={word}&ie=utf-8&fp=result&fr=&ala=0&applid=8832573439820530106&pn=120&rn=30&nojc=0&gsm=78&newReq=1',
# 模拟浏览器(请求标头)
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://image.baidu.com/',
'Connection': 'keep-alive',
}
)
for i in info.json()['data']['images'][:5]:
image_url = client.get(i['thumburl'])
with open(f'files/{time.time()}.jpg', 'wb') as f:
f.write(image_url.content)3. 搜狗爬取图片
python
import time
import httpx
client = httpx.Client()
query = input('请输入图片关键字:')
info = client.get(
url=f'https://pic.sogou.com/napi/pc/searchList?mode=1&start=48&xml_len=48&query={query}&channel=pc_pic&scene=pic_result',
# 模拟浏览器(请求标头)
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://image.baidu.com/',
'Connection': 'keep-alive',
# 多一个时间戳
'x-time4p': str(int(time.time() * 1000)),
}
)
for i in info.json()['data']['items'][:5]:
image_url = client.get(i['thumbUrl'])
with open(f'files/{i["title"]}.jpg', 'wb') as f:
f.write(image_url.content)4. 静态资源爬取
python
# 爬虫 - 静态资源/动态接口
# 找到资源链接(网址)
# 调接口获取网页内容(text)
# 通过正则获取网页图片的链接
# 网络请求调用图片链接获取图片内容
# 保存图片内容
import re
import httpx
client = httpx.Client()
info = client.get('https://www.cctv.com/')
# 粗略查找src(图片)
photos = re.findall('<img src="(.*?)".*>', info.text)
for i in photos:
# 取出有用信息
if re.findall(r'(png|jpg)', i):
res = client.get('https:' + i)
# 保存图片
with open(file=f'静态资源/{i.split('/')[-1]}', mode='wb') as f:
f.write(res.content)四、正则表达式
1. re模块匹配方式
match
python# 导入re模块 import re # match方法(正则表达式,要检测的字符串)- 从头匹配 res = re.match('[0-9]', '0123456789') # 匹配成功返回一个正则对象,失败返回None # .group为匹配成功的对象 if res: print(res.group()) else: print('匹配失败')search
python# 导入re模块 import re # search方法(正则表达式,要检测的字符串)- 查找整个字符串是否有匹配的内容(一个) res = re.search('[0-9]', '0123456789') # 匹配成功返回一个正则对象,失败返回None # .group为匹配成功的对象 if res: print(res.group()) else: print('匹配失败')findall
python# findall (正则表达式,要匹配的函数) - 是否包含(匹配所有) import re # 匹配成功返回一个列表,失败返回一个空列表 res = re.findall('[0-9]', '0123456789') res1 = re.findall('[0-9]', 'abcdef') print(res) print(res1) # findall查找组的时候直接获取组的内容
2. 正则表达式编写
1. 单个匹配
python
import re
# .表示匹配任意字符(除了\n)
# raw(r)使用原字符串的内容,防止字符串内容转译
res1 = re.match(r'.', '0123456789')
print(res1)
# []表示在这个范围内任意匹配
res2 = re.match(r'[0-9]', '0123456789')
print(res2)
# [^]表示不在这个范围内匹配
res3 = re.match(r'[^0-9]', '0123456789')
print(res3)
# \d表示匹配数字
res4 = re.match(r'\d', '0123456789')
print(res4)
# 其他的作为了解即可
# \D表示匹配非数字
# \s匹配空格
# \S匹配非空格
# \w匹配字母数字下划线中文
# \W匹配非字母数字下划线中文2. 多个匹配
python
# 写在匹配字符后面
# * 表示任意次数 (0或者无数次)
# + 表示至少一次
# ? 表示0或者1次
# {n} 匹配n次
# {n,} 匹配n次到无数次
# {n,m} 匹配n到m次
# 验证手机号
# 需求:11位长度 1开头 第二位没有012
import re
res = re.match(r'1[^0-2]\d{9}$', '18291860380')
print(res)3.开头结尾
python
# r'^正则表达式$' - 固定字符串的开头和结尾
import re
# 四位验证码
res1 = re.match(r'^[0-9a-zA-Z]{4}$', '1234')
print(res1)4.分组
python
import re
# | 或者 - 一般用(|)
res1 = re.match(r'^[0-9A-Za-z]{4,20}@(163|126)\.com$', 'niuhao@126.com')
res2 = re.match(r'^[0-9A-Za-z]{4,20}@(163|126)\.com$', '132357134@qq.com')
print(res1, res2)
# ()表示分组 \1表示使用组(1是第一个分组的意思)
content1 = '<h1>wozhenshuai<h1>'
content2 = '<h1>wozhenshuai<h2>'
res3 = re.match(r'^<([0-9a-zA-Z]{2})>.*<\1>$', content1)
res4 = re.match(r'^<([0-9a-zA-Z]{2})>.*<\1>$', content2)
print(res3, res4)
# 分组别名
# 定义别名(捕获) 引用别名(匹配时) 引用别名(替换时)
# (?P<name>...) (?P=name) \g<name>5. 贪婪非贪婪
python
# 贪婪模式:匹配尽可能多的字符(.* .+)
# 非贪婪模式:匹配尽可能少的字符(.*? .+?)
content_test = '<img class="lazy" src="//p2.img.cctvpic.com/photoAlbum/page/performance/img/2026/6/20/1781930258479_596.jpg" data-src="//p2.img.cctvpic.com/photoAlbum/page/performance/img/2026/6/20/1781930258479_596.jpg" width="100%">'
r1 = re.findall(r'^<img.*src="(.*)".*>$', content)
第一个.*贪到的内容: class="lazy" src="//p2.img.cctvpic.com/photoAlbum/page/performance/img/2026/6/20/1781930258479_596.jpg" data-
第二个.*贪到的内容:src="//p2.img.cctvpic.com/photoAlbum/page/performance/img/2026/6/20/1781930258479_596.jpg" width="100%"
第三个.*贪到的内容:
r2 = re.findall(r'^<img.*?src="(.*?)".*>$')
第一个.*贪到的内容: class="lazy"
第二个贪到的内容://p2.img.cctvpic.com/photoAlbum/page/performance/img/2026/6/20/1781930258479_596.jpg
第三个贪到的内容: data-src="//p2.img.cctvpic.com/photoAlbum/page/performance/img/2026/6/20/1781930258479_596.jpg" width="100%"6. 正则修饰符
python
# 修饰符被指定为一个可选的标志,多个标志可以通过按位 OR(|) 它们来指定
# re.I 匹配时不区分大小写
# re.S 使 . 匹配包括换行符\n在内的所有字符
res = re.match('a1d6','A1D6',re.I)