2013-10-18 14 views
19

Muszę wykonać wywołanie API, aby przesłać plik wraz z ciągiem JSON ze szczegółowymi informacjami o pliku.Żądania w pythoku: Opublikuj JSON i plik w jednym żądaniu

Próbuję użyć lib wnioski python to zrobić:

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) 

To rzuca się następujący błąd:

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

jeśli usunąć 'pliki' z żądania, to działa .
Po usunięciu "danych" z żądania działa.
Jeśli nie koduję danych jako JSON, to działa.

Z tego powodu myślę, że błąd polega na wysyłaniu danych i plików JSON w tym samym żądaniu.

Jakieś pomysły, jak to działa?

+0

wydaje się być literówka w twoim kodzie: 'var2' powinno następować po' '', prawda? –

+0

Tak, naprawiłem mój przykład, dzięki! – oznu

Odpowiedz

13

Nie zakodować za pomocą 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) 

Należy zauważyć, że niekoniecznie jest to, co chcesz, ponieważ stanie się on kolejną sekcją danych formularza.

+0

Jeśli robię tak, jak sugerujesz, otrzymuję inny wyjątek: "potrzebuję więcej niż 1 wartości do rozpakowania" i zastanawiam się, co z tym zrobić :-( – Arkady

1

ja nie sądzę, można wysyłać dane i pliki w pliku wieloczęściowy kodowane, więc trzeba wykonać dane „plik” zbyt:

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

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

Jak byś to zdekodował? Klient otrzymałby polecenie Pythona, a nie JSON? to jest pytanie! – ivansabik

+0

@sabik: żądania kodują słownik jako dane formularza. – RemcoGerlich

5

Zobacz ten wątek How to send JSON as part of multipart POST-request

Nie ustawić nagłówek Content-type sam, zostawiam to pyrequests wygenerować

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. "Brak" mnie uratował !!! – EvgenyKolyakov

+0

Powiedzmy, że Flask jest odbiornik jaki byłby sposób kodowania kolby do tego? – MouIdri

+0

@Mouldri wypróbuj 'response.data' –

0

Co więcej:

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

To zadziała tylko wtedy, gdy twój plik znajduje się w tym samym katalogu, w którym znajduje się twój plik t jest.

Jeśli chcesz dołączyć plik z innego katalogu należy zrobić:

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

Gdzie dir_path jest katalogiem z „file_name.pdf” pliku.

Ale co zrobić, jeśli chcesz wysyłać wiele plików PDF?

Możesz po prostu stworzyć niestandardową funkcję, która zwróci listę potrzebnych plików (w twoim przypadku mogą to być tylko te z rozszerzeniem .pdf).Która obejmuje również pliki w podkatalogach (wyszukać pliki rekursywnie):

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')]) 

Następnie można nazwać:

my_data = prepare_pdfs() 

A z prostej pętli:

for file in my_data: 

    pdf = open(file, 'rb') 

    files = { 
     'document': pdf 
    } 

    r = requests.post(url, files=files, ...) 
Powiązane problemy