์นดํ…Œ๊ณ ๋ฆฌ ๋ณด๊ด€๋ฌผ: Python

Python

ํŒŒ์ด์ฌ์œผ๋กœ ์š”์ฒญ๊ณผ ํ•จ๊ป˜ โ€œmultipart / form-dataโ€๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ์ดํ•ดํ•˜์ง€๋งŒ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ

multipart/form-dataํŒŒ์ด์ฌ์œผ๋กœ ์š”์ฒญ ์„ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ํŒŒ์ผ์„ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ์ดํ•ดํ•˜์ง€๋งŒ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ์ดํ•ดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.



๋‹ต๋ณ€

๊ธฐ๋ณธ์ ์œผ๋กœ files๋งค๊ฐœ ๋ณ€์ˆ˜ (์‚ฌ์ „) ๋ฅผ ์ง€์ • requestsํ•˜๋ฉด multipart/form-dataPOST ๋Œ€์‹  POST๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค 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'}

๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์€ ๋‹จ์ผ ๋ฌธ์ž์—ด ๋˜๋Š” ๋ฐ”์ดํŠธ ๊ฐ์ฒด ๋Œ€์‹  ํŠœํ”Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ ์ด๋ฆ„, ์ปจํ…์ธ  ์œ ํ˜• ๋ฐ ๊ฐ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€๋กœ ์ œ์–ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠœํ”Œ์€ 2 ~ 4 ๊ฐœ์˜ ์š”์†Œ๋ฅผ ํฌํ•จํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ ์ด๋ฆ„, ์ปจํ…์ธ , ์„ ํƒ์ ์œผ๋กœ ์ปจํ…์ธ  ์œ ํ˜• ๋ฐ ์ถ”๊ฐ€ ํ—ค๋”์˜ ์„ ํƒ์  ์‚ฌ์ „.

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, ๊ทธ๋Ÿฐ ๋‹ค์Œ์— ๋”ฐ๋ผ ๊ฐ’ ์˜ dataPOST๊ฐ€ ๋ชธ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค ๋ฌด์—‡. ๊ฒฝ์šฐ data๋ฌธ์ž์—ด ์ธ ๋งŒ์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žก์•„ ์ค„๊ป˜; ๊ทธ๋ ‡์ง€ ๋ชจ๋‘ data์™€ files์˜ ์š”์†Œ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋Š” data์ œ ๋‚˜์—ด.

๊ณ ๊ธ‰ ๋ฉ€ํ‹ฐ ํŒŒํŠธ ์ง€์›requests-toolbelt ์„ ํฌํ•จ ํ•˜๋Š” ์šฐ์ˆ˜ํ•œ ํ”„๋กœ์ ํŠธ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค . ๋งค๊ฐœ ๋ณ€์ˆ˜ ์™€ ๋™์ผํ•œ ํ˜•์‹์œผ๋กœ ํ•„๋“œ ์ •์˜๋ฅผ ์‚ฌ์šฉ ํ•˜์ง€๋งŒ, ๋‹ฌ๋ฆฌ ๊ธฐ๋ณธ์ ์œผ๋กœ ํŒŒ์ผ ์ด๋ฆ„ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์—ด๋ฆฐ ํŒŒ์ผ ๊ฐ์ฒด์—์„œ ์š”์ฒญ์„ ์ŠคํŠธ๋ฆฌ๋ฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋จผ์ € ์š”์ฒญ ๋ณธ๋ฌธ์„ ๋ฉ”๋ชจ๋ฆฌ์— ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.filesrequestsrequests

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}
)

ํ•„๋“œ๋Š” ๋™์ผํ•œ ๊ทœ์น™์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ํŒŒ์ผ ์ด๋ฆ„, ๋ถ€๋ถ„ MIME ํ˜•์‹ ๋˜๋Š” ์ถ”๊ฐ€ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด 2 ~ 4 ๊ฐœ์˜ ์š”์†Œ๊ฐ€์žˆ๋Š” ํŠœํ”Œ์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. files๋งค๊ฐœ ๋ณ€์ˆ˜ ์™€ ๋‹ฌ๋ฆฌ filenameํŠœํ”Œ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’์„ ์ฐพ์œผ๋ ค๊ณ  ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

์ด์ „ ๋‹ต๋ณ€์ด ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฏ€๋กœ ์š”์ฒญ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ ์€ Github ์˜ ๋ฒ„๊ทธ ์Šค๋ ˆ๋“œ ๋ฅผ ํ™•์ธํ•˜๊ณ  ์˜ˆ์ œ๋Š” ์ด ์ฃผ์„ ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์š”์ปจ๋Œ€, files ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” ์š”์ฒญ์˜ ๋ฉ€ํ‹ฐdict ํŒŒํŠธ ์ธ์ฝ”๋”ฉ ํŒŒ์ผ POST ์„น์…˜์— ์„ค๋ช… ๋œ๋Œ€๋กœ ํ‚ค๊ฐ€ ์–‘์‹ ํ•„๋“œ์˜ ์ด๋ฆ„์ด๊ณ  ๊ฐ’์ด ๋ฌธ์ž์—ด ๋˜๋Š” 2, 3 ๋˜๋Š” 4 ๊ธธ์ด ํŠœํ”Œ ์ธ a๋ฅผ ์‚ฌ์šฉ ํ•ฉ๋‹ˆ๋‹ค. ๋น ๋ฅธ ์‹œ์ž‘:

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

๋‹ต๋ณ€

๋‹น์‹ ์€ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ files๋ฉ€ํ‹ฐ ํŒŒํŠธ ํผ POST ์š”์ฒญ์„ ๋ณด๋‚ผ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‹ฌ์ง€์–ด ์–ด๋–ค ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์›๋ž˜ ์š”์ฒญ ์†Œ์Šค์—์„œ :

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)

โ˜ ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํ•„๋“œ์˜ ํŠœํ”Œ์—์„œ ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ฃผ๋ชฉํ•˜์‹ญ์‹œ์˜ค. 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')),
)

์ŠคํŠธ๋ฆฌ๋ฐ ์š”์ฒญ API

์œ„์˜ API๋Š” ๋‹น์‹ ์„์œ„ํ•œ ํŒŒ์ด์ฌ ์ •๋„๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์„ ๊ณ ๋ ค ์š”์ฒญ์ด ํˆด ๋ฒจํŠธ ( pip install requests_toolbelt์˜ ํ™•์žฅ ์ธ) ์˜ ํ•ต์‹ฌ ์š”๊ตฌ๋Š” ๊ทธ ํŒŒ์ผ ์—…๋กœ๋“œ๊ฐ€๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ŠคํŠธ๋ฆฌ๋ฐ์— ๋Œ€ํ•œ ์ง€์›์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ MultipartEncoder ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค files, ์–ด๋А๋„ ์žˆ์Šต๋‹ˆ๋‹ค ํŽ˜์ด๋กœ๋“œ๋ฅผ ์‚ฌ์ „, ํŠœํ”Œ ๋˜๋Š” ๋ชฉ๋ก์œผ๋กœ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

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'),
           )
    )

๋‹ต๋ณ€

๋‹ค์Œ์€ ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ถ”๊ฐ€ ๋งค๊ฐœ ๋ณ€์ˆ˜๊ฐ€์žˆ๋Š” ๋‹จ์ผ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์Šค ๋‹ˆํŽซ์ž…๋‹ˆ๋‹ค.

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)

์ฝ˜ํ…์ธ  ์œ ํ˜•์„ ๋ช…์‹œ ์ ์œผ๋กœ ์ง€์ •ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  : ์œ„์˜ ๋‹ต๋ณ€ ์ค‘ ํ•˜๋‚˜์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•˜๊ณ  ์‹ถ์—ˆ์ง€๋งŒ ํ‰ํŒ์ด ๋‚ฎ์•„์„œ ์—ฌ๊ธฐ์— ์ƒˆ๋กœ์šด ๋‹ต๋ณ€์„ ์ž‘์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

name์‚ฌ์ดํŠธ์˜ HTML์—์žˆ๋Š” ์—…๋กœ๋“œ ํŒŒ์ผ ์˜ ์†์„ฑ ์„ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค . ์˜ˆ:

autocomplete="off" name="image">

์•Œ name="image">๊ฒ ์–ด? ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์ดํŠธ์˜ HTML์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋ ค๋ฉด ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค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)

๊ทธ๋ฆฌ๊ณ , ํŒŒ์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์—…๋กœ๋“œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค


๋‹ต๋ณ€

๋ฉ€ํ‹ฐ ํŒŒํŠธ / ํผ ๋ฐ์ดํ„ฐ ํ‚ค ๋ฐ ๊ฐ’ ๋ณด๋‚ด๊ธฐ

์ปฌ ๋ช…๋ น :

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

ํŒŒ์ด์ฌ ์š”์ฒญ-๋” ๋ณต์žกํ•œ POST ์š”์ฒญ :

    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

ํŒŒ์ด์ฌ ์š”์ฒญ-๋ฉ€ํ‹ฐ ํŒŒํŠธ ์ธ์ฝ”๋”ฉ ํŒŒ์ผ POST :

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

๊ทธ๊ฒŒ ๋‹ค์•ผ.


๋‹ต๋ณ€

๋‹ค์Œ์€ ํ•˜๋‚˜์˜ ํฐ ๋‹จ์ผ ํŒŒ์ผ์„ ๋ฉ€ํ‹ฐ ํŒŒํŠธ formdata๋กœ ์—…๋กœ๋“œํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ Python ์Šค ๋‹ˆํŽซ์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ธก์—์„œ NodeJs Multer ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.

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 ์—์„œ multer ๋ฌธ์„œ๋ฅผ ํ™•์ธ ํ•˜์‹ญ์‹œ์˜ค.
์—ฌ๊ธฐ์—์„œ single ( โ€˜fieldNameโ€™) ํ•„๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋‚˜์˜ ๋‹จ์ผ ํŒŒ์ผ์„ ํ—ˆ์šฉํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

var upload = multer().single('fieldName');

์ด ๊ธ€์€ Python ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๋ถ„๋ฅ˜๋˜์—ˆ๊ณ  ๋‹˜์— ์˜ํ•ด ์— ์ž‘์„ฑ๋์Šต๋‹ˆ๋‹ค.