it-swarm.com.de

Machen Sie ein http POST Anforderung zum Hochladen einer Datei mit Python urllib/urllib2

Ich möchte eine POST - Anforderung zum Hochladen einer Datei in einen Web-Service (und zur Antwort) mit Python erstellen. Zum Beispiel kann ich die folgende POST - Anfrage mit curl ausführen:

curl -F "[email protected]" -F output=json http://jigsaw.w3.org/css-validator/validator

Wie kann ich dieselbe Anfrage mit Python urllib/urllib2 machen? Das nächste, was ich bisher bekam, ist folgendes:

with open("style.css", 'r') as f:
    content = f.read()
post_data = {"file": content, "output": "json"}
request = urllib2.Request("http://jigsaw.w3.org/css-validator/validator", \
                          data=urllib.urlencode(post_data))
response = urllib2.urlopen(request)

Ich habe einen HTTP-Fehler 500 aus dem obigen Code erhalten. Aber da mein Befehl curl erfolgreich ist, muss bei meiner Python-Anfrage etwas nicht stimmen?

Ich bin zu diesem Thema ziemlich neu und verzeihen Sie mir bitte, wenn die Anfängerfrage sehr einfache Antworten oder Fehler hat. Vielen Dank im Voraus für all Ihre Hilfe!

11
Ying Xiong

Nach einigem Graben scheint es, dass dieser Beitrag mein Problem gelöst hat. Es stellt sich heraus, dass ich den Multipart-Encoder richtig einrichten muss.

from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2

register_openers()

with open("style.css", 'r') as f:
    datagen, headers = multipart_encode({"file": f})
    request = urllib2.Request("http://jigsaw.w3.org/css-validator/validator", \
                              datagen, headers)
    response = urllib2.urlopen(request)
10
Ying Xiong

Ich persönlich denke, Sie sollten die Bibliothek request betrachten, um Dateien zu veröffentlichen.

url = 'http://jigsaw.w3.org/css-validator/validator'
files = {'file': open('style.css')}
response = requests.post(url, files=files)

Das Hochladen von Dateien mit urllib2 ist nicht unmöglich, aber eine recht komplizierte Aufgabe: http://pymotw.com/2/urllib2/#uploading-files

10
Wolph

Nun, es gibt mehrere Möglichkeiten, dies zu tun. Wie bereits erwähnt, können Sie die Datei in "multipart/form-data" versenden. Der Zieldienst erwartet diesen Typ jedoch möglicherweise nicht. In diesem Fall versuchen Sie möglicherweise weitere Ansätze.

Das Dateiobjekt übergeben

urllib2 kann ein Dateiobjekt als data akzeptieren. Wenn Sie diesen Typ übergeben, liest die Bibliothek die Datei als binären Stream und sendet sie aus. Not setzt jedoch den richtigen Content-Type-Header. Wenn der Content-Length-Header fehlt, versucht er außerdem, auf die len-Eigenschaft des Objekts zuzugreifen, die für die Dateien nicht vorhanden ist. Das heißt, Sie müssen sowohl den Content-Type- als auch den Content-Length-Header angeben, damit die Methode funktioniert:

import os
import urllib2

filename = '/var/tmp/myfile.Zip'
headers = {
    'Content-Type': 'application/Zip',
    'Content-Length': os.stat(filename).st_size,
}
request = urllib2.Request('http://localhost', open(filename, 'rb'),
                          headers=headers)
response = urllib2.urlopen(request)

Wickelt das Dateiobjekt um

Um die Länge nicht zu berücksichtigen, können Sie ein einfaches Wrapper-Objekt erstellen. Mit nur einer kleinen Änderung können Sie es anpassen, um den Inhalt von einer Zeichenfolge zu erhalten, wenn Sie die Datei in den Speicher geladen haben.

class BinaryFileObject:
  """Simple wrapper for a binary file for urllib2."""

  def __init__(self, filename):
    self.__size = int(os.stat(filename).st_size)
    self.__f = open(filename, 'rb')

  def read(self, blocksize):
    return self.__f.read(blocksize)

  def __len__(self):
    return self.__size

Kodiere den Inhalt als base64

Eine andere Möglichkeit besteht darin, die data über base64.b64encode zu codieren und den Content-Transfer-Type: base64-Header bereitzustellen. Diese Methode erfordert jedoch eine Unterstützung auf der Serverseite. Abhängig von der Implementierung kann der Dienst die Datei entweder annehmen und falsch speichern oder HTTP 400 zurückgeben. Z.B. Die GitHub-API gibt keinen Fehler aus, aber die hochgeladene Datei wird beschädigt.

1
real4x