Descargue y guarde el archivo PDF con el módulo de solicitudes de Python


Estoy tratando de descargar un archivo PDF de un sitio web y guardarlo en el disco. Mis intentos fallan con errores de codificación o resultan en archivos PDF en blanco.

In [1]: import requests

In [2]: url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'

In [3]: response = requests.get(url)

In [4]: with open('/tmp/metadata.pdf', 'wb') as f:
   ...:     f.write(response.text)
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-4-4be915a4f032> in <module>()
      1 with open('/tmp/metadata.pdf', 'wb') as f:
----> 2     f.write(response.text)
      3 

UnicodeEncodeError: 'ascii' codec can't encode characters in position 11-14: ordinal not in range(128)

In [5]: import codecs

In [6]: with codecs.open('/tmp/metadata.pdf', 'wb', encoding='utf8') as f:
   ...:     f.write(response.text)
   ...: 

Sé que es un problema de códec de algún tipo, pero parece que no puedo hacer que funcione.

Author: Kevin Guan, 2015-12-29

2 answers

Debes usar response.content en este caso:

with open('/tmp/metadata.pdf', 'wb') as f:
    f.write(response.content)

De el documento:

También puede acceder al cuerpo de la respuesta como bytes, para solicitudes que no son de texto:

>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

Eso significa: response.text devuelve la salida como un objeto de cadena, úsalo cuando estés descargando un archivo de texto . Como el archivo HTML, etc.

Y response.content devuelven la salida como objeto bytes, úsalo cuando estés descargando un archivo binario . Como archivo PDF, archivo de audio, imagen, etc.


También puede usar response.raw en su lugar. Sin embargo, úselo cuando el archivo que está a punto de descargar sea grande. A continuación se muestra un ejemplo básico que también puede encontrar en el documento:

import requests

url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'
r = requests.get(url, stream=True)

with open('/tmp/metadata.pdf', 'wb') as fd:
    for chunk in r.iter_content(chunk_size):
        fd.write(chunk)

chunk_size es el tamaño del trozo que desea utilizar. Si lo configura como 2000, las solicitudes descargarán ese archivo los primeros 2000 bytes, los escribirán en el archivo y lo harán de nuevo, una y otra vez, a menos que haya terminado.

Así que esto puede salvar su RAM. Pero yo prefiera usar response.content en este caso ya que su archivo es pequeño. Como puede ver, use response.raw es complejo.


Se relaciona:

 91
Author: Kevin Guan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:20

Con respecto a la respuesta de Kevin para escribir en una carpeta tmp, debería ser así:

with open('./tmp/metadata.pdf', 'wb') as f:
    f.write(response.content)

Se olvidó . antes de que la dirección y, por supuesto, su carpeta tmp ya debería haber sido creada

 -4
Author: Nima Sajedi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-25 12:30:21