2009-08-12 41 views
5

Tôi quan tâm đến việc viết một tập lệnh python ngắn tải lên một tệp nhị phân ngắn (.wav/.raw audio) thông qua một yêu cầu POST tới một máy chủ từ xa.Các tệp nhị phân HTTP POST bằng Python: ví dụ ngắn gọn không phải là pycurl?

Tôi đã làm điều này với pycurl, điều này làm cho nó rất đơn giản và dẫn đến một tập lệnh súc tích; Thật không may nó cũng yêu cầu người dùng cuối có cài đặt pycurl, mà tôi không thể dựa vào.

Tôi cũng đã xem một số ví dụ trong các bài đăng khác chỉ dựa trên các thư viện cơ bản, urllib, urllib2, v.v., tuy nhiên, điều này dường như khá tiết kiệm, cũng là điều tôi muốn tránh.

Tôi tự hỏi nếu có bất kỳ ví dụ ngắn gọn nào không yêu cầu sử dụng thư viện bên ngoài và điều này sẽ nhanh chóng và dễ dàng cho bên thứ ba hiểu - ngay cả khi chúng không quen thuộc với python.

Những gì tôi đang sử dụng hiện nay có vẻ như,


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 

đây không phải là chính xác, nhưng nó mang lại cho bạn những ý tưởng chung. Nó hoạt động tuyệt vời, đơn giản để các bên thứ ba hiểu, nhưng yêu cầu pycurl.

+0

Liên quan: [Gửi tệp bằng POST từ tập lệnh Python] (http://stackoverflow.com/q/68477/95735) –

Trả lời

4

Việc gửi tệp yêu cầu mã hóa multipart/form-data và, theo như tôi biết, không có cách nào dễ dàng (nghĩa là một lớp lót hoặc thứ gì đó) để thực hiện điều này với stdlib. Nhưng như bạn đã đề cập, có rất nhiều công thức nấu ăn ngoài kia.

Mặc dù chúng có vẻ tiết, trường hợp sử dụng của bạn gợi ý rằng bạn có thể chỉ đóng gói nó một lần vào một hàm hoặc lớp và không lo lắng quá nhiều, phải không? Hãy nhìn vào công thức trên ActiveState và đọc các ý kiến ​​cho các đề xuất:

hoặc xem lớp MultiPartForm trong PyMOTW này, mà dường như khá tái sử dụng:

Tôi tin rằng cả hai xử lý tệp nhị phân.

+1

Cảm ơn, tôi đã kết thúc điều chỉnh một trong những ví dụ của PyMOTW cho mục đích của tôi. Tôi đoán không có cách nào để có được xung quanh bằng văn bản này lên. Tôi tự hỏi tại sao một cái gì đó như thế này vẫn chưa thực hiện theo cách của mình vào urllib hoặc urllib2? – si28719e

1

Làm thế nào để tiết kiệm chi tiết hơn? Bạn xây dựng postdict cơ bản theo cùng một cách, ngoại trừ bạn bắt đầu với

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

Khi bạn vave postdict,

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

và sau đó bạn nhận được và lưu resp.read() và có thể unquote và thử JSON nạp nếu cần thiết. Có vẻ như nó sẽ thực sự ngắn hơn! Vậy tôi đang thiếu gì ...?

+0

Đây thực sự là những gì tôi đã thử ban đầu - Tôi cũng nghĩ rằng nên/sẽ cung cấp giải pháp gọn gàng nhất . Thật không may vì nó là một tập tin POST có vẻ như tôi không thể lấy đi chỉ với việc này. Tôi phải xử lý multipart/form-data. Tôi đã kết thúc với pycurl ban đầu kể từ khi đóng gói thủ tục mã hóa độc đáo, nhưng tôi vẫn không hài lòng vì nó thêm một sự phụ thuộc. – si28719e

0

urllib.urlencode không thích một số loại dữ liệu nhị phân.

2

tôi gặp vấn đề tương tự ngày hôm nay, sau khi đã thử cả hai và pycurl và multipart/form-data, tôi quyết định đọc trăn httplib/urllib2 mã nguồn để tìm hiểu, tôi đã có được một giải pháp tương đối tốt:

  1. thiết lập tiêu đề Content-Length (của tập tin) trước khi làm bài
  2. vượt qua một tập tin mở ra khi làm bài

đây là mã:

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 

xem bài đăng trên blog của tôi: http://www.2maomao.com/blog/python-http-post-a-binary-file-using-urllib2/

2

Tôi biết đây là một chồng cũ, nhưng tôi có một giải pháp khác.

Nếu bạn đã đi qua những rắc rối của việc xây dựng tất cả các tiêu đề ma thuật và tất cả mọi thứ, và chỉ là khó chịu mà đột nhiên một tập tin nhị phân không thể vượt qua vì thư viện python là bình .. bạn khỉ có thể vá một giải pháp ..

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 

Nếu bạn đang sử dụng HTTP: // thay vì HTTPS: // thì hãy thay thế tất cả các phiên bản HTTPSConnection ở trên bằng HTTPConnection.

Trước khi mọi người bực mình với tôi, CÓ, đây là GIẢI PHÁP BAD, nhưng đó là cách để sửa mã hiện tại bạn thực sự không muốn thiết kế lại để làm theo cách khác.

Tại sao điều này khắc phục? Hãy nhìn vào nguồn Python gốc, tệp httplib.py.

Các vấn đề liên quan