См. ниже. Учитывая хорошо известный URL Google, я пытаюсь извлечь данные из этого URL. Эти данные предоставят мне еще один URL-адрес Google, с которого я смогу получить список JWK.

>>> import requests, json
>>> open_id_config_url = 'https://ggp.sandbox.google.com/.well-known/openid-configuration'
>>> response = requests.get(open_id_config_url)
>>> r.status_code
200

>>> response.text
u'{\n "issuer": "https://www.stadia.com",\n "jwks_uri": "https://www.googleapis.com/service_accounts/v1/jwk/stadia-jwt@system.gserviceaccount.com",\n "claims_supported": [\n  "iss",\n  "aud",\n  "sub",\n  "iat",\n  "exp",\n  "s_env",\n  "s_app_id",\n  "s_gamer_tag",\n  "s_purchase_country",\n  "s_current_country",\n  "s_session_id",\n  "s_instance_ip",\n  "s_restrict_text_chat",\n  "s_restrict_voice_chat",\n  "s_restrict_multiplayer",\n  "s_restrict_stream_connect",\n ],\n "id_token_signing_alg_values_supported": [\n  "RS256"\n ],\n}'

Выше я успешно извлек данные из первого URL. Я вижу, что запись jwks_uri содержит второй URL-адрес, который мне нужен. Но когда я пытаюсь преобразовать этот фрагмент текста в словарь Python, он терпит неудачу.

>>> response.json()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/saqib.ali/saqib-env-99/lib/python2.7/site-packages/requests/models.py", line 889, in json
    self.content.decode(encoding), **kwargs
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 382, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

>>> json.loads(response.text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 382, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Единственный способ, которым я могу получить URL JWK, - выполнить этот ужасный анализ регулярного выражения:

>>> re.compile('(?<="jwks_uri": ")[^"]+').findall(response.text)[0]
u'https://www.googleapis.com/service_accounts/v1/jwk/stadia-jwt@system.gserviceaccount.com'

Есть ли более чистый, более Pythonic способ извлечь эту строку? Я действительно хотел бы, чтобы Google отправил обратно строку, которая могла бы быть чисто JSON-ified.

3
Saqib Ali 30 Июн 2019 в 23:47

3 ответа

Лучший ответ

Возвращенная строка json неверна, потому что последний элемент словаря заканчивается ,, который json не может проанализировать.

": [\n  "RS256"\n ],\n}'
                  ^^^

Но ast.literal_eval может это сделать (поскольку синтаксический анализ python принимает списки / запросы, заканчивающиеся запятой). Пока у вас нет логических или null значений, это возможно и питонно

>>> ast.literal_eval(response.text)["jwks_uri"]
'https://www.googleapis.com/service_accounts/v1/jwk/stadia-jwt@system.gserviceaccount.com'
4
Jean-François Fabre 30 Июн 2019 в 20:56

Ваш JSON недопустим, потому что у него есть лишняя запятая после последнего значения в массиве claims_supported.

Я не обязательно рекомендую это, но вы можете использовать сходство синтаксиса JSON и Python для непосредственного анализа этого, поскольку Python гораздо менее требователен:

ast.literal_eval(response.tezt)
2
Daniel Roseman 30 Июн 2019 в 20:57

Как указано в этом ответе, используйте {{ X0}} для разбора json. Он будет допускать запятую, а также другие отклонения от стандарта json.

import yaml

d = yaml.load(response.text)
1
Markus Rother 30 Июн 2019 в 22:26