#python #parsing
#python #синтаксический анализ
Вопрос:
Я использую библиотеку httpagentparser для анализа пользовательских агентов. Однако по какой-либо причине я получаю по-разному отсортированные результаты при выполнении одной и той же команды на одном и том же входе.
user_agent_e="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (httpagentparser.detect(s))"
{'browser': {'name': 'Chrome', 'version': '73.0.3683.86'}, 'bot': False, 'platform': {'name': 'Windows', 'version': '10'}, 'os': {'name': 'Windows', 'version': '10'}}
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (httpagentparser.detect(s))"
{'bot': False, 'os': {'version': '10', 'name': 'Windows'}, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}, 'platform': {'version': '10', 'name': 'Windows'}}
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (httpagentparser.detect(s))"
{'platform': {'version': '10', 'name': 'Windows'}, 'bot': False, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}, 'os': {'version': '10', 'name': 'Windows'}}
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (httpagentparser.detect(s))"
{'browser': {'name': 'Chrome', 'version': '73.0.3683.86'}, 'bot': False, 'os': {'name': 'Windows', 'version': '10'}, 'platform': {'name': 'Windows', 'version': '10'}}
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (httpagentparser.detect(s))"
{'bot': False, 'os': {'version': '10', 'name': 'Windows'}, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}, 'platform': {'version': '10', 'name': 'Windows'}}
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (httpagentparser.detect(s))"
{'platform': {'version': '10', 'name': 'Windows'}, 'os': {'version': '10', 'name': 'Windows'}, 'bot': False, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}}
Как я могу получить предсказуемый результат, используя только эту однострочную строку?
Ответ №1:
Причина в том, что словари не имеют четко определенного порядка. Вы можете использовать OrderedDict
(который имеет порядок), в отсортированном словаре, который вы получаете:
python3 -c "from collections import OrderedDict; import httpagentparser; s='$user_agent_e'; print (OrderedDict(sorted(httpagentparser.detect(s).items())))"
Или развернутый:
from collections import OrderedDict
import httpagentparser; s='$user_agent_e'
print(OrderedDict(sorted(httpagentparser.detect(s).items())))
Ответ №2:
Все это одно и то же.
>>> a={'bot': False, 'os': {'version': '10', 'name': 'Windows'}, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}, 'platform': {'version': '10', 'name': 'Windows'}}
>>> b={'platform': {'version': '10', 'name': 'Windows'}, 'bot': False, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}, 'os': {'version': '10', 'name': 'Windows'}}
>>> c={'browser': {'name': 'Chrome', 'version': '73.0.3683.86'}, 'bot': False, 'os': {'name': 'Windows', 'version': '10'}, 'platform': {'name': 'Windows', 'version': '10'}}
>>> d={'bot': False, 'os': {'version': '10', 'name': 'Windows'}, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}, 'platform': {'version': '10', 'name': 'Windows'}}
>>> e={'platform': {'version': '10', 'name': 'Windows'}, 'os': {'version': '10', 'name': 'Windows'}, 'bot': False, 'browser': {'version': '73.0.3683.86', 'name': 'Chrome'}}
>>> a==b==c==d==e
True
Это словари. Словари не отсортированы, поэтому порядок, в котором печатаются пары ключ-значение, является случайным. Тем не менее, они одинаковы.
Ответ №3:
Порядок ключей может быть разным, например, хэш-функция основана на случайном. Не уверен, как это происходит в 3.5, но я бы сказал — это причина.
Чтобы получить то, что вы хотите, я бы использовал json
с отсортированными ключами.
python3.5 -c "import httpagentparser; import json; s='$user_agent_e'; json.dumps(httpagentparser.detect(s), sort_keys=True)"
Ответ №4:
Словари не упорядочены в версиях Python3 ниже 3.6.
Вы можете использовать CPython 3.6 или выше, если хотите, чтобы все словари сохраняли порядок вставки. В противном случае вы можете преобразовать выходные данные httpagentparser в список:
python3.5 -c "import httpagentparser; s='$user_agent_e'; print (list(map(list, httpagentparser.detect(s).items())))"
Для этого не требуется никакого дополнительного импорта.