Skip to content

生成器和协程和正则表达式

一、生成器

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. 使用步骤

  1. async 定义协程函数
  2. await 让出控制权(不能单独使用)
  3. 定义一个入口函数
  4. 创建多个协程任务(asyncio.creat_task)(参数传递要做的事)需要一个入口函数
  5. 并发执行
  6. 启动事件循环(执行入口函数)(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)