Есть ли способ отправить файл с помощью POST из скрипта Python?
python
post
file-upload
http-post
Только чтение
источник
источник
with open('report.xls', 'rb') as f: r = requests.post('http://httpbin.org/post', files={'report.xls': f})
вместо этого, чтобы он снова закрыл файл после открытия.Да. Вы должны использовать
urllib2
модуль и кодировать с использованиемmultipart/form-data
типа контента. Вот пример кода для начала - это немного больше, чем просто загрузка файлов, но вы должны иметь возможность прочитать его и посмотреть, как это работает:user_agent = "image uploader" default_message = "Image $current of $total" import logging import os from os.path import abspath, isabs, isdir, isfile, join import random import string import sys import mimetypes import urllib2 import httplib import time import re def random_string (length): return ''.join (random.choice (string.letters) for ii in range (length + 1)) def encode_multipart_data (data, files): boundary = random_string (30) def get_content_type (filename): return mimetypes.guess_type (filename)[0] or 'application/octet-stream' def encode_field (field_name): return ('--' + boundary, 'Content-Disposition: form-data; name="%s"' % field_name, '', str (data [field_name])) def encode_file (field_name): filename = files [field_name] return ('--' + boundary, 'Content-Disposition: form-data; name="%s"; filename="%s"' % (field_name, filename), 'Content-Type: %s' % get_content_type(filename), '', open (filename, 'rb').read ()) lines = [] for name in data: lines.extend (encode_field (name)) for name in files: lines.extend (encode_file (name)) lines.extend (('--%s--' % boundary, '')) body = '\r\n'.join (lines) headers = {'content-type': 'multipart/form-data; boundary=' + boundary, 'content-length': str (len (body))} return body, headers def send_post (url, data, files): req = urllib2.Request (url) connection = httplib.HTTPConnection (req.get_host ()) connection.request ('POST', req.get_selector (), *encode_multipart_data (data, files)) response = connection.getresponse () logging.debug ('response = %s', response.read ()) logging.debug ('Code: %s %s', response.status, response.reason) def make_upload_file (server, thread, delay = 15, message = None, username = None, email = None, password = None): delay = max (int (delay or '0'), 15) def upload_file (path, current, total): assert isabs (path) assert isfile (path) logging.debug ('Uploading %r to %r', path, server) message_template = string.Template (message or default_message) data = {'MAX_FILE_SIZE': '3145728', 'sub': '', 'mode': 'regist', 'com': message_template.safe_substitute (current = current, total = total), 'resto': thread, 'name': username or '', 'email': email or '', 'pwd': password or random_string (20),} files = {'upfile': path} send_post (server, data, files) logging.info ('Uploaded %r', path) rand_delay = random.randint (delay, delay + 5) logging.debug ('Sleeping for %.2f seconds------------------------------\n\n', rand_delay) time.sleep (rand_delay) return upload_file def upload_directory (path, upload_file): assert isabs (path) assert isdir (path) matching_filenames = [] file_matcher = re.compile (r'\.(?:jpe?g|gif|png)$', re.IGNORECASE) for dirpath, dirnames, filenames in os.walk (path): for name in filenames: file_path = join (dirpath, name) logging.debug ('Testing file_path %r', file_path) if file_matcher.search (file_path): matching_filenames.append (file_path) else: logging.info ('Ignoring non-image file %r', path) total_count = len (matching_filenames) for index, file_path in enumerate (matching_filenames): upload_file (file_path, index + 1, total_count) def run_upload (options, paths): upload_file = make_upload_file (**options) for arg in paths: path = abspath (arg) if isdir (path): upload_directory (path, upload_file) elif isfile (path): upload_file (path) else: logging.error ('No such path: %r' % path) logging.info ('Done!')
источник
Единственное, что мешает вам использовать urlopen непосредственно для файлового объекта, это то, что у встроенного файлового объекта отсутствует определение len . Простой способ - создать подкласс, который предоставляет urlopen с правильным файлом. Я также изменил заголовок Content-Type в файле ниже.
import os import urllib2 class EnhancedFile(file): def __init__(self, *args, **keyws): file.__init__(self, *args, **keyws) def __len__(self): return int(os.fstat(self.fileno())[6]) theFile = EnhancedFile('a.xml', 'r') theUrl = "http://example.com/abcde" theHeaders= {'Content-Type': 'text/xml'} theRequest = urllib2.Request(theUrl, theFile, theHeaders) response = urllib2.urlopen(theRequest) theFile.close() for line in response: print line
источник
Похоже, что запросы python не обрабатывают очень большие файлы, состоящие из нескольких частей.
В документации рекомендуется заглянуть в
requests-toolbelt
.Вот соответствующая страница из их документации.
источник
Библиотека плакатов Криса Атли отлично подходит для этого (особенно удобная функция
poster.encode.multipart_encode()
). В качестве бонуса он поддерживает потоковую передачу больших файлов без загрузки всего файла в память. См. Также выпуск Python 3244 .источник
Я пытаюсь протестировать django rest api и его работу для меня:
def test_upload_file(self): filename = "/Users/Ranvijay/tests/test_price_matrix.csv" data = {'file': open(filename, 'rb')} client = APIClient() # client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) response = client.post(reverse('price-matrix-csv'), data, format='multipart') print response self.assertEqual(response.status_code, status.HTTP_200_OK)
источник
close()
файл.Вы также можете посмотреть httplib2 с примерами . Я считаю, что использование httplib2 более лаконично, чем использование встроенных модулей HTTP.
источник
requests
вместо этого.def visit_v2(device_code, camera_code): image1 = MultipartParam.from_file("files", "/home/yuzx/1.txt") image2 = MultipartParam.from_file("files", "/home/yuzx/2.txt") datagen, headers = multipart_encode([('device_code', device_code), ('position', 3), ('person_data', person_data), image1, image2]) print "".join(datagen) if server_port == 80: port_str = "" else: port_str = ":%s" % (server_port,) url_str = "http://" + server_ip + port_str + "/adopen/device/visit_v2" headers['nothing'] = 'nothing' request = urllib2.Request(url_str, datagen, headers) try: response = urllib2.urlopen(request) resp = response.read() print "http_status =", response.code result = json.loads(resp) print resp return result except urllib2.HTTPError, e: print "http_status =", e.code print e.read()
источник