Skip to content

Comparison of html parsers in Apache.JMeter 2.13 and Apache.JMeter 3.0. Methodology, automated reproducible test, and an approach to analyzing the results.

License

Notifications You must be signed in to change notification settings

pflb/jmeter.htmlParser.3.0.vs.2.13

Repository files navigation

Описание проекта

Объект тестирования

Тестируются htmlParser-ы для Apache.JMeter 2.13 и Apache.JMeter 3.0.

Парсеры Apache.JMeter 2.13:

  • LagartoBasedHtmlParser
  • HtmlParserHTMLParser
  • JTidyHTMLParser
  • RegexpHTMLParser
  • JsoupBasedHtmlParser

Парсесы Apache.JMeter 3.0:

  • LagartoBasedHtmlParser
  • JTidyHTMLParser
  • RegexpHTMLParser
  • JsoupBasedHtmlParser

Парсеры разбирают стартовые страницы различных веб-сайтов:

  • stackoverflow.com
  • habrahabr.ru
  • yandex.ru
  • mos.ru
  • jmeter.apache.org
  • google.ru
  • linkedin.com
  • github.com

Основа тестирования

Основой для тестирования послужили изменения в Apache.JMeter 3.0, см. http://jmeter.apache.org/changes.html.

Выдержки из списка изменений:

Core improvements

Dependencies refresh

Deprecated Libraries dropped or replaced by up to date ones:

  • htmllexer, htmlparser removed
  • jdom removed

Удалён парсер htmlparser и более неиспользуемая библиотека jdom.

Protocols and Load Testing improvements

Parallel Downloads is now realistic and scales much better:
  • Parsing of CSS imported files (through @import) or embedded resources (background, images, …)

Добавлен новый парсер для CSS-файлов, будут извлекаться ссылки на другие CSS-файлы (через @import) и ссылки на ресурсы, указанные в CSS-файлах: фоновые изображения, картинки, ...

Incompatible changes

  • Since version 3.0, the parser for embedded resources (replaced since 2.10 by Lagarto based implementation) which relied on the htmlparser library (HtmlParserHTMLParser) has been dropped along with its dependencies.
  • The following jars have been removed:

Удалён парсер htmlparser и более неиспользуемые библиотеки htmllexer и jdom.

Improvements

HTTP Samplers and Test Script Recorder
  • Bug 59036 - FormCharSetFinder : Use JSoup instead of deprecated HTMLParser
  • Bug 59033 - Parallel Download : Rework Parser classes hierarchy to allow plug-in parsers for different mime types
  • Bug 59140 - Parallel Download : Add CSS Parsing to extract links from CSS files

Для поиска аттрибута accept-charset в тегах form теперь используется JSoup вместо удалённого HTMLParser [Bug 59036]. Реализован парсер CSS-файлов [Bug 59140] и этот парсер используется по умолчанию [Bug 59033].

Цели тестирования

Сравнить работу всех доступных парсеров. В частности сравнить между собой парсеры версий 2.13 и 3.0, убедиться, что загрузка встроенных ресурсов стала реалистичнее и лучше.

Стратегия тестирования

Этап 1:

  1. Выполнить загрузку стартовых страниц списка сайтов используя все 5 парсеров Apache.JMeter 2.13 и записать логи.
  2. Выполнить загрузку стартовых страниц списка сайтов используя все 4 парсера Apache.JMeter 3.0 и записать логи.
  3. Проанализировать логи работы Apache.JMeter и сравнить их между собой. Оценить, стала ли загрузка встроенных ресурсов лучше, расширился ли перечень загружаемых встроенных ресурсов.

Этап 2:

  1. Выполнить загрузку стартовых страниц списка популярных сайтов, используя Google Chrome и сервис webpagetest.org.
  2. Проанализировать отчёты из webpagetest.org и сравнить их с результатами анализа логов Apache.JMeter. Оценить, реалистичность загрузки встроенных ресурсов.

Подход к тестированию

Чтобы точно определить сколько запросов посылается во время открытия страницы сайта из Apache.JMeter все запросы логируются:

  • View Results Tree — стандратный логгер, логирование в XML-формат с логированием подзапросов, XML-лог будет использоваться для выяснения деталей запросов/ответов/ошибок;
  • CsvLogWriter — кастомный логгер https://github.com/pflb/Jmeter.Plugin.CsvLogWriter, логирование в CSV-формат с логированием подзапросов, CSV-лог будет использоваться для программного подсчёта статистики по работе различных парсеров.

Чтобы иметь возможность сгруппировать запросы по версиям Apache.JMeter, парсерам и сайтам, в лог будут записываться дополнительные переменные для каждого запроса:

  • siteKey — тестируемый сайт;
  • jmeterVersion — версия Apache.JMeter;
  • htmlParser — название html-парсера, используемого в данный момент.

Результаты

Сводка

Оценка улучшения работы парсеров для версии 3.0 по сравнению с версией 2.13

Кардинальных улучшений полноты разбора html-страниц нет, есть ухудшения.

Существенное отличие - в парсерах для Apache.JMeter 3.0 есть рекурсивная загрузка страницы промо-материалов браузера Яндекс Браузер. Это проявляется при загрузке https://yandex.ru/.

Сайты с малым количеством контента — хороший результат

На простых сайтах, таких как jmeter.apache.org, все парсеры работают одинаково. Создавая то же количество подзапросов, которое создаётся браузером. Качество работы парсеров для jmeter.apache.org — идеально, 100%.

Сайты с большим количеством контента — плохой результат

Но на таком сайте как mos.ru, парсеры найдут в среднем 22 ссылки на встроенные ресурсы, тогда как полная загрузка страницы с загрузкой всех встроенных ресурсов браузером — 144 запроса. Качество низкое.

Аналогично на сайте habrahabr.ru, парсер Lagardo из Apache.JMeter 3.0 найдёт 55 ссылок, тогда как браузер сделает 117 подзапросов. Качество — 47,01%. Удовлетворительное качество полноты извлечения ссылок на встроенные ресурсы.

Количество запросов при использовании различных парсеров

Таблица на Google Docs: JMeter.HtmlParser.Compare (верхняя таблица).

Сайт Apache.JMeter Chrome, webpagetest.org, подзапросы Качество
Версия Парсер 1 2 3 4 5 Avg Document Complete Fully Loaded
github.com 2.13 HtmlParser 12 12 12 12 12 12 17 20 60,00%
JTidy 12 12 12 12 12 12 60,00%
Jsoup 12 12 12 12 12 12 60,00%
Lagarto 12 12 12 12 12 12 60,00%
Regexp 12 12 12 12 12 12 60,00%
3.0 JTidy 12 12 12 12 12 12 60,00%
Jsoup 12 12 12 12 12 12 60,00%
Lagarto 12 12 12 12 12 12 60,00%
Regexp 12 12 12 12 12 12 60,00%
google.ru 2.13 HtmlParser 4 4 4 4 4 4 9 12 33,33%
JTidy 3 4 4 4 4 3,8 31,67%
Jsoup 4 4 4 4 4 4 33,33%
Lagarto 4 4 4 4 4 4 33,33%
Regexp 2 2 2 2 2 2 16,67%
3.0 JTidy 4 4 4 4 4 4 33,33%
Jsoup 4 4 4 4 4 4 33,33%
Lagarto 3 4 4 4 4 3,8 31,67%
Regexp 2 2 2 2 2 2 16,67%
habrahabr.ru 2.13 HtmlParser 64 64 64 64 64 64 112 117 54,70%
JTidy 64 64 64 64 64 64 54,70%
Jsoup 64 64 64 64 64 64 54,70%
Lagarto 61 61 61 61 61 61 52,14%
Regexp 65 65 65 65 65 65 55,56%
3.0 JTidy 58 58 58 58 58 58 49,57%
Jsoup 58 58 58 58 58 58 49,57%
Lagarto 55 55 55 55 55 55 47,01%
Regexp 59 59 59 59 59 59 50,43%
jmeter.apache.org 2.13 HtmlParser 9 9 9 9 9 9 9 10 90,00%
JTidy 9 9 9 9 9 9 90,00%
Jsoup 9 9 9 9 9 9 90,00%
Lagarto 9 9 9 9 9 9 90,00%
Regexp 9 9 9 9 9 9 90,00%
3.0 JTidy 10 10 10 10 10 10 100,00%
Jsoup 10 10 10 10 10 10 100,00%
Lagarto 10 10 10 10 10 10 100,00%
Regexp 10 10 10 10 10 10 100,00%
linkedin.com 2.13 HtmlParser 10 10 10 10 10 10 19 21 47,62%
JTidy 10 10 10 10 10 10 47,62%
Jsoup 10 10 10 10 10 10 47,62%
Lagarto 10 10 10 10 10 10 47,62%
Regexp 6 10 6 6 10 7,6 36,19%
3.0 JTidy 10 10 10 10 10 10 47,62%
Jsoup 10 10 10 10 10 10 47,62%
Lagarto 10 10 10 10 10 10 47,62%
Regexp 10 10 6 6 6 7,6 36,19%
mos.ru 2.13 HtmlParser 24 24 24 24 24 24 119 144 16,67%
JTidy 24 24 24 24 24 24 16,67%
Jsoup 24 24 24 24 24 24 16,67%
Lagarto 13 13 13 13 13 13 9,03%
Regexp 24 24 0 24 24 19,2 13,33%
3.0 JTidy 25 25 25 25 25 25 17,36%
Jsoup 25 25 25 25 25 25 17,36%
Lagarto 14 14 14 14 14 14 9,72%
Regexp 25 25 25 25 25 25 17,36%
stackoverflow.com 2.13 HtmlParser 17 17 17 17 17 17 41 42 40,48%
JTidy 17 17 17 17 17 17 40,48%
Jsoup 16 16 16 16 16 16 38,10%
Lagarto 16 16 16 16 16 16 38,10%
Regexp 17 16 16 16 16 16 16,2%
3.0 JTidy 16 16 16 16 16 16 38,10%
Jsoup 16 16 16 16 16 16 38,10%
Lagarto 15 15 15 15 15 15 35,71%
Regexp 16 16 16 16 16 16 38,10%
yandex.ru 2.13 HtmlParser 70 68 72 67 69 69,2 33 35 197,71%
JTidy 18 18 19 18 18 18,2 52,00%
Jsoup 18 18 18 18 18 18 51,43%
Lagarto 14 14 14 14 14 14 40,00%
Regexp 18 18 18 18 19 18,2 52,00%
3.0 JTidy 647 645 619 644 578 626,6 1790,29%
Jsoup 579 640 638 644 620 624,2 1783,43%
Lagarto 48 451 441 450 450 368 1051,43%
Regexp 642 644 337 642 644 581,8 1662,29%

JMeter.HtmlParser.Compare JMeter.HtmlParser.Compare JMeter.HtmlParser.Compare

Описание столбцов:

  • Before Start Render — количество запросов, сделанных браузером, до момента начала отображения содержимого страницы. Это html-разметка, основные js и css-файлы, основные изображения.
  • Document Complete — количество запросов, сделанных браузером, на момент полной загрузки документа. Тут уже загрузились все ресурсы страницы.
  • Fully Loaded — количество запросов, сделанных браузером, на момент когда отработал javascript, когда загрузилось всё.

Хорошим результатом работы парсеров будет, если запросов будет столько же, сколько браузер Google Chrome делает на момент Document Complete, а отличным — на момент Fully Loaded. Мерилом реалистичности работы Apache.JMeter при использовании конкретного парсера будем считать близость количества запросов к количеству запросов, выполняемых браузером на момент Fully Loaded.

Если исключить результаты тестирования сайта yandex.ru, где:

  • парсинг уходит в рекурсию делая снова и снова запросы к yandex.ru пока глубина рекурсии не достигает максимального уровня и завершается ошибкой:

java.lang.Exception: Maximum frame/iframe nesting depth exceeded.

и за мерило качества работы парсеров принять количество запросов на момент Fully Loaded, то получим такую таблицу среднего качества работы парсеров.

Среднее качество работы парсеров

Таблица на Google Docs: JMeter.HtmlParser.Compare (нижняя таблица).

Среднее качество работы парсеров

Самый точный парсер HTMLParser в Apache.JMeter 2.13. В Apache.JMeter 3.0 парсеры Jsoup и JTidy показали одинаковое качество. Парсер Lagarto отстаёт от лидеров. Полнота парсинга для парсера Lagarto в Apache.JMeter 3.0 снизилась по сравнению с Apache.JMeter 2.13.

Качество работы парсера Lagarto на актуальной версии Apache.JMeter 3.0 составило 32,73%, лишь треть всех подзапросов была послана, две трети нагрузки на статику не было подано.

Логи и их обработка

Исходные данные

Все логи доступны по ссылке: https://drive.google.com/drive/folders/0B5nKzHDZ1RIiVkN4dDlFWDR1ZGM.

Отчёты WebPageTest.org

sytekey webpagetest.org Raw page data (.csv) Raw object data (.csv) HTTP Archive (.har)
github.com 160819_VF_FM8 github.com.summary.csv github.com.details.csv github.com.har
google.ru 160819_C9_FQD google.ru.summary.csv google.ru.details.csv google.ru.har
habrahabr.ru 160819_8N_FRB habrahabr.ru.summary.csv habrahabr.ru.details.csv habrahabr.ru.har
jmeter.apache.org 160819_CG_FSM jmeter.apache.org.summary.csv jmeter.apache.org.details.csv jmeter.apache.org.har
linkedin.com 160819_K2_FY1 linkedin.com.summary.csv linkedin.com.details.csv linkedin.com.har
mos.ru 160819_91_G0F mos.ru.summary.csv mos.ru.details.csv mos.ru.har
stackoverflow.com 160819_S0_G18 stackoverflow.com.summary.csv stackoverflow.com.details.csv stackoverflow.com.har
yandex.ru 160819_MR_G1R yandex.ru.summary.csv yandex.ru.details.csv yandex.ru.har

github.com via webpagetest.org google.ru via webpagetest.org habrahabr.ru via webpagetest.org jmeter.apache.org via webpagetest.org linkedin.com via webpagetest.org mos.ru via webpagetest.org stackoverflow.com via webpagetest.org yandex.ru via webpagetest.org

Логи Apache.JMeter

Для обработки используются csv-логи, сформированные плагином CsvLogWriter:

В результате работы которого формируется лог, в список колонок которого входят:

  • timeStamp — момент времени;
  • URL — адрес запроса;
  • elapsed — длительность получения ответа на запрос;
  • bytes — размер ответа;
  • siteKey — используемый сайт;
  • htmlParser — название используемого ;
  • jmeterVersion — используемая версия Apache.JMeter;
  • i — номер итерации тестирования.

Аггрегация csv-логов Apache.JMeter выполняется при помощь pandas вот таким кодом на python:

import pandas as pd
import codecs
from os import listdir
import numpy as np


# Настройки - каталог с логами и настройки считывания логов.
dirPath = "D:/project/jmeter.htmlParser.3.0.vs.2.13/logs"

read_csv_param = dict( index_col=['timeStamp'],
                       low_memory=False,
                       sep = ";",
                       na_values=[' ','','null'])

# Получение списка csv-файлов в каталоге с логами.
files = filter(lambda a: '.csv' in a, listdir(dirPath))


# Чтение содержимого всех csv-файлов в DataFrame dfs.
csvfile = dirPath + "/" + files[0]
print(files[0])
dfs = pd.read_csv(csvfile,**read_csv_param)
for csvfile in files[1:]:
    print(csvfile)
    tempDfs = pd.read_csv(dirPath + "/" + csvfile, **read_csv_param)
    dfs = dfs.append(tempDfs)

#dfs.to_excel(dirPath + "/total.xlsx")

# Убрать из выборки все JSR223, по ним статистику строить не надо, оставить только HTTP Request Sampler.
# У JSR223 URL пустой, у HTTP-запросов URL указан.
dfs = dfs[(pd.isnull(dfs.URL) == False)]


# Сводная таблица по количеству подзапросов, сохраняется в report.subrequests.html - основной результат работы.
# Из количества запросов удаляется один запрос, чтобы исключить корневой запрос.
# Цель данного исследования - подсчёт количества подзапросов, поэтому корневой исключается.
pd.pivot_table(dfs, 
               index=['siteKey', "jmeterVersion", "htmlParser"], 
               values="URL", 
               columns=["i"], 
               aggfunc=lambda url: url.count()-1).to_html(dirPath + "/report.subrequest.count.html")

Рекурсивная загрузка на yandex.ru

Apache.JMeter уходит в рекурсию

Как видно:

  1. Apache.JMeter находит и переходит по ссылке https://yandex.ru/clck/redir/dtype=stred....7004fcb3793e79bb1ac9e&keyno=12
  2. Затем находит новую уникальную ссылку https://yandex.ru/clck/redir/dtype=stred....cd1c46cad58fbfe2f61&keyno=12
  3. И так уходит в рекурсию.

В данном случае это картинка внутри ссылки на загрузку Яндекс Браузера:

Apache.JMeter уходит в рекурсию

И эту картинку парсер находит. JMeter пробует её скачать, в ответ получает html-страницу, там снова ссылка на картинку и другие ссылки. Поведение Apache.JMeter корректное.

А в Apache.JMeter 2.13 либо:

  • есть ограничение на длину ссылок, и за счёт отсекания уникального окончания ссылки рекурсии не происходит;
  • или в Apache.JMeter 2.13, что-то неправильно работает в парсерах;
  • или в Apache.JMeter 2.13, что-то работает наоборот правильно - куки, ещё что-то и сам сервер Яндекса отвечает ему так, чтобы тот не уходил в рекурсию, например, отвечает картинкой на запрос картинки, а не новой html-страницей.

Гадать не буду. Кажется безвыходная ситуация. Но таких ситуаций не бывает. Всегда есть решение.

Например, можно попробовать в качестве User-Agent указать Яндекс Браузер. Тогда сервер, наверно, не покажет картинку для скачивания браузера, или на запрос картинки будет отвечать картинкой, и рекурсии не будет. Это догадка, не проверял её.

Сейчас в скрипте был указан User-Agent для Google Chrome для синхронности с работой webpagetest.org, и сервер видя не свой браузер, видимо, предлагает ссылку на свой.

Состав проекта

  • jmeter.testfile.jmx — тестовый скрипт для Apache.JMeter 2.13 и Apache.JMeter 3.0 принимающий на вход параметры:
    • URL — адрес тестируемого сайта, например, https://yandex.ru/;
    • siteKey — строка по которой будет осуществляться группировка записей в логах, например, yandex.ru;
    • loopCount — количество итераций теста, используется несколько итераций из-за того, что работа веб-сайтов может быть нестабильной;
    • htmlParser.className — парсер для извлечения ссылок на встроенные ресурсы;
    • для работы скрипта необходимо скачать и установить дополнительный плагин CsvLogWriter.
  • jmeter.3.0.bat — командный файл запуска теста для Apache.JMeter 3.0, тут задаётся путь к папке /bin/ Apache.JMeter 3.0, путь к тестовому скрипту jmeter.testfile.jmx, опции запуска теста, а также список htmlParser-ов проверка работы которых выполняется;
  • jmeter.2.13.bat — командный файл запуска теста для Apache.JMeter 2.13, тут задаётся путь к папке /bin/ Apache.JMeter 2.13, путь к тестовому скрипту jmeter.testfile.jmx, опции запуска теста, а также список htmlParser-ов проверка работы которых выполняется;
  • test.bat — командный файл запуска теста на двух версиях Apache.JMeter, 2.13 и 3.0, файл содержит количество итераций тестирования и адреса тестируемых сайтов. Файл вызывает файлы jmeter.2.13.bat и jmeter.3.0.bat;
  • jmeter.3.0.vs.jmeter.2.13.ipynb — блокнот для jupyter для анализа логов работы Apache.JMeter;
  • statistics.xlsx — таблица со статистикой по работе парсеров, результат исследования.

Выводы

Особой практической ценности в статье нет. Но некоторые полезные выводы сделать можно:

  • парсер в среднем извлекает ссылки только на треть ресурсов;
  • парсеры работают почти одинаково, а значит можно применять любой;
  • парсеры заточены под работу с простыми сайтами, такими как jmeter.apache.org;
  • на сайтах с большим количеством содержимого парсеры работают значительно хуже реального браузера;
  • полнота загрузки встроенных ресурсов в новой версии JMeter незначительно снизилась, а не возросла;
  • продемонстрировано прикладное использование плагина CsvLogWriter (см. статью Плагин CsvLogWriter для JMeter), логирующего запросы к embedded-ресурсам в csv-лог, который сделала моя коллега Александра @Sanchez92;
  • с помощью bat-файлов, передачи парамеров JMeter через командную строку, логирования переменных и обработки csv-логов с помощью pandas можно тестировать сам инструмент тестирования; методика отработана.

About

Comparison of html parsers in Apache.JMeter 2.13 and Apache.JMeter 3.0. Methodology, automated reproducible test, and an approach to analyzing the results.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published