Descargo un archivo usando la get
función de la biblioteca de Python requests
. Para almacenar el archivo, me gustaría determinar el nombre de archivo de la forma en que lo haría un navegador web para su cuadro de diálogo 'guardar' o 'guardar como ...'.
Fácil, ¿verdad? Puedo obtenerlo delContent-Disposition
encabezado HTTP, accesible en el objeto de respuesta:
import re
d = r.headers['content-disposition']
fname = re.findall("filename=(.+)", d)
Pero mirando más de cerca este tema, no es tan fácil:
De acuerdo con RFC 6266 sección 4.3 , y la gramática en la sección 4.1 , el valor puede ser un token sin comillas (p. ej. the_report.pdf
) o una cadena entrecomillada que también puede contener espacios en blanco (p. ej. "the report.pdf"
) y secuencias de escape (sin embargo, se desaconsejan estas últimas, por lo que su el manejo no es un requisito difícil para mí). Más lejos,
cuando tanto "nombre de archivo" como "nombre de archivo*" están presentes en un solo valor de campo de encabezado, [nosotros] DEBEMOS elegir "nombre de archivo*" e ignorar "nombre de archivo".
Sin embargo, el valor de filename*
, es todavía un poco más complicado que el de filename
.
Además, el RFC parece permitir espacios en blanco adicionales alrededor del archivo =
.
Por lo tanto, para los ejemplos enumerados en el RFC , me gustaría obtener los siguientes resultados:
example.html
Content-Disposition: INLINE; FILENAME= "an example.html"
an example.html
Content-Disposition: attachment;
filename*= UTF-8''%e2%82%ac%20rates
€ rates
Content-Disposition: attachment;
filename="EURO rates";
filename*=utf-8''%e2%82%ac%20rates
nombre de archivo: € rates
aquí también (no EURO rates
, ya que filename*
tiene prioridad)
Podría implementar el análisis del Content-Disposition
encabezado que obtengo requests
en consecuencia, pero si puedo evitarlo y usar una implementación probada existente, lo preferiría.
¿Hay una biblioteca de Python que pueda hacer esto?
La biblioteca tendría que
requests
respuesta pasada Content-Disposition
valor de campo de encabezado pasado (una cadena) requests.get
realiza la solicitud y devuelva la respuesta, así como el nombre del archivo (si lo hay) Lo que no tiene que manejar (pero si lo hace, aún mejor) ya que puedo hacerlo yo mismo:
desinfecte los valores para que no contengan nombres de directorio u otros elementos de ruta, excepto un solo nombre de archivo, por lo que almacenar con ese nombre no hará que se creen o sobrescriban archivos en ubicaciones arbitrarias
producir extensiones de nombre de archivo "guardar" "que coincidan de manera óptima con el tipo de medio de la carga útil recibida" (consulte la sección 4.3 )
desinfecte los nombres de archivo para evitar la confusión del usuario ( la sección 4.3 menciona la sustitución de "caracteres de control y espacios en blanco iniciales y finales")
proporcionar un respaldo
filename
ni el filename*
parámetro de disposición están presentes oContent-Disposition
falta el encabezado completoAunque debería informar eso constantemente (ya sea subiendo o regresando None
o ''
), para que pueda dejar que mi propio retroceso se active.
Echa un vistazo a rfc6266 . Parece hacer todo lo que quieras. Está licenciado bajo la LGPL 3.0. Es posible que la bifurcación principal no sea súper activa, y algunas otras bifurcaciones pueden tener más ventajas.
Aquí está el flaco:
>>> from rfc6266 import *
>>> parse_headers('Attachment; filename=example.html', relaxed=True)
ContentDisposition(u'Attachment', {u'filename': u'example.html'}, None)
>>> parse_headers('INLINE; FILENAME= "an example.html"', relaxed=True)
ContentDisposition(u'INLINE', {u'filename': u'an example.html'}, None)
>>> h='''attachment;
... filename*= UTF-8''%e2%82%ac%20rates'''
>>> parse_headers(h, relaxed=True)
ContentDisposition(u'attachment', {u'filename*': LangTagged(string=u'\u20ac rates', langtag=None)}, None)
>>> h='''attachment;
... filename="EURO rates";
... filename*=utf-8''%e2%82%ac%20rates'''
>>> parse_headers(h, relaxed=True)
ContentDisposition(u'attachment', {u'filename*': LangTagged(string=u'\u20ac rates', langtag=None), u'filename': u'EURO rates'}, None)
rwenz3l
das-g
rogerdpack
das-g