Implementierter Dateidownload mit Python + Bottle

Flasche ist Pythons leichtes Webanwendungsframework. Web-Apps generieren manchmal Dateien auf der Serverseite und laden sie herunter. Dieses Mal werde ich über die Implementierung des Dateidownloads in Bottle schreiben.

Statisches Dateiverzeichnis

Ich denke, dass Sie in Webanwendungen häufig ein Verzeichnis erstellen, in dem Bilder / CSS / JS-Dateien wie "/ static /" erfasst werden. In solchen Fällen können Sie jedoch keine Anforderungshandler einzeln mit der Funktion "route" erstellen Es ist zweckmäßig, die Funktion "static_file" von "Flasche" wie folgt zu verwenden.

In diesem Beispiel liefert der Zugriff auf "http: // localhost: 8080 / static / hoge.txt" den Inhalt von "hoge.txt" in ". / Static", wie aus dem aktuellen Verzeichnis zur Laufzeit ersichtlich.

Bei der Produktionsbereitstellung vieler Webanwendungen wird das Verzeichnis, in dem statische Dateien erfasst werden, normalerweise direkt von Nginx oder Apache bereitgestellt. Wenn Sie jedoch in Flaschen geschriebene Python-Apps unterstützen, können Sie statische Dateien während der lokalen Entwicklung lesen. (Im Vergleich zu unserer Firma)

# -*- coding: utf-8 -*-
from bottle import route, run, static_file


@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='./static')


run(host='localhost', port=8080)

Wenn man sich [Flaschenquelle] ansieht (https://github.com/bottlepy/bottle/blob/master/bottle.py#L2651), scheint es, dass die wichtigsten Dateiformate durch das Paket "mimetypes" durch Erweiterung abgeleitet werden. ist. Gängige Dateien wie Bilder, CSS- und Zip / GZ-Dateien haben wahrscheinlich den richtigen Mimetyp im HTTP-Header "Content-Type".

Ich möchte, dass es heruntergeladen wird, anstatt angezeigt zu werden ...

Setzen wir die Option "Download" der Funktion "static_file" auf "True".

# -*- coding: utf-8 -*-
from bottle import route, run, static_file


@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='./static', download=True)


run(host='localhost', port=8080)

Wenn Sie den zu lesenden Dateinamen und den vom Browser zu speichernden Dateinamen trennen möchten, legen Sie den im Browser zu speichernden Dateinamen in der Option "Download" fest. Details werden später im Abschnitt "Static_file-Funktionsargumente / -optionen" beschrieben.

Muster 1. Eine kleine Datei, die in den Speicher passt

Sie können die Funktion static_file so wie sie ist verwenden.

# -*- coding: utf-8 -*-
from bottle import route, run, static_file


@route('/sample_image.png')
def sample_image():
    return static_file('./my_sample_image.png', root='.')


run(host='localhost', port=8080)

Bei Implementierung mit "HTTPResponse" wäre dies wie folgt. Dies scheint nützlich zu sein, wenn Sie den Inhalt der Datei zur Laufzeit bearbeiten und schwierige Dinge wie die Verteilung ausführen müssen. Wenn Sie jedoch nur eine vorhandene Datei herunterladen möchten, ist es grundsätzlich einfach und zuverlässig, die Funktion static_file zu verwenden. Mit der Funktion static_file können Sie sich um Details wie das Schätzen des Mimetyps und das Erstellen einer 404-Antwort kümmern, wenn die Datei nicht vorhanden ist.

# -*- coding: utf-8 -*-
from bottle import route, run, template, response


@route('/sample_image.png')
def sample_image():
    response.content_type = 'image/png'
    with open('./my_sample_image.png', 'rb') as fh:
        content = fh.read()
    response.set_header('Content-Length', str(len(content)))
    return content


run(host='localhost', port=8080)

Wenn Sie nun auf "http: // localhost: 8080 / sample_image.png " zugreifen, wird das Bild angezeigt.

Der Handler für die von Bottle aufgerufene HTTP-Anforderung verwendet die Eigenschaft, dass der Rückgabewert des Handlers so wie er ist zum Hauptteil der Antwort wird. Der HTTP-Antwortheader wird geändert, indem das Antwortobjekt des Flaschenpakets unverändert geändert wird. Persönlich ziehe ich es vor, ein HTTPResponse-Objekt wie das folgende explizit zusammenzustellen und zurückzugeben.

# -*- coding: utf-8 -*-
from bottle import route, run, template, HTTPResponse


@route('/sample_image.png')
def sample_image():
    with open('./my_sample_image.png', 'rb') as fh:
        content = fh.read()
    resp = HTTPResponse(status=200, body=content)
    resp.content_type = 'image/png'
    resp.set_header('Content-Length', str(len(content)))
    return resp


run(host='localhost', port=8080)

Wenn der Rückgabewert des Handlers HTTPResponse ist, gibt der Handler für die von Bottle aufgerufene HTTP-Anforderung die Antwort gemäß dem Inhalt des HTTPResponse-Objekts zurück. Weitere Informationen zu HTTPResponse finden Sie unter Request / Response-Objekt von Mastering Bottle.

Muster 2. Große Dateien, die nicht in den Speicher passen

Große Dateien, die nicht in den Speicher passen, müssen nach und nach aus der Datei gelesen und in den Socket geschrieben werden. Auch in solchen Fällen kann static_file verwendet werden. static_file ist keine Antwort, bei der der gesamte Inhalt der Datei gelesen wird, sondern eine Implementierung, die die Datei nach und nach intern liest und verteilt.

Nach der Untersuchung scheint es, dass, wenn der Flaschenhandler ein Generator wird, jedes vom Generator erzeugte Element als zerlegtes Fragment des Körpers an den Client gesendet wird. Selbst in der [Quelle] von static_file (https://github.com/bottlepy/bottle/blob/master/bottle.py#L2725) wird der Inhalt nach und nach von der Generatorfunktion _file_iter_range gelesen und zur Antwort. Und es scheint.

Wenn Sie es selbst implementieren, wird es wie folgt sein.

# -*- coding: utf-8 -*-
from bottle import route, run, template, response


@route('/sample_image.png')
def sample_image():
    response.content_type = 'image/png'
    bufsize = 1024  # 1KB
    with open('./my_sample_image.png', 'rb') as fh:
        while True:
            buf = fh.read(bufsize)
            if len(buf) == 0:
                break  # EOF
            yield buf


run(host='localhost', port=8080)

Sie müssen sich nicht an diese Methode erinnern, da es eine static_file gibt? Es gibt auch eine Geschichte, Ich denke, es kann eine Implementierung geben, z. B. das sofortige Lesen aus der Datenbank, ohne eine Datei durchzugehen, sie in ein CSV-Dateiformat zu verarbeiten und an den Client zu senden. Tatsächlich habe ich herausgefunden, wie es in einem solchen Fall geht, also hoffe ich, dass es jemand anderem hilft.

Wenn Sie das Objekt "HTTPResponse" in Form von "return" implementieren möchten, setzen Sie den Generator auf "body" des Objekts "HTTPResponse".

# -*- coding: utf-8 -*-
from bottle import route, run, template, HTTPResponse


@route('/sample_image.png')
def sample_image():
    resp = HTTPResponse(status=200)
    resp.content_type = 'image/png'

    def _file_content_iterator():
        bufsize = 1024  # 1KB
        with open('./my_sample_image.png', 'rb') as fh:
            while True:
                buf = fh.read(bufsize)
                if len(buf) == 0:
                    break  # EOF
                yield buf

    resp.body = _file_content_iterator()
    return resp


run(host='localhost', port=8080)

Diese Methode kann jedoch auch etwas unangenehm sein, da sie auf den ersten Blick schwer zu verstehen ist, z. B. das Definieren einer Funktion innerhalb einer Funktion. Das ist dein Favorit.

Die Implementierung des Generators mag für diejenigen, die Python noch nicht kennen, schwer zu verstehen sein, aber ich habe einen Artikel über Python-Iteratoren / Generatoren [Python-Iteratoren und -Generatoren] geschrieben (http://qiita.com/tomotaka_ito/items/35f3eb108f587022fa09). Bitte schauen Sie, wenn Sie möchten.

Ich möchte es herunterladen, anstatt es inline anzuzeigen

Es geht mehr um HTTP als um Flasche, aber Sie können dies mit dem Header "Content-Disposition" tun. Wenn Sie die Funktion "static_file" verwenden möchten, können Sie die Option "download" wie oben beschrieben auf "True" setzen. Hier werde ich die Implementierung der Interaktion mit "HTTPResponse" vorstellen.

# -*- coding: utf-8 -*-
from bottle import route, run, template, response


@route('/sample_image.png')
def sample_image():
    response.content_type = 'image/png'
    with open('./my_sample_image.png', 'rb') as fh:
        content = fh.read()
    response.set_header('Content-Length', str(len(content)))
    download_fname = 'hoge.png'
    response.set_header('Content-Disposition', 'attachment; filename="%s"' % download_fname.encode('utf-8'))
    return content


run(host='localhost', port=8080)

Wenn Sie nun auf "http: // localhost: 8080 / sample_image.png " zugreifen, wird das Bild unter dem Dateinamen "hoge.png " gespeichert.

Erläuterung der Argumente und Optionen der Funktion static_file

Die Signatur der Funktion static_file lautet wie folgt.

def static_file(filename, root,
                mimetype='auto',
                download=False,
                charset='UTF-8'):
    ....

--Dateiname: Der Name der Datei in root, die den Inhalt enthält, den Sie liefern möchten. --root: Das Verzeichnis mit der Datei filename, die den Inhalt enthält, den Sie liefern möchten.

Referenzlink

Recommended Posts

Implementierter Dateidownload mit Python + Bottle
Laden Sie die CSV-Datei mit Python herunter
CSV-Datei mit Python lesen (CSV-Datei herunterladen und analysieren)
BASIC-Authentifizierung mit Python-Flasche
Zeichnen Sie eine netCDF-Datei mit Python
SMO mit Python + NumPy implementiert
Extrahieren Sie die xz-Datei mit Python
[Python] Mit Python in eine CSV-Datei schreiben
[Mit Python automatisiert! ] Teil 1: Datei einstellen
Ausgabe in eine CSV-Datei mit Python
Laden Sie die mit appcfg.py bereitgestellte Datei herunter
Laden Sie Python herunter
[Mit Python automatisiert! ] Teil 2: Dateivorgang
Erstellen einer einfachen Power-Datei mit Python
Exklusive Steuerung mit Sperrdatei in Python
HTTP Split Download Typ mit Python gemacht
Überprüfen Sie die Existenz der Datei mit Python
Erstellen Sie schnell eine Excel-Datei mit Python #python
Laden Sie japanische Aktienkursdaten mit Python herunter
Lesen wir die RINEX-Datei mit Python ①
Laden Sie mit Python Dateien im Web herunter
[Python] Eine schnelle Webanwendung mit Bottle!
Erstellen Sie eine Excel-Datei mit Python + Ähnlichkeitsmatrix
Mit Python aufnehmen → Datei speichern (Soundgerät + Welle)
Laden Sie einfach mp3 / mp4 mit Python und youtube-dl herunter!
Laden Sie die Datei mit PHP herunter [Im Aufbau]
Download-Datei für Python Selen Chrome überschreiben
Ich habe mit Python eine Einstellungsdatei erstellt
[Automatisierung] Lesen Sie E-Mails (Nachrichtendatei) mit Python
Laden Sie WAV-Dateien per FTP mit Python auf X-Server hoch und laden Sie sie herunter
Skript-Python-Datei
FizzBuzz in Python3
Scraping mit Python
Statistik mit Python
Scraping mit Python
Python mit Go
Twilio mit Python
In Python integrieren
Spielen Sie mit 2016-Python
Python-Dateiverarbeitung
Laden Sie die Datei herunter, indem Sie das Download-Ziel mit Python & Selemiun & Chrome (Windows-Version) angeben.
AES256 mit Python
Getestet mit Python
Python beginnt mit ()
mit Syntax (Python)
Bingo mit Python
Zundokokiyoshi mit Python
Excel mit Python
Mikrocomputer mit Python
Mit Python besetzen
Mol2-Datei mit Python teilen (-> 17.04.2016. Unterstützt auch SDF-Datei)
nginxparser: Versuchen Sie, die nginx-Konfigurationsdatei mit Python zu analysieren
Lesen einer CSV-Datei mit Python 2/3
Suchen und laden Sie YouTube-Videos automatisch mit Python herunter
[Python] Wie man Excel-Dateien mit Pandas liest
Konvertieren Sie die SVG-Datei mit Python in png / ico
Lesen Sie Tabellendaten in einer PDF-Datei mit Python
[Python] Automatisierung zum Kopieren von Excel-Dateien implementiert
Entwickeln Sie Windows-Apps mit Python 3 + Tkinter (exe-Datei)