求助:无法从Telegram将图片下载为字节流/Base64格式
Telegram图片转字节流/Base64失败问题
我想从Telegram下载图片并直接转换为字节流(bytes)或Base64格式,不想保存为本地图片文件,但尝试后代码执行失败。以下是我写的代码:
channels = ['channel_name'] async with TelegramClient(username, api_id, api_hash) as client: # 遍历Telegram频道 for channel in channels: try: async with client.takeout() as takeout: async for message in takeout.iter_messages(channel, wait_time=0): try: # await client.download_media(message.media, temp_folder+channel+str(message.id)) print(message.media) data = await client.download_file( message.media, bytes, progress_callback=callback ) image = mpimg.imread(io.BytesIO(data), format='JPEG') plt.imshow(image) except FileReferenceExpiredError: print('发生FileReferenceExpiredError异常') except errors.TakeoutInitDelayError as e: print('必须等待', e.seconds, '秒后才能执行导出')
程序先打印message.media,随后抛出如下错误:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) D:\TEMP\hkay\Temp\ipykernel_79040\2965379116.py in <module> 53 # await client.download_media(message.media, temp_folder+channel+str(message.id)) 54 print(message.media) ---> 55 data = await client.download_file( 56 message, 57 bytes, ~\AppData\Roaming\Python\Python39\site-packages\telethon\client\downloads.py in download_file(self, input_location, file, part_size_kb, file_size, progress_callback, dc_id, key, iv) 490 print(data[:16]) 491 """ --> 492 return await self._download_file( 493 input_location, 494 file, ~\AppData\Roaming\Python\Python39\site-packages\telethon\client\downloads.py in _download_file(self, input_location, file, part_size_kb, file_size, progress_callback, dc_id, key, iv, msg_data) 547 548 if progress_callback: --> 549 r = progress_callback(f.tell(), file_size) 550 if inspect.isawaitable(r): 551 await r D:\TEMP\hkay\Temp\ipykernel_79040\1493750919.py in callback(current, total, channel_name) 33 def callback(current, total, channel_name=channel): 34 print('Downloaded from',channel,'-', 'message_id:', message.id, ' ', current, 'out of', total, ---> 35 'bytes: {:.2%}'.format(current / total)) 36 37 # Connect to API with Client TypeError: unsupported operand type(s) for /: 'int' and 'NoneType'
编辑1:
移除progress_callback后,出现新错误:
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) ~\AppData\Roaming\Python\Python39\site-packages\telethon\utils.py in _get_file_info(location) 800 try: --> 801 if location.SUBCLASS_OF_ID == 0x1523d462: 802 return _FileInfo(None, location, None) # crc32(b'InputFileLocation'): AttributeError: 'NoneType' object has no attribute 'SUBCLASS_OF_ID' During handling of the above exception, another exception occurred: TypeError Traceback (most recent call last) D:\TEMP\hkhan\Temp\ipykernel_79040\1631659142.py in <module> 53 #await client.download_media(message.media, temp_folder+channel+str(message.id)) 54 ---> 55 data = await client.download_file(message.media 56 ,bytes 57 ) ~\AppData\Roaming\Python\Python39\site-packages\telethon\client\downloads.py in download_file(self, input_location, file, part_size_kb, file_size, progress_callback, dc_id, key, iv) 490 print(data[:16]) 491 """ --> 492 return await self._download_file( 493 input_location, 494 file, ~\AppData\Roaming\Python\Python39\site-packages\telethon\client\downloads.py in _download_file(self, input_location, file, part_size_kb, file_size, progress_callback, dc_id, key, iv, msg_data) 538 539 try: --> 540 async for chunk in self._iter_download( 541 input_location, request_size=part_size, dc_id=dc_id, msg_data=msg_data): 542 if iv and key: ~\AppData\Roaming\Python\Python39\site-packages\telethon\client\downloads.py in _iter_download(self, file, offset, stride, limit, chunk_size, request_size, file_size, dc_id, msg_data) 680 msg_data: tuple = None 681 ): --> 682 info = utils._get_file_info(file) 683 if info.dc_id is not None: 684 dc_id = info.dc_id ~\AppData\Roaming\Python\Python39\site-packages\telethon\utils.py in _get_file_info(location) 802 return _FileInfo(None, location, None) # crc32(b'InputFileLocation'): 803 except AttributeError: --> 804 _raise_cast_fail(location, 'InputFileLocation') 805 806 if isinstance(location, types.Message): ~\AppData\Roaming\Python\Python39\site-packages\telethon\utils.py in _raise_cast_fail(entity, target) 136 137 def _raise_cast_fail(entity, target): --> 138 raise TypeError('Cannot cast {} to any kind of {}.'.format( 139 type(entity).__name__, target)) 140 TypeError: Cannot cast NoneType to any kind of InputFileLocation.
解决步骤
1. 过滤非图片消息
第二个错误说明遍历的消息里存在不带媒体的内容,message.media为None,必须先判断只处理图片类型的消息:
async for message in takeout.iter_messages(channel, wait_time=0): # 仅处理图片消息 if message.photo: try: # 后续处理逻辑 pass except FileReferenceExpiredError: print('发生FileReferenceExpiredError异常')
2. 替换download_file为download_media
download_file要求传入InputFileLocation类型参数,而download_media可以直接接收message.photo,并且支持直接返回字节流,无需额外配置:
# 直接获取图片字节流 data = await client.download_media(message.photo, bytes)
3. 修复进度回调的除数问题
如果要保留进度回调,需先判断total是否为空,避免除以None报错:
def callback(current, total, channel_name, message_id): if total is None: print(f'从{channel_name}下载 - message_id: {message_id} 已下载 {current} 字节') else: print(f'从{channel_name}下载 - message_id: {message_id} {current}/{total} 字节: {current/total:.2%}')
完整修正代码
import io import matplotlib.pyplot as plt import matplotlib.image as mpimg from telethon import TelegramClient, errors from telethon.errors import FileReferenceExpiredError def callback(current, total, channel_name, message_id): if total is None: print(f'从{channel_name}下载 - message_id: {message_id} 已下载 {current} 字节') else: print(f'从{channel_name}下载 - message_id: {message_id} {current}/{total} 字节: {current/total:.2%}') async def main(): username = '你的用户名' api_id = 123456 # 替换为你的API_ID api_hash = '你的API_HASH' channels = ['channel_name'] async with TelegramClient(username, api_id, api_hash) as client: for channel in channels: try: async with client.takeout() as takeout: async for message in takeout.iter_messages(channel, wait_time=0): if message.photo: try: print(message.photo) # 下载为字节流 data = await client.download_media( message.photo, bytes, progress_callback=lambda cur, tot: callback(cur, tot, channel, message.id) ) # 加载并显示图片 image = mpimg.imread(io.BytesIO(data), format='JPEG') plt.imshow(image) plt.show() except FileReferenceExpiredError: print('发生FileReferenceExpiredError异常') except errors.TakeoutInitDelayError as e: print('必须等待', e.seconds, '秒后才能执行导出') if __name__ == '__main__': import asyncio asyncio.run(main())
内容的提问来源于stack exchange,提问作者hkay
相关产品推荐
相关产品推荐

