Python과 함께 Form-Data를 게시하기 위해 Multipartposthandler를 사용합니다
-
22-08-2019 - |
문제
문제 : Python의 urllib2와 함께 데이터를 게시 할 때 모든 데이터는 URL 인코딩되어 컨텐츠 유형으로 전송됩니다. 파일을 업로드 할 때 컨텐츠 유형은 대신 멀티 파트/양식 데이터로 설정되어야하며 내용은 MIME 인코딩해야합니다. 이 문제에 대한 논의는 다음과 같습니다.http://code.activestate.com/recipes/146306/
이 제한 사항을 해결하기 위해 일부 Sharp Coders는 Multipartposthandler라는 라이브러리를 만들었습니다.이 라이브러리는 Urllib2와 함께 사용할 수있는 오프너 디렉터를 생성하여 Multipart/Form-Data와 함께 자동 게시 할 수 있습니다. 이 라이브러리의 사본은 다음과 같습니다.http://peerit.blogspot.com/2007/07/multipartposthandler-doesnt-work-for.html
나는 Python을 처음 접 했고이 라이브러리를 작동시킬 수 없습니다. 본질적으로 다음 코드를 썼습니다. 로컬 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..."
edit1 : 응답에 감사드립니다. 나는 이것에 대한 활성화 된 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
다른 팁
이 레시피는 Multipart를 사용하여 게시하는 것을 발견했습니다 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 개월 전에 얼마나 일치 하는가, 나는 프로젝트를 만듭니다.
https://pypi.python.org/pypi/multipartposthandler2 UTF-8 시스템의 경우 MultipartPosthandler를 수정합니다. 나는 또한 약간의 개선을했고, 당신은 그것을 테스트 할 수 있습니다 :)
원래 코드가 작동하지 않는 이유에 대한 OP의 질문에 답하기 위해 전달 된 핸들러는 클래스의 인스턴스가 아니 었습니다. 라인
# MIME encode the POST payload
opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler)
읽어야합니다
opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler())