skip to Main Content

When I try to post an array of files in Python using requests, I get “TypeError: a bytes-like object is required, not ‘dict'”.

In order to send an album in Telegram from local, we need to provide an array of files, which contains file type. So I try:

import requests

bot_token = '<BOT_TOKEN>'
send_to = 1234567890
data = {'chat_id': send_to}

album = [
    {'type': 'photo', 'media': 'test/foo.png'},
    {'type': 'photo', 'media': 'test/bar.png'},
]
for i in range(len(album)):
    album[i]['media'] = open(album[i]['media'], 'rb')
files = {'media': album}

test = requests.post(
    f'https://api.telegram.org/{bot_token}/sendMediaGroup',
    data=data, files=files)

When I run this I get:

Traceback (most recent call last):
  File "D:/Games/GitHub/tgapi/test_album.py", line 87, in <module>
    data=data, files=files)
  File "C:ProgramDataAnacondalibsite-packagesrequestsapi.py", line 116, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "C:ProgramDataAnacondalibsite-packagesrequestsapi.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:ProgramDataAnacondalibsite-packagesrequestssessions.py", line 519, in request
    prep = self.prepare_request(req)
  File "C:ProgramDataAnacondalibsite-packagesrequestssessions.py", line 462, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "C:ProgramDataAnacondalibsite-packagesrequestsmodels.py", line 316, in prepare
    self.prepare_body(data, files, json)
  File "C:ProgramDataAnacondalibsite-packagesrequestsmodels.py", line 504, in prepare_body
    (body, content_type) = self._encode_files(files, data)
  File "C:ProgramDataAnacondalibsite-packagesrequestsmodels.py", line 169, in _encode_files
    body, content_type = encode_multipart_formdata(new_fields)
  File "C:ProgramDataAnacondalibsite-packagesurllib3filepost.py", line 90, in encode_multipart_formdata
    body.write(data)
TypeError: a bytes-like object is required, not 'dict'

P.S.:

  • Adding headers={'Content-Type': 'multipart/form-data'} into requests.post does not help.
  • The code to send a single file is:
files = {'photo': open('test/foo.png', 'rb')}

test = requests.post(
    f'https://api.telegram.org/{bot_token}/sendPhoto',
    data=data, files=files)

2

Answers


  1. Chosen as BEST ANSWER

    By referring to a popular package pyTelegramBotAPI, I've figured out:

    import requests
    import json
    
    bot_token = '<BOT_TOKEN>'
    send_to = 1234567890
    data = {'chat_id': send_to}
    
    album = [
        {'type': 'photo', 'media': 'foo.png'},
        {'type': 'photo', 'media': 'bar.png'},
    ]
    files = {}
    for i in range(len(album)):
        files[album[i]['media']] = open(album[i]['media'], 'rb')
    data['media'] = json.dumps(album)
    

    At this moment,

    data = {'chat_id': '345060487',
            'media': '[{"type": "photo", "media": "attach://foo.png"}, {"type": "photo", "media": "attach://bar.png"}]'
    }
    files = {
        'foo.png': open('test/foo.png', 'rb'),
        'bar.png': open('test/bar.png', 'rb'),
    }
    

    And finally this code will work:

    test = requests.post(
        f'https://api.telegram.org/{bot_token}/sendMediaGroup',
        data=data, files=files)
    

    Note that, just like what is done in pyTelegramBotAPI, it's much better to generate a random filename by:

    import random
    import string
    
    def generate_random_filename(length=16):
        return ''.join(random.sample(string.ascii_letters, length))
    

  2. You’re not sending in an array, your files variable is a dictionary, which is exactly what the error is telling you.

    Instead of adding the album from your loop to a dict key of media, just add it to an array and pass that in to your request

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search