Отправка данных json с помощью grequests?

Мне нужно делать асинхронные POST-запросы с помощью grequests.

Тело моего сообщения (в json) таково:

[{'params': {'source': 'widget',
   'id': 'http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif',
   'groupId': '@self',
   'nolog': 'true',
   'userId': '@viewer'},
  'method': 'pos.plusones.get',
  'id': 'p',
  'jsonrpc': '2.0',
  'apiVersion': 'v1',
  'key': 'p'}]

Мне нужно изменить значение ключа [0]['params']['id'] на разные URL-адреса для многих POST-запросов, которые я сделаю.

Итак, я делаю:

myrequests = (grequests.post(POST_URL, data=fgp(a_url) for a_url in all_urls)

Метод fgp() в понимании моего генератора — это метод, который изменяет [0]['params']['id'] на a_url, переданный ему, в теле сообщения POST, которое я отправляю.

И когда я сопоставляю запросы с ответами:

myresponses = grequests.map(myrequests)

Это то, что я получаю столько раз, сколько запросов (очевидно).

Traceback (most recent call last):
  File "/home/ashk/.virtualenvs/cosignp3/src/gevent/gevent/greenlet.py", line 340, in run
    result = self._run(*self.args, **self.kwargs)
  File "/home/ashk/.virtualenvs/cosignp3/lib/python3.4/site-packages/grequests.py", line 71, in send
    self.url, **merged_kwargs)
  File "/home/ashk/.virtualenvs/cosignp3/lib/python3.4/site-packages/requests/sessions.py", line 451, in request
    prep = self.prepare_request(req)
  File "/home/ashk/.virtualenvs/cosignp3/lib/python3.4/site-packages/requests/sessions.py", line 382, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/home/ashk/.virtualenvs/cosignp3/lib/python3.4/site-packages/requests/models.py", line 307, in prepare
    self.prepare_body(data, files, json)
  File "/home/ashk/.virtualenvs/cosignp3/lib/python3.4/site-packages/requests/models.py", line 456, in prepare_body
    body = self._encode_params(data)
  File "/home/ashk/.virtualenvs/cosignp3/lib/python3.4/site-packages/requests/models.py", line 89, in _encode_params
    for k, vs in to_key_val_list(data):
ValueError: too many values to unpack (expected 2)
<Greenlet at 0x7f0f7cbf33d8: <bound method AsyncRequest.send of <grequests.AsyncRequest object at 0x7f0f7c90d080>>(stream=False)> failed with ValueError

EDIT: Проблема решена :-

Я поиграл и вставил заголовки так же, как вы сделали бы это в модуле requests.

Я устанавливаю аргумент kwarg заголовков, чтобы сделать кодировку никакой, а тип содержимого:

(grequests.post(POST_URL, data=fgp(a_url, j=True), headers={'Accept-Encoding':'none', 'Content-Type':'application/json'}) for a_url in urls)

И теперь я получаю вывод правильно:

In [64]: resps[0].json()
Out[64]: 
{'result': {'isSetByViewer': False,
  'kind': 'pos#plusones',
  'metadata': {'type': 'URL', 'globalCounts': {'count': 0.0 }},
  'id': 'http://example.com/dfg',
  'abtk': 'xxxxxxxxxxxxxxx'},
 'id': 'p'}

Примечание. Вывод немного изменен, чтобы скрыть некоторые данные.


person bad_keypoints    schedule 23.04.2015    source источник
comment
Итак, где вы кодируете данные в JSON?   -  person Martijn Pieters    schedule 23.04.2015
comment
@MartijnPieters О да. Спасибо. Это проблема. Но теперь моя проблема в том, что я получаю тело ответа из байтов, например 07\x04\xc3pO\x01\x00\x00'`. Как я могу установить для заголовка Content-Type значение «application/json», чтобы получить правильный ответ?   -  person bad_keypoints    schedule 23.04.2015
comment
Похоже, сервер дает вам плохой ответ; сжатый, но без заголовков, чтобы сказать вам об этом. Вы можете установить дополнительный заголовок Accept-Encoding в сеансе.   -  person Martijn Pieters    schedule 23.04.2015


Ответы (2)


Вам не хватает закрывающей скобки в той строке grequests.post, которую вы показали. Однако, если предположить, что он действительно находится в конце строки:

myrequests = (grequests.post(POST_URL, data=fgp(a_url) for a_url in all_urls))

это означает, что вы создаете только один вызов post, но с несколькими значениями для data. Я думаю, что вместо этого вы имеете в виду:

myrequests = (grequests.post(POST_URL, data=fgp(a_url)) for a_url in all_urls)
person Daniel Roseman    schedule 23.04.2015

Вы пытаетесь отправить данные JSON; попросите requests закодировать это для вас (и установить правильный тип содержимого), используя аргумент json вместо data:

myrequests = (grequests.post(POST_URL, json=fgp(a_url)) for a_url in all_urls)
person Martijn Pieters    schedule 23.04.2015
comment
Неа. Получение этого: b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00}\x8c1\x0e\xc3 \x14C\xafRy\xce\xc0\x90\x89\x1bt\xeb\x1eep\xcbW\x84\x04\xf9\xca\x87fA\xdc\xbdD\xd9;\xda\xcf\xcf\rb\xa6\x06\xdf\xf0\xd1 \xf0\xb3s\x13\xb2\x94\xc2m$<\xf7\x93)\x86\x87\xc9\xf1\x95R1!\xb0\x12~i\x08\x9a\x19\xf7\xb1\xd9\x92\xbe\x99\x062a\xd1\xab\x89\xb7\xf5\xa21K\x15\xc3\xbf\xcb\xbe\xf6\xfe\x03X\x97\xb8\xf1\x87\x00\x00\x00' - person bad_keypoints; 23.04.2015
comment
Я проверил ответ requests.headers и вижу это: 'Accept-Encoding': 'gzip, deflate'. Я не просил об этом. Знаете, как я могу это изменить? Я собираюсь попробовать пару вещей в вызове метода grequests.post. - person bad_keypoints; 23.04.2015
comment
@bad_keypoints: это похоже на сжатые данные; использует ли сервер заголовки Accept*, которые говорят клиентам отправлять тела в сжатом виде? - person Martijn Pieters; 23.04.2015
comment
@bad_keypoints: или это ответ, который вы получаете от сервера? Я немного смущен, откуда берутся эти данные. - person Martijn Pieters; 23.04.2015
comment
Двоичная шестнадцатеричная строка — это данные. - person bad_keypoints; 23.04.2015
comment
Так есть ли в запросе заголовок Content-Encoding? - person Martijn Pieters; 23.04.2015
comment
@bad_keypoints: не то чтобы я действительно мог распаковать эти байты со стандартными параметрами. - person Martijn Pieters; 23.04.2015
comment
Давайте продолжим обсуждение в чате. - person bad_keypoints; 23.04.2015