Frage

Problem: Wenn Daten mit Python urllib2 Posting, alle Daten URL codiert und als Content-Type gesendet: application / x-www-form-urlencoded. Beim Hochladen von Dateien sollte der Content-Type stattdessen eingestellt werden, um multipart / form-data und der Inhalt sein MIME verschlüsselt. Eine Diskussion über dieses Problem ist hier: http://code.activestate.com/recipes/146306/

Um diese Einschränkung zu bekommen einige scharfe Programmierer erstellt eine Bibliothek namens MultipartPostHandler, die eine OpenerDirector schafft man mit urllib2 können meist automatisch mit multipart / form-data POST. Eine Kopie dieser Bibliothek ist hier: http://peerit.blogspot.com/2007/07/multipartposthandler -doesnt-work-for.html

Ich bin neu in Python und bin nicht in der Lage diese Bibliothek zu arbeiten. Ich schrieb im Wesentlichen den folgenden Code ein. Wenn ich es in einem lokalen HTTP-Proxy erfassen, kann ich sehen, dass die Daten noch URL-codiert ist und nicht mehrteiligen MIME verschlüsselt. Bitte helfen Sie mir herauszufinden, was ich tue, falsch oder ein besserer Weg, dies zu tun bekommen. Danke: -)

FROM_ADDR = 'my@email.com'

try:
    data = open(file, 'rb').read()
except:
    print "Error: could not open file %s for reading" % file
    print "Check permissions on the file or folder it resides in"
    sys.exit(1)

# Build the POST request
url = "http://somedomain.com/?action=analyze"       
post_data = {}
post_data['analysisType'] = 'file'
post_data['executable'] = data
post_data['notification'] = 'email'
post_data['email'] = FROM_ADDR

# MIME encode the POST payload
opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler)
urllib2.install_opener(opener)
request = urllib2.Request(url, post_data)
request.set_proxy('127.0.0.1:8080', 'http') # For testing with Burp Proxy

# Make the request and capture the response
try:
    response = urllib2.urlopen(request)
    print response.geturl()
except urllib2.URLError, e:
    print "File upload failed..."

EDIT1: Vielen Dank für Ihre Antwort. Ich bin mir bewusst, der Activestate httplib Lösung dieses Problems (ich es oben verlinkten). Ich würde eher abstrakt das Problem weg und eine minimale Menge an Code verwenden, um weiterhin mit urllib2, wie ich war. Jede Idee, warum der Opener ist nicht installiert und verwendet?

War es hilfreich?

Lösung

Es scheint, dass die einfachste und kompatible Art und Weise, um dieses Problem zu bekommen, ist das Plakat 'Modul zu verwenden.

# test_client.py
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2

# Register the streaming http handlers with urllib2
register_openers()

# Start the multipart/form-data encoding of the file "DSC0001.jpg"
# "image1" is the name of the parameter, which is normally set
# via the "name" parameter of the HTML <input> tag.

# headers contains the necessary Content-Type and Content-Length
# datagen is a generator object that yields the encoded parameters
datagen, headers = multipart_encode({"image1": open("DSC0001.jpg")})

# Create the Request object
request = urllib2.Request("http://localhost:5000/upload_image", datagen, headers)
# Actually do the request, and get the response
print urllib2.urlopen(request).read()

Das funktionierte perfekt und ich habe nicht mit httplib Dreck. Das Modul ist hier verfügbar: http://atlee.ca/software/poster/index.html

Andere Tipps

Dieses Rezept gefunden mehrt mit httplib direkt schreiben (keine externen Bibliotheken beteiligt)

import httplib
import mimetypes

def post_multipart(host, selector, fields, files):
    content_type, body = encode_multipart_formdata(fields, files)
    h = httplib.HTTP(host)
    h.putrequest('POST', selector)
    h.putheader('content-type', content_type)
    h.putheader('content-length', str(len(body)))
    h.endheaders()
    h.send(body)
    errcode, errmsg, headers = h.getreply()
    return h.file.read()

def encode_multipart_formdata(fields, files):
    LIMIT = '----------lImIt_of_THE_fIle_eW_$'
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + LIMIT)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + LIMIT)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(value)
    L.append('--' + LIMIT + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % LIMIT
    return content_type, body

def get_content_type(filename):
    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'

Verwenden Sie einfach python-Anfragen , wird es richtige Header gesetzt und für Sie laden:

import requests 
files = {"form_input_field_name": open("filename", "rb")}
requests.post("http://httpbin.org/post", files=files)

Ich lief in das gleiche Problem und ich musste ohne Verwendung von externen Bibliotheken eine mehrteilige Form Post tun. Ich schrieb eine ganze Blogpost über die Probleme Ich lief in .

ich am Ende mit einer modifizierten Version von http://code.activestate.com/recipes/146306 / . Der Code in dieser URL tatsächlich fügt nur den Inhalt der Datei als Zeichenfolge, die Probleme mit binären Dateien verursachen kann. Hier ist mein Arbeits Code.

import mimetools
import mimetypes
import io
import http
import json


form = MultiPartForm()
form.add_field("form_field", "my awesome data")

# Add a fake file     
form.add_file(key, os.path.basename(filepath),
    fileHandle=codecs.open("/path/to/my/file.zip", "rb"))

# Build the request
url = "http://www.example.com/endpoint"
schema, netloc, url, params, query, fragments = urlparse.urlparse(url)

try:
    form_buffer =  form.get_binary().getvalue()
    http = httplib.HTTPConnection(netloc)
    http.connect()
    http.putrequest("POST", url)
    http.putheader('Content-type',form.get_content_type())
    http.putheader('Content-length', str(len(form_buffer)))
    http.endheaders()
    http.send(form_buffer)
except socket.error, e:
    raise SystemExit(1)

r = http.getresponse()
if r.status == 200:
    return json.loads(r.read())
else:
    print('Upload failed (%s): %s' % (r.status, r.reason))

class MultiPartForm(object):
    """Accumulate the data to be used when posting a form."""

    def __init__(self):
        self.form_fields = []
        self.files = []
        self.boundary = mimetools.choose_boundary()
        return

    def get_content_type(self):
        return 'multipart/form-data; boundary=%s' % self.boundary

    def add_field(self, name, value):
        """Add a simple field to the form data."""
        self.form_fields.append((name, value))
        return

    def add_file(self, fieldname, filename, fileHandle, mimetype=None):
        """Add a file to be uploaded."""
        body = fileHandle.read()
        if mimetype is None:
            mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
        self.files.append((fieldname, filename, mimetype, body))
        return

    def get_binary(self):
        """Return a binary buffer containing the form data, including attached files."""
        part_boundary = '--' + self.boundary

        binary = io.BytesIO()
        needsCLRF = False
        # Add the form fields
        for name, value in self.form_fields:
            if needsCLRF:
                binary.write('\r\n')
            needsCLRF = True

            block = [part_boundary,
              'Content-Disposition: form-data; name="%s"' % name,
              '',
              value
            ]
            binary.write('\r\n'.join(block))

        # Add the files to upload
        for field_name, filename, content_type, body in self.files:
            if needsCLRF:
                binary.write('\r\n')
            needsCLRF = True

            block = [part_boundary,
              str('Content-Disposition: file; name="%s"; filename="%s"' % \
              (field_name, filename)),
              'Content-Type: %s' % content_type,
              ''
              ]
            binary.write('\r\n'.join(block))
            binary.write('\r\n')
            binary.write(body)


        # add closing boundary marker,
        binary.write('\r\n--' + self.boundary + '--\r\n')
        return binary

ich, was für ein fallen zusammen, 2 Jahre, 6 Monate her schaffe ich das Projekt

https://pypi.python.org/pypi/MultipartPostHandler2 , die MultipartPostHandler fix für UTF-8-Systeme. Ich habe auch ein paar kleinere Verbesserungen gemacht, Sie sind herzlich eingeladen, es zu testen :)

die OPs Frage, warum hat der ursprüngliche Code zu beantworten, nicht funktioniert, der Handler übergeben war keine Instanz einer Klasse. Die Zeile

# MIME encode the POST payload
opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler)

sollte lesen

opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler())
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top