Ich lade eine Datei mit der get
Funktion der Python- requests
Bibliothek herunter. Zum Speichern der Datei möchte ich den Dateinamen bestimmen, den ein Webbrowser für den Dialog "Speichern" oder "Speichern unter ..." verwenden würde.
Einfach richtig? Ich kann es einfach aus demContent-Disposition
HTTP-Header abrufen, auf den über das Antwortobjekt zugegriffen werden kann:
import re
d = r.headers['content-disposition']
fname = re.findall("filename=(.+)", d)
Aber wenn man sich dieses Thema genauer ansieht, ist es gar nicht so einfach:
Gemäß RFC 6266 Abschnitt 4.3 und der Grammatik in Abschnitt 4.1 kann der Wert ein Token ohne Anführungszeichen (z. B. the_report.pdf
) oder eine Zeichenfolge in Anführungszeichen sein, die auch Leerzeichen (z. B. "the report.pdf"
) und Escape-Sequenzen enthalten kann (von letzteren wird jedoch abgeraten, daher ihre Handhabung ist keine harte Anforderung für mich). Des Weiteren,
Wenn sowohl "Dateiname" als auch "Dateiname*" in einem einzigen Header-Feldwert vorhanden sind, SOLLTEN [wir] "Dateiname*" auswählen und "Dateiname" ignorieren.
Der Wert von filename*
ist jedoch etwas komplizierter als der von filename
.
Außerdem scheint der RFC zusätzliche Leerzeichen um die =
.
Daher möchte ich für die im RFC aufgeführten Beispiele die folgenden Ergebnisse:
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
Dateiname: € rates
auch hier (nicht EURO rates
, da filename*
Vorrang)
Ich könnte das Parsen des Content-Disposition
Headers, von dem ich komme, requests
entsprechend selbst implementieren, aber wenn ich es vermeiden und stattdessen eine vorhandene bewährte Implementierung verwenden kann, würde ich das vorziehen.
Gibt es eine Python-Bibliothek, die das kann?
Die Bibliothek müsste
requests
Antwort extrahiert und zurückgibtContent-Disposition
Header-Feldwert (einer Zeichenfolge) extrahiert und zurückgibt, requests.get
die, die die Anforderung ausführt, und die Antwort sowie den Dateinamen (falls vorhanden) zurückgibt, Was es nicht bewältigen muss (aber wenn doch, noch besser), da ich das selbst machen kann:
Werte so bereinigen, dass sie außer einem einzelnen Dateinamen keine Verzeichnisnamen oder andere Pfadelemente enthalten, sodass das Speichern unter diesem Namen nicht dazu führt, dass Dateien an beliebigen Orten erstellt oder überschrieben werden
"save"-Dateinamenerweiterungen erzeugen, die "optimal zum Medientyp der empfangenen Payload passen" (siehe Abschnitt 4.3 )
Dateinamen bereinigen, um Benutzerverwirrung zu vermeiden ( Abschnitt 4.3 erwähnt das Ersetzen von "Steuerzeichen und führenden und nachgestellten Leerzeichen")
einen Rückfall bieten
filename
noch der filename*
Dispositionsparameter vorhanden sind oderContent-Disposition
Header fehltObwohl es dies konsistent melden sollte (sei es durch Erhöhen oder durch Zurückgeben None
von oder ''
), damit ich meinen eigenen Fallback einsetzen kann.
Siehe rfc6266 . Es scheint alles zu tun, was Sie wollen. Es ist unter der LGPL 3.0 lizenziert. Die Hauptgabel ist möglicherweise nicht besonders aktiv, und einige andere Gabeln haben möglicherweise mehr Leckereien.
Hier ist der Dünne:
>>> 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
rogerpack
das-g