2009-08-12 22 views
5

Jestem zainteresowany pisaniem krótkiego skryptu Pythona, który przesyła krótki plik binarny (.wav/.raw audio) za pośrednictwem żądania POST do zdalnego serwera.Pliki binarne HTTP POST za pomocą Pythona: zwięzłe przykłady nieprzypisane?

Zrobiłem to z pycurl, co czyni go bardzo prostym i powoduje zwięzły skrypt; niestety wymaga również, aby użytkownik końcowy miał zainstalowany pycurl, na którym nie mogę polegać.

Widziałem również kilka przykładów w innych postach, które opierają się tylko na podstawowych bibliotekach, urllib, urllib2 itp., Ale generalnie wydają się być dość szczegółowe, co jest również czymś, czego chciałbym uniknąć.

Zastanawiam się, czy istnieją jakieś zwięzłe przykłady, które nie wymagają korzystania z zewnętrznych bibliotek i które będą szybko i łatwo zrozumiałe dla osób trzecich - nawet jeśli nie są szczególnie obeznane z pythonem.

Co Używam obecnie wygląda,


def upload_wav(wavfile, url=None, **kwargs): 
    """Upload a wav file to the server, return the response.""" 

    class responseCallback: 
     """Store the server response.""" 
     def __init__(self): 
      self.contents='' 
     def body_callback(self, buf): 
      self.contents = self.contents + buf 

     def decode(self): 
      self.contents = urllib.unquote(self.contents) 
      try: 
       self.contents = simplejson.loads(self.contents) 
      except: 
       return self.contents 

    t = responseCallback() 
    c = pycurl.Curl() 
    c.setopt(c.POST,1) 
    c.setopt(c.WRITEFUNCTION, t.body_callback) 
    c.setopt(c.URL,url) 
    postdict = [ 
     ('userfile',(c.FORM_FILE,wavfile)), #wav file to post                     
     ] 
    #If there are extra keyword args add them to the postdict                     
    for key in kwargs: 
     postdict.append((key,kwargs[key])) 
    c.setopt(c.HTTPPOST,postdict) 
    c.setopt(c.VERBOSE,verbose) 
    c.perform() 
    c.close() 
    t.decode() 
    return t.contents 

to nie jest dokładny, ale daje ogólne pojęcie. Działa świetnie, jest to proste dla osób trzecich, aby zrozumieć, , ale wymaga pycurl.

+0

Powiązane: [Wyślij plik za pomocą POST ze skryptu w języku Python] (http://stackoverflow.com/q/68477/95735) –

Odpowiedz

4

Zapisywanie pliku wymaga kodowania multipart/form-data i, o ile wiem, nie ma łatwego sposobu (to znaczy jedno-liniowego lub czegoś podobnego), aby to zrobić ze stdlib. Ale jak wspomniałeś, istnieje wiele przepisów na ten temat.

Mimo że wydają się pełne, Twój przypadek użycia sugeruje, że możesz prawdopodobnie zamknąć go w funkcji lub klasie i nie martwić się zbytnio, prawda? Spójrz na receptury na ActiveState i przeczytać komentarze na sugestie:

lub zobaczyć klasę MultiPartForm w tym PyMOTW, co wydaje się dość wielokrotnego użytku:

Wierzę, że oba obsługują pliki binarne.

+1

Dzięki, zakończyłem dostosowywanie jednego z przykładów PyMOTW do mojego celu. Chyba nie ma sposobu, żeby to napisać. Zastanawiam się, dlaczego coś takiego nie dotarło jeszcze do urllib lub urllib2? – si28719e

1

W jaki sposób urllib jest znacznie bardziej szczegółowy? Budować postdict w zasadzie w ten sam sposób, z wyjątkiem zacząć

postdict = [ ('userfile', open(wavfile, 'rb').read()) ] 

Po vave postdict,

resp = urllib.urlopen(url, urllib.urlencode(postdict)) 

a następnie dostać i zapisać resp.read() a może koniec cytatu i spróbuj JSON-załadunek w razie potrzeby. Wygląda na to, że będzie krótszy! Więc czego mi brakuje ...?

+0

To jest to, co początkowo próbowałem - myślałem również, że powinien/powinien dostarczyć najmodniejsze rozwiązanie . Niestety, ponieważ jest to plik POST, wydaje mi się, że nie mogę uciec, robiąc to. Muszę obsługiwać dane wieloczęściowe/formularzowe. Skończyło się na tym, że początkowo chodziłem z pycurlem, ponieważ ładnie ujmuje tę procedurę kodowania, ale wciąż byłem niezadowolony, ponieważ dodaje on zależność. – si28719e

0

urllib.urlencode nie lubi niektórych rodzajów danych binarnych.

2

poznałem podobny problem dzisiaj, po próbowałem zarówno i pycurl i multipart/form-data, zdecyduję się czytać pyton httplib/urllib2 kod źródłowy, aby dowiedzieć się, że udało nam się porównywalnie dobre rozwiązanie:

  1. ustawić nagłówek Content-Length (pliku) przed wykonaniem słupek
  2. zdać otwierany plik, gdy robi po

Oto kod:

import urllib2, os 
image_path = "png\\01.png" 
url = 'http://xx.oo.com/webserviceapi/postfile/' 
length = os.path.getsize(image_path) 
png_data = open(image_path, "rb") 
request = urllib2.Request(url, data=png_data) 
request.add_header('Cache-Control', 'no-cache') 
request.add_header('Content-Length', '%d' % length) 
request.add_header('Content-Type', 'image/png') 
res = urllib2.urlopen(request).read().strip() 
return res 

zobacz mój wpis na blogu:

2

Wiem, że to stary stary stos, ale mam inne rozwiązanie.

Jeśli poszedł thru trud budowania wszystkie magiczne nagłówki i wszystko, a są po prostu zdenerwowany, że nagle plik binarny nie może przejść, ponieważ biblioteka Pythona jest średnią .. można małpa załatać rozwiązanie ..

import httplib 
class HTTPSConnection(httplib.HTTPSConnection): 
def _send_output(self, message_body=None): 
    self._buffer.extend(("","")) 
    msg = "\r\n".join(self._buffer) 
    del self._buffer[:] 
    self.send(msg) 
    if message_body is not None: 
     self.send(message_body) 

httplib.HTTPSConnection = HTTPSConnection 

Jeśli używasz protokołu HTTP: // zamiast HTTPS: //, zamień wszystkie wystąpienia HTTPSConnection powyżej za pomocą HTTPConnection.

Zanim ludzie się zdenerwują, TAK, jest to Złe ROZWIĄZANIE, ale jest to sposób na naprawienie istniejącego kodu, którego naprawdę nie chce się przebudowywać, aby zrobić to w inny sposób.

Dlaczego to rozwiązuje? Przejdź do oryginalnego źródła Pythona, pliku httplib.py.

Powiązane problemy