2008-09-16 4 views

Antwort

26

Ja. Sie würden das Modul urllib2 verwenden und mit dem Inhaltstyp multipart/form-data codieren. Hier ist ein Beispielcode für den Anfang - es ist ein bisschen mehr als nur Hochladen der Datei, aber Sie sollten durch sie in der Lage zu lesen und sehen, wie es funktioniert:

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

Auf Python 2.6.6 Ich war einen Fehler in Mehrteiliger Grenze Parsing bekommen, während Sie diesen Code auf Windows. Ich musste von string.letters zu string.ascii_letters wechseln, wie in http://stackoverflow.com/questions/2823316/generate-a-random-letter-in-python/2823331#2823331 beschrieben, damit dies funktioniert. Die Randbedingung wird hier erläutert: http://stackoverflow.com/questions/147451/what-are-valid-characters-for-creating-a-multipart-form-boundary/147467#147467 –

+0

Aufruf run_upload ({' Server ':', 'Thread': ''}, Pfade = ['/ Pfad/zu/Datei.txt']) verursacht Fehler in dieser Zeile: upload_file (Pfad) , da "Datei hochladen" 3 Parameter erfordert , also ersetze ich es mit dieser Zeile upload_file (Pfad, 1, 1) – Radian

0

Sie können auch einen Blick haben wollen unter httplib2, mit examples. Ich finde die Verwendung von httplib2 ist prägnanter als die Verwendung der integrierten HTTP-Module.

+1

Es gibt keine Beispiele, die zeigen, wie mit Dateiuploads umzugehen. – dland

+0

Link ist veraltet + kein inlined Beispiel. – jlr

+1

Es ist seither nach https://github.com/httplib2/httplib2 umgezogen. Auf der anderen Seite würde ich heute wahrscheinlich "Anfragen" empfehlen. – pdc

2

Chris Atlee poster Bibliothek funktioniert wirklich gut für diese (vor allem die Komfortfunktion poster.encode.multipart_encode()). Als Bonus unterstützt es das Streamen großer Dateien, ohne eine ganze Datei in den Speicher zu laden. Siehe auch Python issue 3244.

4

Die einzige Sache, die Sie davon abhält, urlopen direkt auf einem Dateiobjekt zu verwenden, ist die Tatsache, dass das eingebaute Dateiobjekt keine len Definition hat. Eine einfache Möglichkeit besteht darin, eine Unterklasse zu erstellen, die urlopen mit der korrekten Datei versorgt. Ich habe auch den Content-Type-Header in der Datei unten geändert.

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 Ich teste deinen Code in Python2.7, aber es funktioniert nicht. urlopen (Request (THEURL, thefile, ...)) kodiert, lediglich den Inhalt der Datei, als ob eine normale Post, aber das richtige Formularfeld nicht angeben kann. Ich versuche sogar Variante urlopen (THEURL, urlencode ({ 'serverside_field_name': EnhancedFile ('my_file.txt')})), lädt er eine Datei aber (natürlich!) Mit falschem Inhalt als . Habe ich etwas verpasst? – RayLuo

+0

Danke für die Antwort. Unter Verwendung des obigen Codes hatte ich eine 2,2-GB-Rohbilddatei unter Verwendung der PUT-Anforderung in den Webserver übertragen. –

157

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

Anfragen macht es sehr einfach, Multipart-kodierte Dateien hochladen:

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

Das ist es. Ich mache keine Witze - das ist eine Codezeile. Die Datei wurde gesendet. Lassen Sie uns überprüfen:

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

Ich versuche das gleiche, und es funktioniert gut, wenn die Dateigröße weniger als ~ 1,5 MB ist. seine sonst einen Fehler werfen .. bitte Blick auf [hier] haben (http://stackoverflow.com/questions/20217348/requests-post-files-upload-large-file-more-than-1-5-mb-python). –

+1

, was zu einem gewissen Website mit Wunsch zu tun versucht, ist Login, die ich erfolgreich getan habe, aber jetzt will ich nach der Anmeldung ein Video hochladen und die Form hat ein anderen Felder vor der Vorlage ausgefüllt werden. Also, wie soll ich diese Werte wie Videos Beschreibung passieren, Videos Titel etc – TaraGurung

+14

Sie würden vermutlich 'mit offenem tun wollen ('Report.xls', 'rb') als f: r = requests.post ('http: // httpbin.org/post ', files = {' report.xls ': f}) 'stattdessen, so schließt es die Datei nach dem Öffnen wieder. – Hjulle

3

Sieht aus wie Python-Anfragen nicht behandelt extrem große mehrteilige Dateien.

Die Dokumentation empfiehlt Ihnen, in requests-toolbelt zu schauen.

Here's the pertinent page aus ihrer Dokumentation.

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

ich für mich Rest api und seine Arbeits zu testen versuchen 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)