2008-09-16 11 views

答えて

26

はい。 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!') 
+1

私はマルチパート境界の解析でエラーを取得しました。これを行うには、string.lettersからstring.ascii_lettersに変更する必要がありました(http://stackoverflow.com/questions/2823316/generate-a-random-letter-in-python/2823331#2823331)。境界上の要件は、ここで説明されていますhttp://stackoverflow.com/questions/147451/what-are-valid-characters-for-creating-a-multipart-form-b​​oundary/147467#147467 –

+0

run_uploadを({」を呼び出しますサーバ ':'」、 '糸': ''}、パス= [ '/パス/に/ file.txtを'])この行でエラーが発生し : upload_file(パス) 3つのパラメータを必要とする "ファイルをアップロードする" ため は、私は、ファイルのアップロードに対処する方法を示しています何の例がありません – Radian

0

あなたはまた外観を持つようにしたいことhttplib2で、examplesである。私は、httplib2を使用することが、組み込みのHTTPモジュールを使用するよりも簡潔であることを発見しました。

+1

このライン upload_file(パス、1、1)に置き換えられます。 – dland

+0

リンクは古く、インライン化されていません。 – jlr

+1

その後、https://github.com/httplib2/httplib2に移動しました。一方で、今日はおそらく '要求'を代わりにお勧めします。 – pdc

2

Chris Atleeさんのposterライブラリは、この機能(特に便利機能poster.encode.multipart_encode())のために本当にうまく機能します。ボーナスとして、ファイル全体をメモリにロードせずに大きなファイルのストリーミングをサポートします。 Python issue 3244も参照してください。

4

ファイルオブジェクトに直接urlopenを使用することを止める唯一の事実は、組み込みファイルオブジェクトにlenの定義がないことです。簡単な方法は、urlopenに正しいファイルを提供するサブクラスを作成することです。 以下のファイルのContent-Typeヘッダーも変更しました。

>>> with open('report.xls', 'rb') as f: r = requests.post('http://httpbin.org/post', files={'report.xls': f}) 

それだ:http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file

要求の中から

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

@robert Python2.7でコードをテストしますが、機能しません。 urlopen(Request(theUrl、theFile、...))は、ファイルの内容を通常の投稿と同じようにエンコードしますが、正しい書式フィールドは指定できません。 私は変わったurlopen(theUrl、urlencode({'serverside_field_name':EnhancedFile( 'my_file.txt')})))を試しても、間違った内容のファイルを(もちろん!)my_file.txtとしてアップロードします'、0x00D6B718>でモード' r '。 私は何かを見逃しましたか? – RayLuo

+0

答えをありがとう。上記のコードを使用すると、PUTリクエストを使用して2.2 GBのRAWイメージファイルをWebサーバーに転送しました。 –

157

は、マルチパートエンコードされたファイルをアップロードすることが非常に簡単になります。私は冗談ではありません - これはコードの1行です。ファイルが送信されました。確認しましょう:

>>> r.text 
{ 
    "origin": "179.13.100.4", 
    "files": { 
    "report.xls": "<censored...binary...data>" 
    }, 
    "form": {}, 
    "url": "http://httpbin.org/post", 
    "args": {}, 
    "headers": { 
    "Content-Length": "3196", 
    "Accept-Encoding": "identity, deflate, compress, gzip", 
    "Accept": "*/*", 
    "User-Agent": "python-requests/0.8.0", 
    "Host": "httpbin.org:80", 
    "Content-Type": "multipart/form-data; boundary=127.0.0.1.502.21746.1321131593.786.1" 
    }, 
    "data": "" 
} 
+1

ファイルサイズが1.5 MB未満の場合、私は同じことを試しています。それ以外の場合は、エラーを投げてください.. [こちら]を見てください(http://stackoverflow.com/questions/20217348/requests-post-files-upload-large-file-more-than-1-5-mb-python )。 –

+1

何をしようとしているのは、私がうまくやったリクエストを使っていくつかのサイトにログインすることですが、今はログイン後にビデオをアップロードしたいのですが、フォームに提出するフィールドが異なります。だから、どのように私はビデオの説明、ビデオのタイトルなど – TaraGurung

+14

のような値を渡す必要がありますあなたはおそらく '( 'report.xls'、 'rb')を開くと' f:r = requests.post( 'http:// httpbin.org/post '、files = {' report.xls ':f}) 'を実行して、オープンした後でファイルを再度閉じます。 – Hjulle

3

非常に大きなマルチパートファイルはpythonリクエストでは処理されません。

ドキュメントでは、requests-toolbeltに見てお勧めします。そのドキュメントから

Here's the pertinent page。私は私のために残りのAPIとその作業をDjangoのテストしようとしています

0
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() 
2

:Windows上でこのコードを使用している間のpython 2.6.6で

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)