Как стать автором
Обновить

С чем едят UserAgent

Время на прочтение5 мин
Количество просмотров7.1K

msdn_ua

Для начала, конечно, стоило рассказать зачем едят этот самый «пользовательский агент». Ну или, вообще, начать с того что же это за агент такой. (Кстати, никто не знает какой-нибудь славянско-православный перевод этого термина?)Но рассчитывая, что хабра юзер либо уже знает и использует useragent либо ему это не нужно, я бы не хотел останавливаться на предисловиях. И так, мой совет — употребляйте useragent с регулярными выражениями!



Конечно, тебе свойственно регулярно употреблять выражения, %username%, но они другие и для души, а я о regex. Одной из основных задач в моей работе, является правильное определение возможностей устройства и браузера конечного пользователя. Так как основной упор мы делаем на мобильные устройства (сотовые телефоны), то их я и возьму в пример. В отличие от пользователей обычных компьютеров, пользователи мобильных устройств жёстко и жестоко ограничены в разрешении экрана, возможностях браузера и т.д. У нас имеется небольшая база данных собранная и автоматически обновляемая с помощью UAProf и Wurfl. Но заголовки агентов (useragent header) постоянно изменяются и количество различий постоянно растёт. О том чтобы делать поиск очередного устройства проверкой агента один к одному не может идти и речи, но как то же надо искать. Поэтому мы стали разбираться с устройством useragent и что из него можно выжать.

Ингредиенты


Стандарты и формат — как обычно никто их не соблюдает. Формат useragent изменяется от производителя к производителю и от серии к серии. К тому же большинство сотовых операторов любят переписывать заголовки.
Основные блоки должны быть такие:
устройство/версия браузер/версия (поддерживаемые стандарты и технологии).
msdn_ua
Первый же пример sonyericssonk530i/r6bc browser/netfront/3.3 profile/midp-2.0 configuration/cldc-1.1 как бы говорит нам, что скобки ожидать не приходится, а второй пример mozilla/5.0 (symbianos/9.4; u; series60/5.0 nokia5800d-1/21.0.025; profile/midp-2.1 configuration/cldc-1.1 ) applewebkit/413 (khtml, like gecko) safari/413 мягко намекает, что и порядок никто соблюдать не будет. Но всё же мне важно знать, что разные агенты появляются у одного и того же устройства, например nokia n95:
  • mozilla/5.0 (symbianos/9.2; u; series60/3.1 nokian95/12.0.013; profile/midp-2.0 configuration/cldc-1.1 ) applewebkit/413 (khtml, like gecko) safari/413
  • mozilla/5.0 (symbianos/9.2; u; series60/3.1 nokian95/31.0.017; profile/midp-2.0 configuration/cldc-1.1 ) applewebkit/413 (khtml, like gecko) safari/413 [en-us]
  • mozilla/5.0 (symbianos/9.2; u; series60/3.1 nokian95/30.0.015; profile/midp-2.0 configuration/cldc-1.1 )
  • mozilla/5.0 (symbianos/9.2; u; series60/3.1 nokian95_8gb/30.0.018; profile/midp-2.0 configuration/cldc-1.1 ) applewebkit/413
  • mozilla/5.0 series60; nokian95;


Рецепт


Однако, как можно заметить кое какая логика есть. После слеша (/) идёт версия — динамическая часть, которая особой роли не играет. Обязательно присутствует указание на браузер. Разделение токенов с помощью пробела и/или точки с запятой. Покрутив логи мы обнаружили много мусора в заголовках агента, поэтому первым шагом стала стандартизация и выделение сегментов. Получились вот такие полезности:
  1. Выбираем то, что действительно useragent: ([[(]?[a-z0-9._+;]\s?[/\-;:\\,*\s]*[)\]]?\s?)*
  2. Определяем токен браузера: ((iemobile|kbrowser)\s[0-9.]+)|((up(\.link)?|netfront|obigo|opera\s?(mini|mobile)?|deckit|safari|(apple)?webkit|mozilla|openwave)/[0-9\.a-z\-]+\+?)|(browser/[a-z\-0-9]+/?[0-9\.a-z\-]+)|([a-z\.-]+browser[a-z\.-]*(/[0-9\.a-z\-]+)?)
  3. Определяем профиль и конфигурацию: (((profile|configuration|java(platform)?)/[a-z]+-?)|((cldc|midp|wap)[\s\-]?))[0-9\.-a-z]+
  4. Язык: ((?<=[\s;\[\(])[a-z]{2}[\s-][a-z]{2}(?=[\s;\]\)]))|\[([a-z]{2,3}[\-_\s]?)+\]
  5. Версия: [\s;/]+(v(er)?[\s.]*)?[0-9]+\.[0-9\.]+([a-z]{1,2}[0-9\.]*)?
  6. Иногда указывают размеры экрана в пикселях: [0-9]{3}x[0-9]{3}

Естественно, что сто процентного результата не получилось, но прогонка по 30 000 useragent-ов показала, что правильные сегменты высветились в 97%. Так что результат вполне достойный. Но нам этого не хватило. Некоторые вещи надо проверять по базе данных и там всё тот же разброс и разнообразие моделей и агентов. Возникла простая и интуитивно понятная идея — поиск по модели. То есть несмотря на то, что существует более десятка разных useragent-ов для той же 95-ой Нокии, в каждом варианте присутствует nokian95. Задача была бы тривиальной, если бы нужно было определить/искать только одну и ту же модель (допустим узнать iPhone или нет). Но тогда вполне хватило бы if-else. В жизни всё сложней и никакого универсального стандарта для определения модели просто нет.

Десерт


Мы пошли от обратного — подчистим useragent от тех токенов, определять которые мы научились.
Используя те же выражения (с лёгкими изменениями) я стираю из useragent блоки один за другим (псевдокод while useragent ismatch replace match with string.empty). Получается остаток из неизвестных мне заранее кусков, часть которых является мусором, а какой то один — моделью. Простейшим решением стало разбиение остатка на отдельные токены — Split(' ', '/', ';') и поиск токена с производителем. Ищем в какая часть содержит одну из следующих строк:

"nokia", "motorola", "mot-", "moto-", "motorazr", "sonyericsson", "samsung", "sec-", "sgh-", "lg-", "lge", "lg", "sie-", "siemens","ipod", "iphone" ,"ipaq", "spv", "i-mate", "mobilephone", "htc", "vodafone", "palm", "rover", "gigabyte", "asus", "alcatel", "mitsu", "verizon", "apple".


Теперь из приведённых выше разных длинных useragent-ов n95 у меня остаются только nokian95 и nokian95_8gb соответственно. Вот ещё несколько примеров полных useragent-ов и результатов очистки:
  • samsung-sgh-f480/f480jihh2 shp/vpp/r5 netfront/3.4 qtv5.3 smm-mms/1.2.0 profile/midp-2.0 configuration/cldc-1.1
    =samsung-sgh-f480
  • sonyericssonw705/r1ea browser/netfront/3.4 profile/midp-2.1 configuration/cldc-1.1 javaplatform/jp-8.4.2
    =sonyericssonw705
  • lg-kc910q browser/teleca-q7.1 mms/lg-mms-v1.0/1.2 mediaplayer/lgplayer/1.0 java/asvm/1.1 profile/midp-2.1 configuration/cldc-1.1
    =lg-kc910q
  • mozilla/5.0 (symbianos/9.3; u; series60/3.2 nokia6210navigator/03.25; profile/midp-2.1 configuration/cldc-1.1 ) applewebkit/413 (khtml, like gecko) safari/413
    =nokia6210navigator
  • sgh-z370/1.0 netfront/3.3 profile/midp-2.0 configuration/cldc-1.1
    =sgh-z370
  • vodafone/1.0/sex1i/r2aa mozilla/4.0 (compatible; msie 6.0; windows ce; iemobile 7.11) up.link/6.3.1.20.0 profile/midp-2.0 configuration/cldc-1.1
    =vodafone sex1i


На посошок


Помимо браузера вас может интересовать токен WAP (кратко WAP 1.0 = WML, WAP 2.0 = XHTML). Версия mmp (multimedia mobile processor) должна указывать на поддержку аудио/видео кодеков — 1.0 только аудио mp3, а 2.0 поддерживает и видео 3gp. В большей части useragent-ов указанна операционная система и версия — актуально для iPhone: ip(hone|od).*?os\s*(v(er(sion)?)?)?[\s.]*([0-9._]+|[a-z]+)

Приятного аппетита


Проверка на базе данных и подгонка (finetunning) привели к 99% результату. Это конечно явный overfitting, но это была одной из целей (максимальная точность в определённой аудитории и регионе). Кстати, вышеприведённые regex-ы более абстрактны и должны дать большую погрешность в силу своей универсальности.
Теги:
Хабы:
+28
Комментарии14

Публикации

Изменить настройки темы

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн