82

I'm using Requests to upload a PDF to an API. It is stored as "response" below. I'm trying to write that out to Excel.

import requests

files = {'f': ('1.pdf', open('1.pdf', 'rb'))}
response = requests.post("https://pdftables.com/api?&format=xlsx-single",files=files)
response.raise_for_status() # ensure we notice bad responses
file = open("out.xls", "w")
file.write(response)
file.close()

I'm getting the error:

file.write(response)
TypeError: expected a character buffer object
Georgy
  • 12,464
  • 7
  • 65
  • 73
Chris J. Vargo
  • 2,266
  • 7
  • 28
  • 43
  • 21
    [`file.write(response.content)`](http://docs.python-requests.org/en/latest/user/quickstart/#binary-response-content). – Peter Wood Jun 29 '15 at 22:34
  • 19
    `with open(filename, mode='wb') as localfile:     localfile.write(response.content)` is more clean and elegant than open and close, IMHO. – törzsmókus Jun 21 '17 at 12:02
  • 1
    Skip the top two answers and head straight to [this one](https://stackoverflow.com/a/65637213/6243352). It'd be nice if OP could move the checkmark to that answer--the existing top answer is pretty much useless and the most-upvoted one is of limited usefulness. – ggorlen Jan 27 '21 at 16:43

3 Answers3

99

I believe all the existing answers contain the relevant information, but I would like to summarize.

The response object that is returned by requests get and post operations contains two useful attributes:

Response attributes

  • response.text - Contains str with the response text.
  • response.content - Contains bytes with the raw response content.

You should choose one or other of these attributes depending on the type of response you expect.

  • For text-based responses (html, json, yaml, etc) you would use response.text
  • For binary-based responses (jpg, png, zip, xls, etc) you would use response.content.

Writing response to file

When writing responses to file you need to use the open function with the appropriate file write mode.

  • For text responses you need to use "w" - plain write mode.
  • For binary responses you need to use "wb" - binary write mode.

Examples

Text request and save

# Request the HTML for this web page:
response = requests.get("https://stackoverflow.com/questions/31126596/saving-response-from-requests-to-file")
with open("response.txt", "w") as f:
    f.write(response.text)

Binary request and save

# Request the profile picture of the OP:
response = requests.get("https://i.stack.imgur.com/iysmF.jpg?s=32&g=1")
with open("response.jpg", "wb") as f:
    f.write(response.content)

Answering the original question

The original code should work by using wb and response.content:

import requests

files = {'f': ('1.pdf', open('1.pdf', 'rb'))}
response = requests.post("https://pdftables.com/api?&format=xlsx-single",files=files)
response.raise_for_status() # ensure we notice bad responses
file = open("out.xls", "wb")
file.write(response.content)
file.close()

But I would go further and use the with context manager for open.

import requests

with open('1.pdf', 'rb') as file:
    files = {'f': ('1.pdf', file)}
    response = requests.post("https://pdftables.com/api?&format=xlsx-single",files=files)

response.raise_for_status() # ensure we notice bad responses

with open("out.xls", "wb") as file:
    file.write(response.content)
JGC
  • 5,725
  • 1
  • 32
  • 30
  • How to find out which type of file you're getting? For example I'm downloading a file from a link user has given me and I have to find out which type of writing I need to do. – Farhood ET Nov 29 '21 at 08:55
  • 1
    That's a good question. Check out https://stackoverflow.com/a/898723/6252525 This suggests using mimetypes.guess_type(), and then use a lookup to determine whether the mime type is binary or not. – JGC Nov 29 '21 at 21:41
50

You can use the response.text to write to a file:

    import requests
    
    files = {'f': ('1.pdf', open('1.pdf', 'rb'))}
    response = requests.post("https://pdftables.com/api?&format=xlsx-single",files=files)
    response.raise_for_status() # ensure we notice bad responses
    with open("resp_text.txt", "w") as file:
        file.write(response.text)
Pat Myron
  • 4,437
  • 2
  • 20
  • 39
bhawnesh dipu
  • 1,272
  • 1
  • 13
  • 17
-19

As Peter already pointed out:

In [1]: import requests

In [2]: r = requests.get('https://api.github.com/events')

In [3]: type(r)
Out[3]: requests.models.Response

In [4]: type(r.content)
Out[4]: str

You may also want to check r.text.

Also: https://2.python-requests.org/en/latest/user/quickstart/

Georgy
  • 12,464
  • 7
  • 65
  • 73
Sait
  • 19,045
  • 18
  • 72
  • 99