পাইথনে অনুরোধগুলি সহ একটি "মাল্টিপার্ট / ফর্ম-ডেটা" কীভাবে প্রেরণ করবেন?


211

multipart/form-dataপাইথনে অনুরোধগুলি সহ কীভাবে প্রেরণ করবেন ? কীভাবে ফাইল পাঠাতে হয় তা আমি বুঝতে পারি তবে কীভাবে এই পদ্ধতিতে ফর্ম ডেটা পাঠানো যায় তা বুঝতে পারি না।


আপনার প্রশ্নটি আসলে পরিষ্কার নয়। তুমি কি অর্জন করতে চাও? আপনি কি ফরমে কোনও ফাইল আপলোড ছাড়াই "মাল্টিপার্ট / ফর্ম-ডেটা" প্রেরণ করতে চান?
হান্স তারপরে

4
সত্য যে filesপরামিতি উভয় করতে ব্যবহার করা হয় খুব খারাপ এপিআই হয়। আমি মাল্টিপার্ট ডেটা প্রেরণ শিরোনাম ইস্যু উত্থাপন করেছি - এটি ঠিক করার জন্য আমাদের আরও ভাল API দরকার । আপনি যদি সম্মত হন যে filesমাল্টিপার্ট ডেটা প্রেরণের জন্য প্যারামিটার ব্যবহার করা সর্বোত্তমভাবে বিভ্রান্তিকর হয় তবে উপরের ইস্যুতে দয়া করে এপিআই পরিবর্তন করতে বলুন।
পাইওটর ডব্রোগস্ট

এই টুইটটি বন্ধ হয়েছে প্রাসঙ্গিক বা অন্যথায় বন্ধ সমস্যাগুলিতে মন্তব্য করতে লোকদের উত্সাহিত করবেন না।
ইয়ান স্ট্যাপলটন কর্ডাসকো

1
কোন বিষয় নয়, আমি আপনার মন্তব্যটি বন্ধ হওয়ার আগে পোস্ট করা হয়েছিল তা বুঝতে পেরেছি। আমি ঘৃণা করি কীভাবে স্ট্যাকওভারফ্লো জিনিসগুলিকে কালানুক্রমিক ক্রমে রাখে না।
ইয়ান স্ট্যাপলটন কর্ডাসকো

উত্তর:


166

মূলত, আপনি যদি কোনও filesপ্যারামিটার (একটি অভিধান) নির্দিষ্ট করে থাকেন তবে পোস্টের পরিবর্তে requestsএকটি multipart/form-dataPOST প্রেরণ করবেন application/x-www-form-urlencoded। তবে আপনি সেই অভিধানে আসল ফাইল ব্যবহারের মধ্যে সীমাবদ্ধ নন:

>>> import requests
>>> response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
>>> response.status_code
200

এবং httpbin.org আপনাকে কী শিরোনামগুলি পোস্ট করেছে তা জানতে দেয়; আমাদের মধ্যে response.json():

>>> from pprint import pprint
>>> pprint(response.json()['headers'])
{'Accept': '*/*',
 'Accept-Encoding': 'gzip, deflate',
 'Connection': 'close',
 'Content-Length': '141',
 'Content-Type': 'multipart/form-data; '
                 'boundary=c7cbfdd911b4e720f1dd8f479c50bc7f',
 'Host': 'httpbin.org',
 'User-Agent': 'python-requests/2.21.0'}

আরও ভাল, আপনি একক স্ট্রিং বা বাইটস অবজেক্টের পরিবর্তে টিপল ব্যবহার করে প্রতিটি অংশের জন্য ফাইলের নাম, সামগ্রীর ধরণ এবং অতিরিক্ত শিরোনাম নিয়ন্ত্রণ করতে পারেন can এই টিপলটিতে 2 থেকে 4 টি উপাদান থাকবে বলে আশা করা হচ্ছে; ফাইলের নাম, সামগ্রী, allyচ্ছিকভাবে একটি সামগ্রীর ধরণ এবং আরও শিরোনামগুলির একটি alচ্ছিক অভিধান।

আমি Noneফাইলের নাম হিসাবে টিউপল ফর্মটি ব্যবহার করব , যাতে filename="..."এই অংশগুলির জন্য অনুরোধটি থেকে প্যারামিটারটি বাদ পড়ে:

>>> files = {'foo': 'bar'}
>>> print(requests.Request('POST', 'http://httpbin.org/post', files=files).prepare().body.decode('utf8'))
--bb3f05a247b43eede27a124ef8b968c5
Content-Disposition: form-data; name="foo"; filename="foo"

bar
--bb3f05a247b43eede27a124ef8b968c5--
>>> files = {'foo': (None, 'bar')}
>>> print(requests.Request('POST', 'http://httpbin.org/post', files=files).prepare().body.decode('utf8'))
--d5ca8c90a869c5ae31f70fa3ddb23c76
Content-Disposition: form-data; name="foo"

bar
--d5ca8c90a869c5ae31f70fa3ddb23c76--

files আপনার যদি একই নামটির সাথে ক্রম এবং / অথবা একাধিক ক্ষেত্রের প্রয়োজন হয় তবে দ্বি-মানের টিউপসগুলির একটি তালিকাও হতে পারে:

requests.post(
    'http://requestb.in/xucj9exu',
    files=(
        ('foo', (None, 'bar')),
        ('foo', (None, 'baz')),
        ('spam', (None, 'eggs')),
    )
)

আপনি উভয় উল্লেখ করেন filesএবং dataতারপর, এটা নির্ভর করে মান এর dataকি পোস্টের মূল অংশটি তৈরি করতে ব্যবহার করা হবে। যদি dataএকটি স্ট্রিং হয় তবে কেবল এটি ব্যবহৃত হবে; অন্যথায় উভয়ই dataএবং filesব্যবহৃত হয়, dataপ্রথমে তালিকাভুক্ত উপাদানগুলির সাথে ।

এখানে দুর্দান্ত requests-toolbeltপ্রকল্পও রয়েছে, যার মধ্যে উন্নত মাল্টিপার্ট সমর্থন অন্তর্ভুক্ত রয়েছে । এটি filesপ্যারামিটারের মতো একই ফর্ম্যাটে ক্ষেত্রের সংজ্ঞা গ্রহণ করে , তবে এর বিপরীতে requestsএটি ফাইলের পরামিতিটি সেট না করার জন্য ডিফল্ট হয়। এছাড়াও, এটি ওপেন ফাইল অবজেক্টগুলি থেকে অনুরোধটি প্রবাহিত করতে পারে, যেখানে requestsপ্রথমে মেমরিতে অনুরোধের বডিটি তৈরি করবে:

from requests_toolbelt.multipart.encoder import MultipartEncoder

mp_encoder = MultipartEncoder(
    fields={
        'foo': 'bar',
        # plain file object, no filename or mime type produces a
        # Content-Disposition header with just the part name
        'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
    }
)
r = requests.post(
    'http://httpbin.org/post',
    data=mp_encoder,  # The MultipartEncoder is posted as data, don't use files=...!
    # The MultipartEncoder provides the content-type header with the boundary:
    headers={'Content-Type': mp_encoder.content_type}
)

ক্ষেত্রগুলি একই সম্মেলনগুলি অনুসরণ করে; একটি ফাইলের নাম, অংশ মাইম-টাইপ বা অতিরিক্ত শিরোনাম যুক্ত করতে 2 এবং 4 উপাদানের মধ্যে একটি টুপল ব্যবহার করুন। filesপ্যারামিটারের বিপরীতে , filenameআপনি যদি টিউপল ব্যবহার না করেন তবে কোনও ডিফল্ট মান সন্ধান করার চেষ্টা করা হয় না।


3
যদি ফাইলগুলি = {} ব্যবহার করা হয় তবে শিরোনাম = {'সামগ্রী-প্রকার': 'ব্লাহ ব্লাহ' be অবশ্যই ব্যবহার করা উচিত নয়!
জাকি

5
@ জাকী: প্রকৃতপক্ষে, multipart/form-dataসামগ্রী-প্রকারের কারণগুলিতে পোস্ট বডির অংশগুলি বর্ণন করতে ব্যবহৃত সীমানা মান অবশ্যই অন্তর্ভুক্ত থাকতে হবে । সেটিংস Content-Typeহেডার নিশ্চিত করে যে requestsএটা সঠিক মান সেট করে।
মার্টিজন পিটারস

গুরুত্বপূর্ণ দ্রষ্টব্য: অনুরোধটি কেবল তখনই প্রেরণ করা হবে multipart/form-dataযদি মানটির files=সত্যতা হয়, তাই আপনাকে যদি কোনও multipart/form-dataঅনুরোধ প্রেরণের প্রয়োজন হয় তবে কোনও ফাইল অন্তর্ভুক্ত না করে থাকে তবে আপনি একটি সত্যবাদী তবে অর্থহীন মান যেমন সেট করতে পারেন {'':''}এবং data=আপনার অনুরোধের সাথে সেট করতে পারেন। আপনি যদি এটি করছেন তবে Content-Typeশিরোনামটি নিজে সরবরাহ করবেন না ; requestsএটি আপনার জন্য সেট করা হবে। আপনি এখানে সত্যতা যাচাই করতে পারেন: github.com/psf/requests/blob/…
ড্যানিয়েল সীতুনায়াকে

@ ড্যানিয়েলসিতুনয়াকে এই জাতীয় হ্যাকের দরকার নেই। filesডিকের মধ্যে সমস্ত ক্ষেত্র স্রেফ রাখুন , সেগুলি ফাইল হতে হবে না (কেবলমাত্র টিউপল ফর্মটি ব্যবহার করতে হবে এবং ফাইলের নাম সেট করতে হবে তা নিশ্চিত করুন None)। আরও ভাল, requests_toolbeltপ্রকল্প ব্যবহার করুন ।
মার্টিজন পিটারস

ধন্যবাদ @ মার্তিজজনপিটারস, টিউপল ফর্মের কৌশলটি দুর্দান্ত! চেষ্টা করে দেখব।
ড্যানিয়েল সিতুনায়াকে

107

পূর্ববর্তী উত্তরগুলি লিখিত হওয়ার পরে, অনুরোধগুলি পরিবর্তন হয়েছে। কটাক্ষপাত আছে গিটহাব এ বাগ থ্রেড আরো বিস্তারিত জন্য এবং এই মন্তব্যটি একটি উদাহরণ জন্য।

সংক্ষেপে, ফাইলগুলির প্যারামিটারটি চাওয়ার dictসাথে ফর্ম ক্ষেত্রের নাম এবং মানটি স্ট্রিং বা একটি 2, 3 বা 4-দৈর্ঘ্যের টুপল হিসাবে থাকে, অনুরোধে একটি মাল্টি পার্ট-এনকোডযুক্ত ফাইল পোস্ট করুন বিভাগে বর্ণিত দ্রুত শুরু:

>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

উপরের দিকে, টিপলটি নিম্নরূপে রচিত:

(filename, data, content_type, headers)

মানটি যদি কেবল একটি স্ট্রিং হয় তবে ফাইলের নামটি কী হিসাবে একই থাকবে, নিম্নলিখিতটির মতো:

>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}

Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream

72c2b6f406cdabd578c5fd7598557c52

মানটি যদি একটি টিউপল হয় এবং প্রথম এন্ট্রি হয় Noneতবে ফাইলের নামটি অন্তর্ভুক্ত করা হবে না:

>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}

Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream

72c2b6f406cdabd578c5fd7598557c52

2
আপনার যদি আলাদা করতে হয় nameএবং filenameএকই নামে একাধিক ক্ষেত্র থাকতে হয় তবে কী হবে?
মাইকেল

1
@ মিশেল হিসাবে আমার একটি সিমিলার সমস্যা রয়েছে। আপনি কি প্রশ্নটি দেখে কিছু প্রস্তাব দিতে পারেন? [লিংক] ( stackoverflow.com/questions/30683352/... )
Shaardool

কেউ একই নামে একাধিক ক্ষেত্র রেখে এই সমস্যাটি সমাধান করেছেন?
ব্যবহারকারী3131037

1
filesটিউপলের প্রথম মান হিসাবে এন খালি স্ট্রিংটি পাস করার কৌশলটি আর কাজ করে না: requests.post dataঅতিরিক্ত নন-ফাইল multipart/form-dataপ্যারামিটারগুলি প্রেরণ করার জন্য আপনাকে প্যারামিটার ব্যবহার করতে হবে
লুকাস সিমন

1
Noneখালি স্ট্রিংয়ের পরিবর্তে পাস করা কাজ করে মনে হচ্ছে
আলেকজান্ডার ব্লিন

73

আপনার কোনও ফাইল আপলোড করার প্রয়োজন নেই এমন সময়েও আপনাকে filesএকটি বহুগুণ ফর্ম পোষ্ট অনুরোধ প্রেরণ করতে পরামিতিটি ব্যবহার করতে হবে।

মূল অনুরোধ উত্স থেকে:

def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.

    ...
    :param files: (optional) Dictionary of ``'name': file-like-objects``
        (or ``{'name': file-tuple}``) for multipart encoding upload.
        ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``,
        3-tuple ``('filename', fileobj, 'content_type')``
        or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``,
        where ``'content-type'`` is a string
        defining the content type of the given file
        and ``custom_headers`` a dict-like object 
        containing additional headers to add for the file.

সম্পর্কিত অংশটি হ'ল: file-tuple can be a2-tuple, ।3-tupleor a4-tuple

উপরের উপর ভিত্তি করে, সরল মাল্টিপার্ট ফর্ম অনুরোধ যাতে আপলোড এবং ক্ষেত্র গঠনের জন্য উভয় ফাইল অন্তর্ভুক্ত থাকে:

multipart_form_data = {
    'file2': ('custom_file_name.zip', open('myfile.zip', 'rb')),
    'action': (None, 'store'),
    'path': (None, '/path1')
}

response = requests.post('https://httpbin.org/post', files=multipart_form_data)

print(response.content)

Plain সরল পাঠ্য ক্ষেত্রগুলির জন্য টিপলে প্রথম আর্গুমেন্ট হিসাবে নোট করুন None- এটি ফাইল নাম ক্ষেত্রের জন্য একটি স্থানধারক যা কেবল ফাইল আপলোডগুলির জন্য ব্যবহৃত হয়, তবে Noneডেটা জমা দেওয়ার জন্য পাঠ্য ক্ষেত্রগুলির জন্য প্রথম প্যারামিটারটি পাস করার প্রয়োজন হয় ।

একই নামে একাধিক ক্ষেত্র

যদি আপনাকে একই নামে একাধিক ক্ষেত্র পোস্ট করতে হয় তবে অভিধানের পরিবর্তে আপনি নিজের বকেটকে তালিকার তালিকা (বা একটি টিপল) হিসাবে সংজ্ঞা দিতে পারেন:

multipart_form_data = (
    ('file2', ('custom_file_name.zip', open('myfile.zip', 'rb'))),
    ('action', (None, 'store')),
    ('path', (None, '/path1')),
    ('path', (None, '/path2')),
    ('path', (None, '/path3')),
)

স্ট্রিমিং অনুরোধগুলি এপিআই

উপরে এপিআই তোমার জন্য pythonic যথেষ্ট নয়, তাহলে ব্যবহারের বিষয়ে বিবেচনা অনুরোধ toolbelt ( pip install requests_toolbelt) যা একজন এক্সটেনশান কোর অনুরোধ মডিউল যে সেইসাথে স্ট্রিমিং ফাইল আপলোড করার জন্য সহায়তা প্রদান করে MultipartEncoder যা পরিবর্তে ব্যবহার করা যেতে পারে files, এবং যা এছাড়াও দেয় আপনি পেলোডকে অভিধান, tuple বা তালিকা হিসাবে সংজ্ঞায়িত করেন।

MultipartEncoderপ্রকৃত আপলোড ক্ষেত্রগুলি ছাড়া বা ছাড়া মাল্টিপার্ট অনুরোধের জন্য উভয়ই ব্যবহার করা যেতে পারে। এটি অবশ্যই dataপ্যারামিটারে বরাদ্দ করা উচিত ।

import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder

multipart_data = MultipartEncoder(
    fields={
            # a file upload field
            'file': ('file.zip', open('file.zip', 'rb'), 'text/plain')
            # plain text fields
            'field0': 'value0', 
            'field1': 'value1',
           }
    )

response = requests.post('http://httpbin.org/post', data=multipart_data,
                  headers={'Content-Type': multipart_data.content_type})

যদি আপনাকে একই নামে একাধিক ক্ষেত্র প্রেরণ করতে হয়, বা যদি ফর্ম ক্ষেত্রগুলির ক্রমটি গুরুত্বপূর্ণ হয় তবে অভিধানের পরিবর্তে একটি টিপল বা একটি তালিকা ব্যবহার করা যেতে পারে:

multipart_data = MultipartEncoder(
    fields=(
            ('action', 'ingest'), 
            ('item', 'spam'),
            ('item', 'sausage'),
            ('item', 'eggs'),
           )
    )

এই জন্য আপনাকে ধন্যবাদ. কীগুলির ক্রমটি আমার কাছে গুরুত্বপূর্ণ ছিল এবং এটি অনেক সহায়তা করেছিল।
জাঁকজমক

অ্যামেজিং। অনির্বচনীয়ভাবে, আমি যে এপিআই নিয়ে কাজ করছি তার জন্য একই কী এর জন্য 2 টি পৃথক মান প্রয়োজন। এটা চমৎকার. ধন্যবাদ.
আজান

@ সিপিপিজ্জা, আসলে এই লাইনের অর্থ কী? > "('file.py', খুলুন ('file.py', 'rb'), 'পাঠ্য / প্লেইন')"। এটি আমার পক্ষে কাজ করে না :(
ডেনিস কোরেইবা

@ ডেনিসকোরিয়াবা: এটি একটি ফাইল আপলোড ক্ষেত্রের একটি উদাহরণ যা ধরে নিয়েছে যে নামক কোনও ফাইল file.pyআপনার স্ক্রিপ্টের মতো একই ফোল্ডারে রয়েছে।
সিসিপিজ্জা

1
আপনি Noneখালি স্ট্রিংয়ের পরিবর্তে ব্যবহার করতে পারেন । তারপরে অনুরোধগুলি কোনও ফাইলের নাম অন্তর্ভুক্ত করবে না। পরিবর্তে Content-Disposition: form-data; name="action"; filename=""এটি হবে Content-Disposition: form-data; name="action"। সার্ভারের জন্য এই ক্ষেত্রগুলিকে ফর্ম ক্ষেত্র হিসাবে নয় ফাইল হিসাবে গ্রহণ করার জন্য এটি আমার পক্ষে সমালোচনামূলক।
মিতার

8

অনুরোধগুলি ব্যবহার করে অতিরিক্ত পরামিতি সহ একটি একক ফাইল আপলোড করার জন্য এখানে সহজ কোড স্নিপেট:

url = 'https://<file_upload_url>'
fp = '/Users/jainik/Desktop/data.csv'

files = {'file': open(fp, 'rb')}
payload = {'file_id': '1234'}

response = requests.put(url, files=files, data=payload, verify=False)

দয়া করে মনে রাখবেন যে আপনার কোনও সামগ্রীর প্রকার স্পষ্টভাবে নির্দিষ্ট করার দরকার নেই।

দ্রষ্টব্য: উপরের উত্তরগুলির মধ্যে একটিতে মন্তব্য করতে চেয়েছিলেন তবে কম খ্যাতির কারণে এখানে একটি নতুন প্রতিক্রিয়া খসড়া করা যায়নি।


4

আপনাকে nameসাইটের এইচটিএমএলে থাকা আপলোড ফাইলটির বৈশিষ্ট্যটি ব্যবহার করতে হবে। উদাহরণ:

autocomplete="off" name="image">

আপনি দেখুন name="image"> ? ফাইল আপলোড করার জন্য আপনি এটি কোনও সাইটের এইচটিএমএলে খুঁজে পেতে পারেন। ফাইলটি আপলোড করতে আপনার এটি ব্যবহার করতে হবেMultipart/form-data

লিপি:

import requests

site = 'https://prnt.sc/upload.php' # the site where you upload the file
filename = 'image.jpg'  # name example

এখানে, চিত্রের জায়গায়, HTML এ আপলোড ফাইলটির নাম যুক্ত করুন

up = {'image':(filename, open(filename, 'rb'), "multipart/form-data")}

আপলোডের জন্য যদি আপলোডের জন্য বোতামটি ক্লিক করতে হয় তবে আপনি এটি ব্যবহার করতে পারেন:

data = {
     "Button" : "Submit",
}

তারপরে অনুরোধ শুরু করুন

request = requests.post(site, files=up, data=data)

এবং সম্পন্ন হয়েছে, ফাইল সফলভাবে আপলোড হয়েছে


3

মাল্টিপার্ট / ফর্ম-ডেটা কী এবং মান প্রেরণ করুন

কার্ল কমান্ড:

curl -X PUT http://127.0.0.1:8080/api/xxx ...
-H 'content-type: multipart/form-data; boundary=----xxx' \
-F taskStatus=1

অজগর অনুরোধ - আরও জটিল পোস্টের অনুরোধগুলি :

    updateTaskUrl = "http://127.0.0.1:8080/api/xxx"
    updateInfoDict = {
        "taskStatus": 1,
    }
    resp = requests.put(updateTaskUrl, data=updateInfoDict)

মাল্টিপার্ট / ফর্ম-ডেটা ফাইল প্রেরণ করুন

কার্ল কমান্ড:

curl -X POST http://127.0.0.1:8080/api/xxx ...
-H 'content-type: multipart/form-data; boundary=----xxx' \
-F file=@/Users/xxx.txt

অজগর অনুরোধ - একটি মাল্টি পার্ট-এনকোডযুক্ত ফাইল পোস্ট করুন :

    filePath = "/Users/xxx.txt"
    fileFp = open(filePath, 'rb')
    fileInfoDict = {
        "file": fileFp,
    }
    resp = requests.post(uploadResultUrl, files=fileInfoDict)

এখানেই শেষ.


-1

এখানে পাইথন স্নিপেটটি আপনাকে একটি বৃহত একক ফাইল মাল্টিপার্ট ফর্মডাটা হিসাবে আপলোড করতে হবে। নোডজেস মুল্টর মিডলওয়্যারের সাথে সার্ভারের দিকে চলছে।

import requests
latest_file = 'path/to/file'
url = "http://httpbin.org/apiToUpload"
files = {'fieldName': open(latest_file, 'rb')}
r = requests.put(url, files=files)

সার্ভারের পক্ষের জন্য দয়া করে মাল্টারের ডকুমেন্টেশনগুলি এখানে পরীক্ষা করুন: https://github.com/expressjs/multer এখানে ফিল্ড সিঙ্গল ('ফিল্ডনেম') একক ফাইল গ্রহণ করতে ব্যবহৃত হয়, যেমন:

var upload = multer().single('fieldName');
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.