2008-09-16 13 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

अजगर 2.6.6 पर मैं मल्टीपार्ट सीमा पार्स करने में कोई त्रुटि हो रही थी विंडोज पर इस कोड का उपयोग करते हुए। मुझे स्ट्रिंग.लेटर्स से 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-boundary/147467#147467 –

+0

कॉलिंग run_upload ({' सर्वर ':' ',' थ्रेड ':' '}, पथ = ['/पथ/से/file.txt ']) इस पंक्ति में त्रुटि का कारण बनता है: upload_file (पथ) क्योंकि "अपलोड फ़ाइल" के लिए 3 पैरामीटर की आवश्यकता होती है इसलिए मैं इसे इस लाइन upload_file (पथ, 1, 1) – Radian

0

तुम भी देखने के लिए चाहते हो सकता है httplib2 पर, examples के साथ। मुझे अंतर्निहित HTTP मॉड्यूल का उपयोग करने के बजाय httplib2 का उपयोग करना अधिक संक्षिप्त है।

+1

के साथ बदल देता हूं कोई उदाहरण नहीं है जो फ़ाइल अपलोड से निपटने का तरीका दिखाता है। – dland

+0

लिंक पुराना है + कोई रेखांकित उदाहरण नहीं है। – jlr

+1

तब से यह https://github.com/httplib2/httplib2 पर ले जाया गया है। दूसरी तरफ, आजकल मैं इसके बजाय 'अनुरोध' की सिफारिश करता हूं। – pdc

2

क्रिस एटली की poster लाइब्रेरी इस के लिए वास्तव में अच्छी तरह से काम करती है (विशेष रूप से सुविधा फ़ंक्शन poster.encode.multipart_encode())। बोनस के रूप में, यह पूरी फाइल को स्मृति में लोड किए बिना बड़ी फ़ाइलों की स्ट्रीमिंग का समर्थन करता है। Python issue 3244 भी देखें।

4

एकमात्र चीज जो आपको सीधे किसी फ़ाइल ऑब्जेक्ट पर urlopen का उपयोग करने से रोकती है, यह तथ्य है कि बिल्टिन फ़ाइल ऑब्जेक्ट में लेन परिभाषा नहीं है। सबक्लास बनाने का एक आसान तरीका है, जो सही फ़ाइल के साथ urlopen प्रदान करता है। मैंने नीचे दी गई फ़ाइल में सामग्री-प्रकार शीर्षलेख भी संशोधित किया है।

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 (अनुरोध (theUrl, theFile, ...)) फ़ाइल की सामग्री को केवल एक सामान्य पोस्ट के रूप में एन्कोड करता है लेकिन सही फॉर्म फ़ील्ड निर्दिष्ट नहीं कर सकता है। मैं भी संस्करण यूरलोपेन (theUrl, urlencode ({'serveride_field_name': EnhancedFile ('my_file.txt')}) को भी कोशिश करता हूं), यह एक फ़ाइल अपलोड करता है लेकिन (निश्चित रूप से!) गलत सामग्री के साथ पर। क्या मुझे कुछ याद आया? – RayLuo

+0

उत्तर के लिए धन्यवाद। उपर्युक्त कोड का उपयोग करके मैंने वेबरवर में PUT अनुरोध का उपयोग करके 2.2 जीबी कच्ची छवि फ़ाइल स्थानांतरित कर दी थी। –

157

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

अनुरोधों को बहुत ही सरल मल्टीपार्ट एन्कोड फ़ाइलों को अपलोड करने में आता है:

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

यह है कि। मैं मजाक नहीं कर रहा हूं - यह कोड की एक पंक्ति है। फाइल भेजी गई थी। आइए जांचें:

>>> 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 एमबी से कम है तो मैं वही काम कर रहा हूं और इसके ठीक काम कर रहा हूं। अन्यथा यह एक त्रुटि फेंक रहा है .. कृपया [यहां] देखें (http://stackoverflow.com/questions/20217348/requests-post-files-upload-large-file-more-than-1-5-mb-python)। –

+1

करने के लिए कोशिश कर रहा हूँ क्या कुछ साइट का उपयोग अनुरोध जो मैं सफलतापूर्वक किया है करने के लिए प्रवेश है, लेकिन अब मैं में प्रवेश करने के बाद एक वीडियो अपलोड करना चाहते हैं और फार्म एक विभिन्न क्षेत्रों प्रस्तुत करने से पहले भरे जाने के लिए है। आर = requests.post ('http:: तो मैं कैसे च के रूप में वीडियो वर्णन, वीडियो शीर्षक आदि जैसे उन मूल्यों को पास करना चाहिए – TaraGurung

+14

आप शायद 'खुला साथ क्या करना चाहते हैं (' report.xls ',' rb ') // httpbin.org/post ', files = {' report.xls ': f})' इसके बजाय, इसलिए यह खोलने के बाद फ़ाइल को फिर से बंद कर देता है। – Hjulle

3

ऐसा लगता है कि पाइथन अनुरोध अत्यधिक बड़ी बहु-भाग फ़ाइलों को संभाल नहीं पाता है।

प्रलेखन आपको requests-toolbelt में देखने की सलाह देता है।

Here's the pertinent page उनके दस्तावेज़ से।

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

मैं मेरे लिए बाकी एपीआई और उसके काम करने django परीक्षण करने के लिए कोशिश कर रहा हूँ:

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) 
संबंधित मुद्दे