2013-10-18 27 views
19

Tôi cần thực hiện cuộc gọi API để tải lên tệp cùng với chuỗi JSON có thông tin chi tiết về tệp.Yêu cầu Python: Gửi JSON và tệp theo yêu cầu duy nhất

Tôi đang cố gắng sử dụng các yêu cầu python lib để làm điều này:

import requests 

info = { 
    'var1' : 'this', 
    'var2' : 'that', 
} 

data = json.dumps({ 
    'token' : auth_token, 
    'info' : info, 
}) 

headers = {'Content-type': 'multipart/form-data'} 

files = {'document': open('file_name.pdf', 'rb')} 

r = requests.post(url, files=files, data=data, headers=headers) 

này ném các lỗi sau:

raise ValueError("Data must not be a string.") 
ValueError: Data must not be a string 

Nếu tôi loại bỏ các 'files' từ yêu cầu, nó hoạt động .
Nếu tôi xóa 'dữ liệu' khỏi yêu cầu, nó hoạt động.
Nếu tôi không mã hóa dữ liệu dưới dạng JSON thì nó hoạt động.

Vì lý do này, tôi cho rằng lỗi là thực hiện việc gửi dữ liệu JSON và các tệp trong cùng một yêu cầu.

Bất kỳ ý tưởng nào về cách làm việc này?

+0

Có dường như là một lỗi đánh máy trong mã của bạn: 'var2' nên được theo sau bởi một' '', phải không? –

+0

vâng, cố định ví dụ của tôi, cảm ơn! – oznu

Trả lời

13

Đừng mã hóa sử dụng json .

import requests 

info = { 
    'var1' : 'this', 
    'var2' : 'that', 
} 

data = { 
    'token' : auth_token, 
    'info' : info, 
} 

headers = {'Content-type': 'multipart/form-data'} 

files = {'document': open('file_name.pdf', 'rb')} 

r = requests.post(url, files=files, data=data, headers=headers) 

Lưu ý rằng điều này có thể không nhất thiết là thứ bạn muốn, vì nó sẽ trở thành một phần dữ liệu biểu mẫu khác.

+0

Nếu tôi làm như bạn đề nghị, tôi nhận được một ngoại lệ: "cần nhiều hơn 1 giá trị để giải nén" và tự hỏi phải làm gì với nó :-( – Arkady

1

Tôi không nghĩ rằng bạn có thể gửi cả dữ liệu và các tập tin trong một file nhiều phần dữ liệu được mã hóa, vì vậy bạn cần phải làm cho dữ liệu của bạn một "tập tin" quá:

files = { 
    'data' : data, 
    'document': open('file_name.pdf', 'rb') 
} 

r = requests.post(url, files=files, headers=headers) 
+0

Bạn giải mã như thế nào? Khách hàng sẽ nhận được một dict python không JSON phải không? đó là một câu hỏi! – ivansabik

+0

@sabik: yêu cầu mã hóa từ điển dưới dạng dữ liệu biểu mẫu. – RemcoGerlich

5

Xem chủ đề này How to send JSON as part of multipart POST-request

Đừng đặt tiêu đề Content-type chính mình, rời khỏi đó để pyrequests để tạo

def send_request(): 
payload = {"param_1": "value_1", "param_2": "value_2"} 
files = { 
    'json': (None, json.dumps(payload), 'application/json'), 
    'file': (os.path.basename(file), open(file, 'rb'), 'application/octet-stream') 
} 

r = requests.post(url, files=files) 
print(r.content) 
+0

Wow .. The 'None' saved me !!! – EvgenyKolyakov

+0

giả sử Flask là người nhận những gì sẽ là cách để mã flask cho rằng? – MouIdri

+0

@Mouldri try 'response.data' –

0

Hơn thế nữa:

files = { 
    'document': open('file_name.pdf', 'rb') 
} 

Điều đó sẽ chỉ hoạt động nếu tệp của bạn nằm trong cùng một thư mục nơi tập lệnh của bạn t là.

Nếu bạn muốn thêm tập tin từ thư mục khác nhau, bạn nên làm:

files = { 
    'document': open(os.path.join(dir_path, 'file_name.pdf'), 'rb') 
} 

đâu dir_path là một thư mục với bạn 'file_name.pdf' tập tin.

Nhưng nếu bạn muốn gửi nhiều tệp PDF thì sao?

Bạn chỉ cần thực hiện chức năng tùy chỉnh để trả về danh sách các tệp bạn cần (trong trường hợp của bạn chỉ có thể là những tệp có phần mở rộng là .pdf).Đó cũng bao gồm các file trong thư mục con (tìm kiếm cho các tập tin một cách đệ quy):

def prepare_pdfs(): 
    return sorted([os.path.join(root, filename) for root, dirnames, filenames in os.walk(dir_path) for filename in filenames if filename.endswith('.pdf')]) 

Sau đó, bạn có thể gọi nó là:

my_data = prepare_pdfs() 

Và với vòng lặp đơn giản:

for file in my_data: 

    pdf = open(file, 'rb') 

    files = { 
     'document': pdf 
    } 

    r = requests.post(url, files=files, ...) 
Các vấn đề liên quan