Разные результаты при выполнении синтаксического анализа useragent

#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())))"
  

Для этого не требуется никакого дополнительного импорта.