استخدام MultipartPostHandler لنشر بيانات النموذج باستخدام Python

StackOverflow https://stackoverflow.com/questions/680305

سؤال

مشكلة:عند نشر البيانات باستخدام urllib2 الخاص بـ Python، يتم ترميز جميع البيانات بعنوان URL وإرسالها كنوع محتوى:application/x-www-form-urlencoded.عند تحميل الملفات، يجب بدلاً من ذلك تعيين نوع المحتوى على بيانات متعددة الأجزاء/النموذج وأن تكون المحتويات مشفرة بـ MIME.مناقشة هذه المشكلة هنا:http://code.activestate.com/recipes/146306/

للتغلب على هذا القيد، أنشأ بعض المبرمجين المتميزين مكتبة تسمى MultipartPostHandler والتي تنشئ OpenerDirector يمكنك استخدامه مع urllib2 لإجراء عملية POST تلقائيًا في الغالب مع بيانات متعددة الأجزاء/النماذج.نسخة من هذه المكتبة هنا:http://peerit.blogspot.com/2007/07/multipartposthandler-doesnt-work-for.html

أنا جديد على لغة بايثون ولا أستطيع تشغيل هذه المكتبة.لقد كتبت بشكل أساسي الكود التالي.عندما ألتقطها في وكيل HTTP محلي، أستطيع أن أرى أن البيانات لا تزال مشفرة بعنوان URL وليست مشفرة بـ MIME متعددة الأجزاء.الرجاء مساعدتي في معرفة ما أفعله بشكل خاطئ أو طريقة أفضل لإنجاز ذلك.شكرًا :-)

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..."

تحرير 1:شكرا لأستجابتك.أنا على علم بحل ActiveState httplib لهذا (لقد قمت بربطه أعلاه).أفضل التخلص من المشكلة واستخدام الحد الأدنى من التعليمات البرمجية لمواصلة استخدام urllib2 كما كنت.هل لديك أي فكرة عن سبب عدم تثبيت أداة الفتح واستخدامها؟

هل كانت مفيدة؟

المحلول

ويبدو أن أسهل وأكثر متوافقة طريقة للالتفاف على هذه المشكلة هو استخدام "المرسل حدة.

# 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()

وهذا عمل مثالية وأنا لم يكن لديك لالوحل مع httplib. وحدة متاحة هنا: http://atlee.ca/software/poster/index.html

نصائح أخرى

وجدت هذه الوصفة للنشر متعددة الأجزاء باستخدام httplib مباشرة (أي المكتبات الخارجية المعنية)

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'

مجرد استخدام طلبات بايثون, ، سيقوم بتعيين الرؤوس المناسبة ويقوم بالتحميل نيابةً عنك:

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

لقد واجهت نفس المشكلة وكنت بحاجة إلى نشر نموذج متعدد الأجزاء دون استخدام مكتبات خارجية.لقد كتبت كاملة مدونة حول المشكلات التي واجهتها.

انتهى بي الأمر باستخدام نسخة معدلة من http://code.activestate.com/recipes/146306/.يقوم الكود الموجود في عنوان URL هذا في الواقع بإلحاق محتوى الملف كسلسلة، مما قد يسبب مشاكل في الملفات الثنائية.وهنا رمز العمل الخاص بي.

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

وأنا ما تتزامن، 2 سنة، 6 شهور I إنشاء المشروع

https://pypi.python.org/pypi/MultipartPostHandler2 ، أن إصلاح MultipartPostHandler ل أنظمة 8 حسابات الأمانة الأحادية. كما أنني قد فعلت بعض التحسينات الطفيفة، أنتم مدعوون لاختبار :)

لإجابة سؤال على OP لماذا رمز الأصلي لم تنجح، وكان معالج مرت في لا مثيل فئة. خط

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

ويجب قراءة

opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler())
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top