Python Discord机器人批量下载图片报错TypeError求助
问题:批量抓取帖子图片失败,仅能下载一张且触发TypeError错误
作为Python和Discord API新手,尝试通过网站API抓取1-10条帖子的图片并保存到缓存文件夹,但目前仅能下载一张图片,还触发TypeError: Constructor parameter should be str错误。附上相关代码及报错栈,寻求解决方法:
@group.command(name="search", description="Search for posts.") async def test(self, interaction: discord.Interaction, search: str, amount: app_commands.Range[int, 1, 10]): async def main(): async with aiohttp.ClientSession() as session: async with session.get(f'-------------------------------') as response: ImageUrl = [] Post = [] data = await response.json() for post in data['posts']: ImageUrl.append(post['file']['url']) #Post.append(f"{post['id']}.{post['file']['ext']}") print(ImageUrl) print(Post) for url in ImageUrl: async with session.get(url) as response2: print(await response2.read()) imgdata = await response2.read() with open(f"./cogs/cache/{post['id']}.{post['file']['ext']}", "wb+") as f: f.write(imgdata) asyncio.run(main())
报错信息:
Traceback (most recent call last): File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\discord\app_commands\commands.py", line 827, in _do_call return await self._callback(self.binding, interaction, **params) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\aiohttp\client.py", line 376, in _build_url url = URL(str_or_url) ^^^^^^^^^^^^^^^ File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\yarl\_url.py", line 179, in __new__ raise TypeError("Constructor parameter should be str")TypeError: Constructor parameter should be str ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\aiohttp\client.py", line 376, in _build_url url = URL(str_or_url) ^^^^^^^^^^^^^^^ File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\yarl\_url.py", line 179, in __new__ raise TypeError("Constructor parameter should be str")TypeError: Constructor parameter should be str The above exception was the direct cause of the following exception: Traceback (most recent call last): File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\discord\app_commands\tree.py", line 1248, in _call await command._invoke_with_namespace(interaction, namespace) File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\discord\app_commands\commands.py", line 853, in _invoke_with_namespace return await self._do_call(interaction, transformed_values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\Mae\Desktop\Programming Funnies\.venv\Lib\site-packages\discord\app_commands\commands.py", line 842, in _do_call raise CommandInvokeError(self, e) from e discord.app_commands.errors.CommandInvokeError: Command 'search' raised an exception: TypeError: Constructor parameter should be str
问题分析
- TypeError触发原因:
- 第一个
session.get使用的是占位符-------------------------------,并非有效字符串URL; - 部分帖子的
post['file']['url']可能不是字符串类型(如None),导致无法构造有效请求URL。
- 第一个
- 仅下载一张图片原因:
保存文件时使用的是外层循环结束后的post变量(此时指向最后一条帖子),所有图片会被覆盖为同一个文件名,最终仅保留最后一张。 - 额外问题:在Discord bot的异步上下文里调用
asyncio.run(main())会创建新事件循环,易引发冲突,应直接使用await main()。
修正后的代码
import os import aiohttp import discord from discord import app_commands @group.command(name="search", description="Search for posts.") async def test(self, interaction: discord.Interaction, search: str, amount: app_commands.Range[int, 1, 10]): async def main(): # 确保缓存文件夹存在 cache_dir = "./cogs/cache" if not os.path.exists(cache_dir): os.makedirs(cache_dir) # 替换为真实API地址,需包含search和amount参数 api_url = f"https://你的API地址/search?q={search}&limit={amount}" async with aiohttp.ClientSession() as session: async with session.get(api_url) as response: if response.status != 200: print(f"API请求失败,状态码: {response.status}") return data = await response.json() # 遍历指定数量的帖子,直接处理下载 for post in data['posts'][:amount]: file_info = post.get('file') if not file_info: print(f"帖子{post.get('id')}无文件信息,跳过") continue img_url = file_info.get('url') if not isinstance(img_url, str): print(f"帖子{post.get('id')}的图片URL无效,跳过") continue img_ext = file_info.get('ext', 'jpg') img_filename = f"{post['id']}.{img_ext}" img_path = os.path.join(cache_dir, img_filename) try: async with session.get(img_url) as img_response: if img_response.status == 200: img_data = await img_response.read() with open(img_path, "wb") as f: f.write(img_data) print(f"已保存图片: {img_filename}") else: print(f"下载失败,URL: {img_url},状态码: {img_response.status}") except Exception as e: print(f"处理帖子{post.get('id')}出错: {str(e)}") # 适配Discord异步上下文,直接await await main() await interaction.response.send_message(f"已完成{amount}条帖子的图片抓取,保存至缓存文件夹", ephemeral=True)
关键改动说明
- 修复URL问题:替换占位符为真实API地址,同时检查图片URL是否为有效字符串,避免TypeError;
- 合并循环逻辑:直接在遍历帖子的循环内处理下载,确保每个图片对应正确的帖子ID和文件名,解决覆盖问题;
- 文件夹预处理:提前创建缓存文件夹,防止因路径不存在导致写入失败;
- 异步上下文修正:用
await main()替代asyncio.run(main()),适配Discord bot的事件循环; - 错误处理增强:增加API响应状态检查、文件信息校验和异常捕获,提升代码稳定性;
- 数量控制:通过
data['posts'][:amount]确保只抓取用户指定数量的帖子。
内容的提问来源于stack exchange,提问作者Meolsei
相关产品推荐
相关产品推荐

