You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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触发原因:
    1. 第一个session.get使用的是占位符-------------------------------,并非有效字符串URL;
    2. 部分帖子的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)

关键改动说明

  1. 修复URL问题:替换占位符为真实API地址,同时检查图片URL是否为有效字符串,避免TypeError;
  2. 合并循环逻辑:直接在遍历帖子的循环内处理下载,确保每个图片对应正确的帖子ID和文件名,解决覆盖问题;
  3. 文件夹预处理:提前创建缓存文件夹,防止因路径不存在导致写入失败;
  4. 异步上下文修正:用await main()替代asyncio.run(main()),适配Discord bot的事件循环;
  5. 错误处理增强:增加API响应状态检查、文件信息校验和异常捕获,提升代码稳定性;
  6. 数量控制:通过data['posts'][:amount]确保只抓取用户指定数量的帖子。

内容的提问来源于stack exchange,提问作者Meolsei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:54:54