Вибираємо html-парсер для Apache.JMeter

Середня якість повноти вилучення посилань на вбудовані ресурси html-парсерами Apache.JMeter
Середня якість роботи парсерів (для семи сайтів)

Пропоную:
  • порахувати середнє якість повноти вилучення посилань на вбудовані ресурси html-парсерами Apache.JMeter;
  • перевірити чи правда витяг посилань у Apache.JMeter 3.0 стало більш повним;
  • випробувати в справі плагін CsvLogWriter.
Як говорить народна мудрість: Вірити вір, але…


Опис проекту

Об'єкт тестування
Тестуються 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 (верхня таблиця).
Зведена таблиця порівняння роботи різних html-парсерів Apache.JMeter з результатами роботи Google Chrome
Статистика роботи Apache.JMeter в розрізі версій і html-парсерів і її порівняння з роботою Google Chrome

Опис стовпців:
  • 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 (нижня таблиця).

Середня якість роботи парсерів
Середня якість роботи парсерів (для семи сайтів, без yandex.ru)

Найточніший парсер 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
Зображення звітів







Шапки звітів webpagetest.org з яких виділялися дані Document Complete та Fully Loaded

З значень колонок Document Complete та Fully Loaded потрібно исклюить один запит (кореневої), щоб отримати кількість підзапитів.

Логи Apache.JMeter
Для обробки використовуються csv-логи, сформовані плагіном CsvLogWriter:Сторонній плагін використовується, щоб в csv-лог потрапили запити на embedded-ресурси.

В результаті роботи CsvLogWriter формується лог, в список колонок якого входять:
  • timeStamp — момент часу;
  • URL — адреса запиту;
  • elapsed — тривалість отримання відповіді на запит;
  • bytes — розмір відповіді;
  • siteKey — використовується сайт;
  • htmlParser — назва використовуваного ;
  • jmeterVersion — використовувана версія Apache.JMeter;
  • i — номер ітерації тестування.


Автоматизація обробки логів
Агрегацію csv-логів Apache.JMeter виконується за допомогою pandas ось таким кодом python:
import pandas as pd
import codecs
from import os 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=["і"], 
aggfunc=lambda url: url.count()-1).to_html(dirPath + "/report.subrequest.count.html")


Рекурсивна завантаження на yandex.ru
Apache.JMeter йде в рекурсію
Рекурсивна завантаження вбудованих ресурсів для актуальної версії Apache.JMeter 3.0 з налаштуваннями за замовчуванням (html-парсер Lagarto) на сайті yandex.ru

Як видно:
  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
Фрагмент html-коду сайту yandex.ru обробка якого додає новий крок рекурсії, посилання і картинка для скачування Яндекс Браузера

Картинку парсер знаходить. JMeter пробує її завантажити, у відповідь отримує html-сторінку, там знову посилання на картинку і інші посилання. І все повторюється. Поведінка Apache.JMeter коректне.

А в Apache.JMeter 2.13 рекурсія походить тільки на парсере HtmlParser, здогадки чому не відбувається на інших:
  • є обмеження на довжину посилань, і за рахунок відсікання унікального закінчення посилання рекурсії не відбувається;
  • 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 — таблиця зі статистикою по роботі парсерів, результат дослідження.
Тест легко змінити під себе, вказати свої сайти і потрібну кількість ітерацій. Всі настройки задаються у файлі test.bat.

CALL jmeter.2.13.bat http://stackoverflow.com/ 5 stackoverflow.com
CALL jmeter.2.13.bat https://habrahabr.ru/ 5 habrahabr.ru
CALL jmeter.2.13.bat https://yandex.ru/ 5 yandex.ru
CALL jmeter.2.13.bat https://www.mos.ru/ 5 mos.ru
CALL jmeter.2.13.bat http://jmeter.apache.org/ 5 jmeter.apache.org
CALL jmeter.2.13.bat https://www.google.ru/ 5 google.ru
CALL jmeter.2.13.bat https://www.linkedin.com/ 5 linkedin.com
CALL jmeter.2.13.bat https://github.com/ 5 github.com

CALL jmeter.3.0.bat http://stackoverflow.com/ 5 stackoverflow.com
CALL jmeter.3.0.bat https://habrahabr.ru/ 5 habrahabr.ru
CALL jmeter.3.0.bat https://yandex.ru/ 5 yandex.ru
CALL jmeter.3.0.bat https://www.mos.ru/ 5 mos.ru
CALL jmeter.3.0.bat http://jmeter.apache.org/ 5 jmeter.apache.org
CALL jmeter.3.0.bat https://www.google.ru/ 5 google.ru
CALL jmeter.3.0.bat https://www.linkedin.com/ 5 linkedin.com
CALL jmeter.3.0.bat https://github.com/ 5 github.com

Далі результати можна вставляти з Excel-файл з налаштованими формулами і одержувати наочну таблицю результатів.
Можна спробувати доопрацювати парсери, і за схожою методикою відслідковувати поліпшення якості розбору embedded-ресурсів.

Висновки
Особливої практичної цінності в статті немає. Але деякі корисні висновки зробити можна:
  • парсер в середньому отримує посилання лише на третину ресурсів;
  • парсери працюють майже однаково, а значить можна застосовувати будь -;
  • парсери заточені під роботу з простими сайтами, такими як jmeter.apache.org;
  • на сайтах з великою кількістю вмісту парсери працюють значно гірше реального браузера;
  • повнота завантаження вбудованих ресурсів у новій версії JMeter незначно знизилась, а не виросла;
  • продемонстровано прикладне використання плагіна CsvLogWriter, логирующего запити до embedded-ресурсів в csv-лог, який зробила моя колега Олександра Sanchez92;
  • за допомогою bat-файлів, передачі парамеров JMeter через командний рядок, логування змінних і обробки csv-логів з допомогою pandas можна тестувати сам інструмент тестування, див. проект на github https://github.com/pflb/jmeter.htmlParser.3.0.vs.2.13методика відпрацьована.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.