Что такое browsermob-proxy и как заставить его работать? Туториал для начинающих. Пример использования на Python

Вводная

Некоторое время назад я написал небольшую статью о browsermob-proxy http://poliarush.com/working/development/chromedriver-python-browsermob-proxy.html для использования на http://lessons2.ru, где попытался изложить, как использовать этот чудный инструмент для ChromeWebdriver. Но так сложилось, что до сих пор многие задают вопросы на частных консультациях, как же все таки с ним работать и не знают как запустить прокси и получить данные.

И все же, что такое browsermob-proxy? Это отдельный инструмент\библиотека, которая запускает прокси сервер и собирает данные, которые прошли через этот прокси сервер для последующей обработки в формате json. Формат данных еще называется HAR - HTTP Archive Specification. Вы уже его могли видеть, когда открывали developers tools в chrome.

Что будем использовать? Инсталляция

Для работы нам потребуются browsermob-proxy-py инсталируем его через pip

pip install browsermob-proxy

и сама библиотека browsermob-proxy, которая все будет выполнять.

  1. Скачиваем browsermob-proxy http://bmp.lightbody.net/
  2. Копируем в какую-то папку на жестком диске, например c:\Program Files (x86)\browsermob-proxy\

Для того чтобы формировать запросы на сервер мы будем использовать python библиотеку requests Requests: HTTP for Humans™ — Requests 2.30.0 documentation в силу ее простоты.

А дальше простой кодинг и ничего лишнего.

Наша задача

  1. Запустить прокси сервер
  2. Настроить браузер на использование прокси сервера
  3. Выполнить загрузку http://google.com в браузере
  4. Считать данные с прокси сервера

Основы

Для того, чтобы понять как работает browsermob-proxy нам нужен браузер и интерпретатор python.

1. Запустить прокси сервер

Открываем интерпретатор python и пишем следующие строки:

from browsermobproxy import Server
server = Server(r"c:\Program Files (x86)\browsermob-proxy\bin\browsermob-proxy")
server.start()

Ну вот и все :smile:

Вот еще альтернативный вариант, если вам сам сервер нужно запустить на другом порту

from browsermobproxy import Server
server = Server(r"c:\Program Files (x86)\browsermob-proxy\bin\browsermob-proxy", , {"port":9090})
server.start()

Но это порт для веб-сервера, а не для прокси сервера. Об этом более детально в шаге 2.

Как убедиться, что сервер нормально работает? Если при старте у вас не было ошибки, то все хорошо. Можно также запустить netstat -a и прослушать какие порты заняты

2. Настроить браузер на использование прокси сервера

В первом шаге мы узнали, что есть какой-то порт прокси сервера, на который нужно настроить браузер. Как его узнать? Только через прогон программного кода. Запускаем дальше команды в интерпретаторе:

import requests
resp = requests.post('http://localhost:8080/proxy', {})
resp
resp.content

Мы должны получить

In [95]: resp
Out[95]: <Response [200]>

In [96]: resp.content
Out[96]: '{"port":9097}'

Вот это и есть наш порт, т.е. фактически мы его получаем при первом POST запросе на веб-сервер. Ну а теперь нам надо просто вычленить номер порта и сохранить

port = resp.json()['port']

Ну а теперь просто надо открыть какой-то браузер и настроить на работу через прокси host = localhost и port = 9097

3. Выполнить загрузку http://google.com в браузере

И так теперь у нас есть уже включенный прокси и настроенный браузер. Теперь в браузере заходим на урл http://localhost:8080/proxy/9097/har и смотрим, что идет через прокси. Но там будет просто пустая страница, потому что еще никаких действий не было. Для того, чтобы начать сессию мониторинга Вам нужно нотифицировать об этом прокси сервер. Как это сделать? Надо сделать PUT запрос на прокси сервер

resp = requests.put('http://localhost:8080/proxy/9097/har', {"initialPageRef": "google"})

Далее идем в браузер с прокси и открываем урл http://google.com.

4. Считать данные с прокси сервера

Через прокси прошли уже данные, теперь нам надо считать их. Как это можно сделать?

resp = requests.get('http://localhost:8080/proxy/9097/har')
resp.content
resp.json()

В общем, весь лог прикладывать не буду, только часть чтобы все было читабельно

In [111]: resp.content
Out[111]: '{"log":{"browser":{"name":"Firefox","version":"23.0"},"creator":{"nam
e":"BrowserMob Proxy","version":"2.0"},"pages":[{"pageTimings":{},"startedDateTi
me":"2013-10-09T21:26:49.391+0000","id":"Page 1","title":""}],"version":"1.1","e
ntries":[{"request":{"queryString":[],"cookies":[],"bodySize":0,"url":"http://oc
sp.thawte.com/","httpVersion":"HTTP","headersSize":0,"method":"POST","headers":[
]},"response":{"cookies":[],"bodySize":1425,"httpVersion":"HTTP","headersSize":0
,"statusText":"Ok","redirectURL":"","content":{"size":1425,"mimeType":"applicati
on/ocsp-response"},"headers":[],"status":200},"startedDateTime":"2013-10-09T21:2
9:56.647+0000","timings":{"blocked":1,"dns":195,"connect":336,"send":0,"wait":33
5,"receive":2},"pageref":"Page 1","serverIPAddress":"199.7.57.72","time":868,"ca

In [114]: resp.json()
Out[114]:
{u'log': {u'browser': {u'name': u'Firefox', u'version': u'23.0'},
  u'creator': {u'name': u'BrowserMob Proxy', u'version': u'2.0'},
  u'entries': [{u'cache': {},
    u'pageref': u'google',
    u'request': {u'bodySize': 0,
     u'cookies': [],
     u'headers': [],
     u'headersSize': 0,
     u'httpVersion': u'HTTP',
     u'method': u'GET',
     u'queryString': [],
     u'url': u'http://download.cdn.mozilla.net/pub/mozilla.org/firefox/releases/
24.0/update/win32/en-US/firefox-23.0.1-24.0.partial.mar'},
    u'response': {u'bodySize': 300000,

Эту же информацию мы можем посмотреть визуально через браузер, если зайдем на урл http://localhost:8080/proxy/9097/har

А дальше уже дело за Вами, точнее за вашими потребностями, ведь считать конкретные данные с словаря в Python не составляет особого труда

In [115]: resp.json()['log']['browser']['name']
Out[115]: u'Firefox'

Дополнение

Многое из того, что я показывал уже реализовано в клиенте browsermob-proxy-py. Просто берите и используйте! А зачем я тогда это все рассказывал? Чтобы Вы поняли суть, применение высокоуровневого API значительно проще, если понятна концепция.

from browsermobproxy import Server, Client
server = Server(r"c:\Program Files (x86)\browsermob-proxy\bin\browsermob-proxy")
server.start()
client = Client("localhost:8080")
client.port
client.new_har('google')
client.har

В итоге получаем вот такой вот вывод:

In [1]: from browsermobproxy import Server, Client

In [2]: server = Server(r"c:\Program Files (x86)\browsermob-proxy\bin\browsermob
-proxy")

In [3]: server.start()

In [6]: client = Client("localhost:8080")

In [7]: client.port
Out[7]: 9091

# configure browser with proxy server settings here

In [8]: client.new_har('google')
Out[8]: (204, None)

# open http://google.com here

In [9]: client.har
Out[9]:
{u'log': {u'browser': {u'name': u'Firefox', u'version': u'23.0'},
  u'creator': {u'name': u'BrowserMob Proxy', u'version': u'2.0'},
  u'entries': [{u'cache': {},
    u'pageref': u'google',
    u'request': {u'bodySize': 0,
     u'cookies': [],
     u'headers': [],
     u'headersSize': 0,
     u'httpVersion': u'HTTP',
     u'method': u'GET',
     u'queryString': [],
     u'url': u'http://www.google.com/'},
    u'response': {u'bodySize': 258,
     u'content': {u'mimeType': u'text/html; charset=UTF-8', u'size': 258},
     u'cookies': [],
     u'headers': [],
     u'headersSize': 0,
     u'httpVersion': u'HTTP',
     u'redirectURL': u'',
     u'status': 302,
     u'statusText': u'Found'},
    u'serverIPAddress': u'74.125.143.105',
    u'startedDateTime': u'2013-10-09T22:34:45.022+0000',
    u'time': 297,
    u'timings': {u'blocked': 9,
     u'connect': 78,
     u'dns': 93,
     u'receive': 29,
     u'send': 0,
     u'wait': 97}},
   {u'cache': {},
    u'pageref': u'google',
    u'request': {u'bodySize': 0,
     u'cookies': [],
     u'headers': [],
     u'headersSize': 0,
     u'httpVersion': u'HTTP',
     u'method': u'GET',
     u'queryString': [{u'name': u'gws_rd', u'value': u'cr'},
      {u'name': u'ei', u'value': u'BdpVUvK9Cc_KswamroG4Dw'}],
     u'url': u'http://www.google.se/?gws_rd=cr&ei=BdpVUvK9Cc_KswamroG4Dw'},
    u'response': {u'bodySize': 259,
     u'content': {u'mimeType': u'text/html; charset=UTF-8', u'size': 259},
     u'cookies': [],
     u'headers': [],
     u'headersSize': 0,
     u'httpVersion': u'HTTP',
     u'redirectURL': u'',
     u'status': 302,
     u'statusText': u'Found'},
    u'serverIPAddress': u'74.125.143.94',
    u'startedDateTime': u'2013-10-09T22:34:45.325+0000',
    u'time': 226,
    u'timings': {u'blocked': 0,
     u'connect': 70,
     u'dns': 60,
     u'receive': 0,
     u'send': 0,
     u'wait': 96}}],
  u'pages': [{u'id': u'google',
    u'pageTimings': {},
    u'startedDateTime': u'2013-10-09T22:34:22.758+0000',
    u'title': u''}],
  u'version': u'1.1'}}

Вывод

Не нужно делать вывод, что browsermob-proxy какой-то замороченный тул с которым не понятно как работать. Как видно из приведенного примера, все просто и очень наглядно, и Вы можете смело его использовать, как для автоматизации тестирования, так и для ручного тестирования, где прослеживаете все запросы через прокси. В общем, решать как всегда Вам.

Это был Поляруш Михаил, хорошей Вам автоматизации! И я очень жду, что
Вы поддержите меня и начнете писать подобные заметки в базу знаний. Удачи и подписывайтесь на RSS канал базы знаний ! А кто хочет обучиться автоматизации заходите на http://lessons2.ru

7 лайков

Добрый день, Михаил!
Подскажите как настроить перехват ответов при использовании Se Grid. Локально работает все отлично, ответы перехватываются, но вот на гриде с удаленным нодом BMP работает, но вот ответы не отливливает.
Заранее спасибо

p.s.Если можно, то примеры лучше сразу на джаве, пжлс)

Browsermob proxy c selenium grid не настраивал, могу предположить, что там конечно будут некоторые проблемы.

В общем, должно выглядеть так:

  1. Запускаем Browsermob proxy
  2. Узнаем хост и порт запущенного Browsermob proxy
  3. Устанавливаем прокси для RemoteWebDriver
  4. Запускаем RemoteWebDriver

Но это надо пробовать и смотреть на практике.
Если немного погуглить, то видно что у многих такие вопросы возникают http://robert.arles.us/category/browsermob/
И много этот вопрос уже обсуждался на google groups Redirecting to Google Groups (тут даже где-то видел ваш аватар :smile: ) и Redirecting to Google Groups

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

Да, обсуждей много в интернете, но решений никто так и не нашел пока, к сожалению
Спасибо за ответ

Я не нахожу возможности установить прокси для нодов, только для хаба получается, но этого не надо.
Может у кого идеи есть как это решить?

Михаил, огромное спасибо за замечательную статью! Побольше бы таких!
Очень приятно видеть работу фичи на примере, а не посылание в гугл/стак оверфлоу

Идеи для того, чтобы попробовать:

  • через какую-то библиотеку заходить на удаленный сервер и поднимать там прокси сервер
  • сделать xml-rpc сервера на нодах, которые будут постоянно висет и поднимать\останавливать прокси и возвращать нужную информацию
  • запускать отдельный степ в jenkins на конкретном ноде при запуске билд плана

Вот некий Robert Arles поделился своими соображениями по поводу JENKINS + JENKINS SLAVE NODES + SELENIUM 2 + BROWSERMOB PROXY http://robert.arles.us/category/browsermob/

Solution. Set the tests needing a proxy to run on localhost (wait, wait… I’m not crazy) Create a Jenkins slave-node, I chose a JNLP slave on a Windows PC, with a selenium server running locally (see where I’m going with “localhost”, yet?) Setup the job in Jenkins to be restricted to that node. Now, for the proxy part. Write the test code to start and use a Browsermob proxy as a Java instance, not using the ‘java -jar filename’ option at the command line. This is a nice way to go because a Java proxy instance is FAR cleaner to work with than writing to and reading from the REST interface you have to use otherwise. A nice side effect for us using this setup with a Jenkins slave-node is that other tests in the test suite will still be distributed through our Selenium Grid Hub. This means we can still migrate to a slave-node model at any time, but only if and when we decide to do so.

Now when the tests are launched, they should run on the Jenkins slave-node, and that means the Java test code will run on the same server as the tests themselves (remember the crazy part where I said the tests should be set to run on localhost? They are local to the slave-node, now) Viola, the test code and proxy, and the Selenium browser session are running on the same machine, so can both contact the proxy using “localhost” as the server address.

Спасибо, надеюсь во благо и пользу таких статей. Вот еще бы и другие автоматизаторы, кроме меня, делились такой информацией, тогда бы вообще было бы супер.

Я, например, стесняюс выкладывать свой “кодец” :smile: Но после рефакторинга собираюсь опубликовать свой вариант BDD на Python+Behave

Да ладно, чего там стесняться, зато можно узнать что сделал не так или можно сделать по другому. А это много стоит, хотя конечно можно и самому натыкаться на свои проблемы.

Даже у продвинутого автоматизатора не удалось по этому описанию настроить BMP чтоб работал с гридом (читала в BMP саппорт чате), так что у меня и подавно не получится, даже примерно по этому описанию не знаю что тыкать…
Вобщем, есть хорошая штука BMP, да смысла в ней мало, т.к. не пользоваться гридом - это странно :slight_smile:

Т.е. “опытный автоматизатор” пытался делать по инструкции указной выше?
Ну, как будет свободное время, возьмусь за эту задачу.
Если что получиться, отпишусь.

А так все свои мысли по этому поводу уже высказал, больше нечего добавить, увы :frowning:

Спасибо! Буду ждать решения, но может в какой-то очередной заход что-то и получится до этого у самой)

Рассказал об этом тут

Я могу предположить, что с нода (где запускается браузер) просто напросто не виден прокси по тому адресу, который был передан в capabilities. Как это проверить и как исправить, если причина действительно в этом.

Давайте рассмотрим пример. Моя локальная машина имеет адрес 192.168.0.100, на ней запускаются тесты. На второй машине, которая имеет адрес 192.168.0.102, работает нод (где находится хаб в данном случае неважно).

Теперь я запускаю BrowserMobProxy и проверяю, какой адрес он мне отдаст, чтобы передать его в capabilities:

int port = 8071;
ProxyServer bmp = new ProxyServer(port);
bmp.start();
Proxy proxy = bmp.seleniumProxy();
System.out.println(proxy.getHttpProxy());

На консоль выводится
alexei-pc:8071
Это имя моей машины, оно прописано локально, а не на DNS-сервере, поэтому другие машины (в том числе та, где находится нод) по этому имени найти прокси не смогут. Это можно легко проверить – запустить на второй машине консоль и попробовать попинговать по адресу alexei-pc – выдаётся сообщение “unknown host”. Вот и причина, почему прокси недоступен.

Чтобы исправить это, достаточно вручную указать правильные настройки прокси, например, по IP-адресу:

String ipAddress = new NetworkUtils().getIp4NonLoopbackAddressOfThisMachine().getHostAddress();
int port = 8071;
ProxyServer bmp = new ProxyServer(port);
bmp.start();
Proxy proxy = new Proxy();
proxy.setHttpProxy(ipAddress + ":" + port);
DesiredCapabilities caps = DesiredCapabilities.firefox();
caps.setCapability(CapabilityType.PROXY, proxy);
WebDriver driver = new RemoteWebDriver(new URL("http://192.168.0.102:4444/wd/hub"), caps);

И вот в таком варианте всё отлично работает.

Установил browsermobproxy через pip без ошибок, но все поломалось когда попытался импортировать его:

from browsermobproxy import Server

Получаю ошибку

    File "C:\Python34\lib\site-packages\browsermobproxy\__init__.py", line 3, in <module>
    from server import Server
ImportError: No module named 'server'

В интернете много у кого такая же, но решения так и не нашел. В чем может быть проблема?

Уже и не через pip установил. Та же ошибка. Питон 3.4.1

Ребята, вся надежда на вас, уже с ума схожу от этого browsermobproxy.

Проблема решилась переходом на питон 2.7

1 лайк

Добрый день, Михаил!
Подскажите как решить проблему с browsermobproxy.exceptions.ProxyServerError: Can’t connect to Browsermob-Proxy
все перелапател не че не могу сделать
мой код

from browsermobproxy import Server, Client
server = Server("/Users/pivnichenko/www/br/bin/browsermob-proxy", {"port":9090})
server.start()
client = Client("localhost:8080")
client.port
client.new_har('google')
client.har

Заранее спасибо

Неправильный путь при инициализации сервера передаете, потому никакой сервер у вас и не запускается , потому и эксепшн такой. Попробуйте абсолютный путь к батнику, что-то типа такого:

server = Server(@"C:\Users\pivnichenko\www\br\bin\browsermob-proxy.bat", {"port":9090})

Или, может быть просто не хватало “C:” вначале урла, потому как в примере выше работает и без указания бат файла в пути. Ну хз, у меня он указан и работает, но у меня адаптор на С#, вероятны различия в реализации.

Здравствуйте! Мне нужно перехватить данные, которые отправляются в FormData в POST запросе, можно ли это сделать при помощи browsermob-proxy? Нужно как-то специально его(browsermob-proxy) настраивать, чтобы он перехватывал данные из POST запроса?
Сейчас у меня получается лишь перехватить headers, cookie, queryString и еще некоторые данные, и то cookie и headers приходят как пустой спискок ([])