<p>Is there a way to send a file using POST from a Python script?</p>

[{'answer_id': 68502, 'author': 'John Millikin', 'author_id': 3560, 'author_profile': 'https://Stackoverflow.com/users/3560', 'pm_score': 5, 'selected': False, 'text': '<p>Yes. You\'d use the <code>urllib2</code> module, and encode using the <code>multipart/form-data</code> content type. Here is some sample code to get you started -- it\'s a bit more than just file uploading, but you should be able to read through it and see how it works:</p>\n\n<pre><code>user_agent = "image uploader"\ndefault_message = "Image $current of $total"\n\nimport logging\nimport os\nfrom os.path import abspath, isabs, isdir, isfile, join\nimport random\nimport string\nimport sys\nimport mimetypes\nimport urllib2\nimport httplib\nimport time\nimport re\n\ndef random_string (length):\n    return \'\'.join (random.choice (string.letters) for ii in range (length + 1))\n\ndef encode_multipart_data (data, files):\n    boundary = random_string (30)\n\n    def get_content_type (filename):\n        return mimetypes.guess_type (filename)[0] or \'application/octet-stream\'\n\n    def encode_field (field_name):\n        return (\'--\' + boundary,\n                \'Content-Disposition: form-data; name="%s"\' % field_name,\n                \'\', str (data [field_name]))\n\n    def encode_file (field_name):\n        filename = files [field_name]\n        return (\'--\' + boundary,\n                \'Content-Disposition: form-data; name="%s"; filename="%s"\' % (field_name, filename),\n                \'Content-Type: %s\' % get_content_type(filename),\n                \'\', open (filename, \'rb\').read ())\n\n    lines = []\n    for name in data:\n        lines.extend (encode_field (name))\n    for name in files:\n        lines.extend (encode_file (name))\n    lines.extend ((\'--%s--\' % boundary, \'\'))\n    body = \'\\r\\n\'.join (lines)\n\n    headers = {\'content-type\': \'multipart/form-data; boundary=\' + boundary,\n               \'content-length\': str (len (body))}\n\n    return body, headers\n\ndef send_post (url, data, files):\n    req = urllib2.Request (url)\n    connection = httplib.HTTPConnection (req.get_host ())\n    connection.request (\'POST\', req.get_selector (),\n                        *encode_multipart_data (data, files))\n    response = connection.getresponse ()\n    logging.debug (\'response = %s\', response.read ())\n    logging.debug (\'Code: %s %s\', response.status, response.reason)\n\ndef make_upload_file (server, thread, delay = 15, message = None,\n                      username = None, email = None, password = None):\n\n    delay = max (int (delay or \'0\'), 15)\n\n    def upload_file (path, current, total):\n        assert isabs (path)\n        assert isfile (path)\n\n        logging.debug (\'Uploading %r to %r\', path, server)\n        message_template = string.Template (message or default_message)\n\n        data = {\'MAX_FILE_SIZE\': \'3145728\',\n                \'sub\': \'\',\n                \'mode\': \'regist\',\n                \'com\': message_template.safe_substitute (current = current, total = total),\n                \'resto\': thread,\n                \'name\': username or \'\',\n                \'email\': email or \'\',\n                \'pwd\': password or random_string (20),}\n        files = {\'upfile\': path}\n\n        send_post (server, data, files)\n\n        logging.info (\'Uploaded %r\', path)\n        rand_delay = random.randint (delay, delay + 5)\n        logging.debug (\'Sleeping for %.2f seconds------------------------------\\n\\n\', rand_delay)\n        time.sleep (rand_delay)\n\n    return upload_file\n\ndef upload_directory (path, upload_file):\n    assert isabs (path)\n    assert isdir (path)\n\n    matching_filenames = []\n    file_matcher = re.compile (r\'\\.(?:jpe?g|gif|png)$\', re.IGNORECASE)\n\n    for dirpath, dirnames, filenames in os.walk (path):\n        for name in filenames:\n            file_path = join (dirpath, name)\n            logging.debug (\'Testing file_path %r\', file_path)\n            if file_matcher.search (file_path):\n                matching_filenames.append (file_path)\n            else:\n                logging.info (\'Ignoring non-image file %r\', path)\n\n    total_count = len (matching_filenames)\n    for index, file_path in enumerate (matching_filenames):\n        upload_file (file_path, index + 1, total_count)\n\ndef run_upload (options, paths):\n    upload_file = make_upload_file (**options)\n\n    for arg in paths:\n        path = abspath (arg)\n        if isdir (path):\n            upload_directory (path, upload_file)\n        elif isfile (path):\n            upload_file (path)\n        else:\n            logging.error (\'No such path: %r\' % path)\n\n    logging.info (\'Done!\')\n</code></pre>\n'}, {'answer_id': 75158, 'author': 'pdc', 'author_id': 8925, 'author_profile': 'https://Stackoverflow.com/users/8925', 'pm_score': 0, 'selected': False, 'text': '<p>You may also want to have a look at <a href="http://code.google.com/p/httplib2/" rel="nofollow noreferrer">httplib2</a>, with <a href="http://bitworking.org/projects/httplib2/doc/html/libhttplib2.html#examples" rel="nofollow noreferrer">examples</a>. I find using httplib2 is more concise than using the built-in HTTP modules.</p>\n'}, {'answer_id': 525193, 'author': 'gotgenes', 'author_id': 38140, 'author_profile': 'https://Stackoverflow.com/users/38140', 'pm_score': 2, 'selected': False, 'text': '<p>Chris Atlee\'s <a href="http://atlee.ca/software/poster/" rel="nofollow noreferrer">poster</a> library works really well for this (particularly the convenience function <code>poster.encode.multipart_encode()</code>). As a bonus, it supports streaming of large files without loading an entire file into memory. See also <a href="http://bugs.python.org/issue3244" rel="nofollow noreferrer">Python issue 3244</a>.</p>\n'}, {'answer_id': 7969778, 'author': 'ilmarinen', 'author_id': 1024114, 'author_profile': 'https://Stackoverflow.com/users/1024114', 'pm_score': 2, 'selected': False, 'text': '<p>The only thing that stops you from using urlopen directly on a file object is the fact that the builtin file object lacks a <strong>len</strong> definition. A simple way is to create a subclass, which provides urlopen with the correct file. \nI have also modified the Content-Type header in the file below.</p>\n\n<pre><code>import os\nimport urllib2\nclass EnhancedFile(file):\n    def __init__(self, *args, **keyws):\n        file.__init__(self, *args, **keyws)\n\n    def __len__(self):\n        return int(os.fstat(self.fileno())[6])\n\ntheFile = EnhancedFile(\'a.xml\', \'r\')\ntheUrl = "http://example.com/abcde"\ntheHeaders= {\'Content-Type\': \'text/xml\'}\n\ntheRequest = urllib2.Request(theUrl, theFile, theHeaders)\n\nresponse = urllib2.urlopen(theRequest)\n\ntheFile.close()\n\n\nfor line in response:\n    print line\n</code></pre>\n'}, {'answer_id': 10234640, 'author': 'Piotr Dobrogost', 'author_id': 95735, 'author_profile': 'https://Stackoverflow.com/users/95735', 'pm_score': 8, 'selected': False, 'text': '<p>From: <a href="https://requests.readthedocs.io/en/latest/user/quickstart/#post-a-multipart-encoded-file" rel="noreferrer">https://requests.readthedocs.io/en/latest/user/quickstart/#post-a-multipart-encoded-file</a></p>\n\n<p>Requests makes it very simple to upload Multipart-encoded files:</p>\n\n<pre><code>with open(\'report.xls\', \'rb\') as f:\n    r = requests.post(\'http://httpbin.org/post\', files={\'report.xls\': f})\n</code></pre>\n\n<p>That\'s it. I\'m not joking - this is one line of code. The file was sent. Let\'s check:</p>\n\n<pre><code>&gt;&gt;&gt; r.text\n{\n  "origin": "179.13.100.4",\n  "files": {\n    "report.xls": "&lt;censored...binary...data&gt;"\n  },\n  "form": {},\n  "url": "http://httpbin.org/post",\n  "args": {},\n  "headers": {\n    "Content-Length": "3196",\n    "Accept-Encoding": "identity, deflate, compress, gzip",\n    "Accept": "*/*",\n    "User-Agent": "python-requests/0.8.0",\n    "Host": "httpbin.org:80",\n    "Content-Type": "multipart/form-data; boundary=127.0.0.1.502.21746.1321131593.786.1"\n  },\n  "data": ""\n}\n</code></pre>\n'}, {'answer_id': 31305207, 'author': 'rye', 'author_id': 5091149, 'author_profile': 'https://Stackoverflow.com/users/5091149', 'pm_score': 3, 'selected': False, 'text': '<p>Looks like python requests does not handle extremely large multi-part files.</p>\n\n<p>The documentation recommends you look into <code>requests-toolbelt</code>.</p>\n\n<p><a href="https://toolbelt.readthedocs.org/en/latest/uploading-data.html" rel="nofollow">Here\'s the pertinent page</a> from their documentation.</p>\n'}, {'answer_id': 36078069, 'author': 'user6081103', 'author_id': 6081103, 'author_profile': 'https://Stackoverflow.com/users/6081103', 'pm_score': 0, 'selected': False, 'text': '<pre><code>def visit_v2(device_code, camera_code):\n    image1 = MultipartParam.from_file("files", "/home/yuzx/1.txt")\n    image2 = MultipartParam.from_file("files", "/home/yuzx/2.txt")\n    datagen, headers = multipart_encode([(\'device_code\', device_code), (\'position\', 3), (\'person_data\', person_data), image1, image2])\n    print "".join(datagen)\n    if server_port == 80:\n        port_str = ""\n    else:\n        port_str = ":%s" % (server_port,)\n    url_str = "http://" + server_ip + port_str + "/adopen/device/visit_v2"\n    headers[\'nothing\'] = \'nothing\'\n    request = urllib2.Request(url_str, datagen, headers)\n    try:\n        response = urllib2.urlopen(request)\n        resp = response.read()\n        print "http_status =", response.code\n        result = json.loads(resp)\n        print resp\n        return result\n    except urllib2.HTTPError, e:\n        print "http_status =", e.code\n        print e.read()\n</code></pre>\n'}, {'answer_id': 37142773, 'author': 'Ranvijay Sachan', 'author_id': 2654232, 'author_profile': 'https://Stackoverflow.com/users/2654232', 'pm_score': 2, 'selected': False, 'text': '<p>I am trying to test django rest api and its working for me:</p>\n\n<pre><code>def test_upload_file(self):\n        filename = "/Users/Ranvijay/tests/test_price_matrix.csv"\n        data = {\'file\': open(filename, \'rb\')}\n        client = APIClient()\n        # client.credentials(HTTP_AUTHORIZATION=\'Token \' + token.key)\n        response = client.post(reverse(\'price-matrix-csv\'), data, format=\'multipart\')\n\n        print response\n        self.assertEqual(response.status_code, status.HTTP_200_OK)\n</code></pre>\n'}, {'answer_id': 67273481, 'author': 'Станислав Тышко', 'author_id': 15771153, 'author_profile': 'https://Stackoverflow.com/users/15771153', 'pm_score': 1, 'selected': False, 'text': '<p><code>pip install http_file</code></p>\n<pre class="lang-py prettyprint-override"><code>#импорт вспомогательных библиотек\nimport urllib3\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\nimport requests\n#импорт http_file\nfrom http_file import download_file\n#создание новой сессии\ns = requests.Session()\n#соеденение с сервером через созданную сессию\ns.get(\'URL_MAIN\', verify=False)\n#загрузка файла в \'local_filename\' из \'fileUrl\' через созданную сессию\ndownload_file(\'local_filename\', \'fileUrl\', s)\n</code></pre>\n'}, {'answer_id': 74142597, 'author': 'xCovelus', 'author_id': 1550930, 'author_profile': 'https://Stackoverflow.com/users/1550930', 'pm_score': 0, 'selected': False, 'text': '<p>I tried some of the options here, but I had some issue with the headers (\'files\' field was empty).</p>\n<p>A simple mock to explain how I did the post using requests and fixing the issues:</p>\n<pre><code>import requests\n\nurl = \'http://127.0.0.1:54321/upload\'\nfile_to_send = \'25893538.pdf\'\n\nfiles = {\'file\': (file_to_send,\n                  open(file_to_send, \'rb\'),\n                  \'application/pdf\',\n                  {\'Expires\': \'0\'})}\n\nreply = requests.post(url=url, files=files)\nprint(reply.text)\n</code></pre>\n<p>More at <a href="https://requests.readthedocs.io/en/latest/user/quickstart/" rel="nofollow noreferrer">https://requests.readthedocs.io/en/latest/user/quickstart/</a></p>\n<p>To test this code, you could use a simple dummy server as this one (thought to run in a GNU/Linux or similar):</p>\n<pre><code>import os\nfrom flask import Flask, request, render_template\n\nrx_file_listener = Flask(__name__)\n\nfiles_store = &quot;/tmp&quot;\n@rx_file_listener.route(&quot;/upload&quot;, methods=[\'POST\'])\ndef upload_file():\n    storage = os.path.join(files_store, &quot;uploaded/&quot;)\n    print(storage)\n    \n    if not os.path.isdir(storage):\n        os.mkdir(storage)\n\n    try:\n        for file_rx in request.files.getlist(&quot;file&quot;):\n            name = file_rx.filename\n            destination = &quot;/&quot;.join([storage, name])\n            file_rx.save(destination)\n        \n        return &quot;200&quot;\n    except Exception:\n        return &quot;500&quot;\n\nif __name__ == &quot;__main__&quot;:\n    rx_file_listener.run(port=54321, debug=True)\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/68477', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4883/']