最近在学习python中的flask框架遇到了如下的问题,还望大家指点一下
1.在做一个随机下载图片模块,用户请求/random_img路径时从对应的url下载图片至服务器,然后再将下载完毕的图片返回给用户,下载过程是基于异步协程完成,但是在多用户请求的时候出现了部分图片无法下载,请求中断的情况,请问这是怎么回事呢?该怎么进行处理。
2.用户使用电脑随机下载图片可以得到完整的图片返回,但是使用手机下载图片时候返回的图片名称与异步下载的图片名称不一致
如下:
以下为我的flask框架代码
from flask import Flask, request, send_file, make_response, send_from_directory
from sms_main import Weapon
import asyncio
import os, random
import shutil
#实例化SMS类获取协程对象
cc=Weapon()
# 随机图片视图函数
@app.get('/random_img')
async def download_random_img():
folder_path = '/home/yys/Python/yys_SMSBOOM/img'
# 删除该文件夹下所有文件并重新创建文件
if len(os.listdir('./img'))>100:
shutil.rmtree(folder_path)
os.makedirs(folder_path)
"""随机数据处理"""
anime_list = cc.random_anime_wall()
random_url = random.choice(anime_list)
"""异步处理随机下载任务"""
c = cc.async_process_img(random_url)
await asyncio.gather(c)
"""检索img下文件并返回用户"""
file_list = os.listdir('./img')
random_img = 'img/' + random.choice(file_list)
return send_file(random_img, as_attachment=True)
以下为我的异步下载图片函数
class Weapon(object):
# 协程处理图片下载通用方法
async def async_process_img(self, url):
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=self.header) as resp:
file_name = 'img/' + str(resp.url).split('/')[-1]
async with aiofiles.open(file_name, 'wb') as f:
while True:
try:
read_size = await resp.content.read(1024 * 1024)
if not read_size:
break
await f.write(read_size)
except aiohttp.ClientConnectionError:
await asyncio.sleep(5)
continue
# 数据库读取图片url返回flask调用
def random_anime_wall(self):
# random_tables = ['anime_wall', 'wall_cc']
conn = pymysql.Connect(host='localhost', user='root', password='root', database='yys_SMSBOOM', port=3306)
cursor = conn.cursor()
with conn:
with cursor:
# cursor.execute(f'select url_name from {random.choice(random_tables)}')
cursor.execute('select url_name from wall_cc')
row = cursor.fetchall()
url_list = []
for i in row:
url_list.append(i[0])
return url_list
关于flask框架异步数据发送问题
在您的代码中,异步下载图片的过程是在协程中完成的,但是在多个请求同时发生时,可能会出现下载图片时卡住的情况。这可能是因为异步下载图片的协程在等待服务器的响应时,会导致整个线程阻塞,无法响应其他请求,因此您可以通过创建一个专门的异步协程池来处理请求,并且可以控制同时运行的协程数量。
例如,使用asyncio.create_task()方法将下载图片的协程添加到异步协程池中,然后使用await asyncio.gather()方法来等待所有协程完成后再进行下一步操作。这样,您就可以在处理其他请求时,同时异步下载图片,提高效率和并发处理能力。
此外,关于图片名称不一致的问题,可能是由于移动文件时的文件名更改问题导致的,建议使用os.rename()方法来重命名文件名称。
下面是修改后的代码示例:
import os
import random
import shutil
import asyncio
import aiohttp
import aiofiles
from flask import Flask, send_file
app = Flask(name)
定义异步协程池
async_pool = asyncio.Semaphore(10)
实例化SMS类获取协程对象
cc = Weapon()
随机图片视图函数
@app.get('/random_img')
async def download_random_img():
folder_path = '/home/yys/Python/yys_SMSBOOM/img'
if len(os.listdir('./img')) > 100:
shutil.rmtree(folder_path)
os.makedirs(folder_path)
"""随机数据处理"""
anime_list = cc.random_anime_wall()
random_url = random.choice(anime_list)
"""异步处理随机下载任务"""
async with async_pool:
task = asyncio.create_task(cc.async_process_img(random_url))
await asyncio.gather(task)
"""检索img下文件并返回用户"""
file_list = os.listdir('./img')
random_img = 'img/' + random.choice(file_list)
# 重命名文件
new_name = f"img/random_{random.randint(1000, 9999)}.jpg"
os.rename(random_img, new_name)
return send_file(new_name, as_attachment=True)
class Weapon(object):
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/58.0.3029.110 Safari/537.3'}
# 协程处理图片下载通用方法
async def async_process_img(self, url):
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=self.header) as resp:
file_name = 'img/' + str(resp.url).split('/')[-1]
async with aiofiles.open(file_name, 'wb') as f:
while True:
try:
read_size = await resp.content.read(1024 * 1024)
if not read_size:
break
await f.write(read_size)
except aiohttp.ClientConnectionError:
await asyncio
对于第二个问题,手机下载的图片名称与异步下载的图片名称不一致,可能是由于手机端对于文件名的解析方式与电脑端不同,导致出现了该问题。为了解决这个问题,我们可以考虑在返回图片前对于图片进行重新命名,以确保手机端能够正确解析图片的名称。
修改后的代码如下所示:
from flask import Flask, request, send_file, make_response, send_from_directory
from sms_main import Weapon
import asyncio
import os, random
import shutil
import uuid
#实例化SMS类获取协程对象
cc=Weapon()
# 随机图片视图函数
@app.get('/random_img')
async def download_random_img():
folder_path = '/home/yys/Python/yys_SMSBOOM/img'
# 删除该文件夹下所有文件并重新创建文件
if len(os.listdir('./img'))>100:
shutil.rmtree(folder_path)
os.makedirs(folder_path)
"""随机数据处理"""
anime_list = cc.random_anime_wall()
random_url = random.choice(anime_list)
"""异步处理随机下载任务"""
c = cc.async_process_img(random_url)
await asyncio.gather(c)
"""检索img下文件并返回用户"""
file_list = os.listdir('./img')
random_img = 'img/' + str(uuid.uuid4()) + '.' + random.choice(file_list).split('.')[-1]
os.rename('img/' + random.choice(file_list), random_img)
return send_file(random_img, as_attachment=True)
在代码中,我们使用uuid库为每一张图片生成一个唯一的名称,然后将图片重命名为该名称,以确保在不同的设备上都能够正确解析图片的名称。