1. Тема та контекст
- Тема: Доповідь присвячена вебскрапінгу з використанням підходу на основі DSL (Domain Specific Language) та нечіткого порівняння дерев для надійного отримання даних зі складних і динамічних веб-сторінок.
- Формат: Презентація на конференції fwdays.
- Спікер: Дмитро.
2. Ключові тези
- Традиційний вебскрапінг через
querySelector, зав'язаний на класи чи ID, крихкий, бо структура DOM часто змінюється (наприклад, через умовний рендеринг у React). - Як альтернативу можна використовувати DSL (предметно-орієнтовану мову) для опису шаблону даних, які потрібно витягти, не прив'язуючись жорстко до структури.
- Основна задача — реалізувати алгоритм нечіткого порівняння двох дерев (шаблону та реального DOM), який знайде відповідність навіть при відмінностях у вкладеності, наявності зайвих елементів тощо.
- Наївна реалізація такого алгоритму має експоненційну складність і непридатна на практиці, тому потрібні серйозні оптимізації (кешування, обмеження пошуку, евристики).
- Готова бібліотека
harvesterреалізує цей підход і дозволяє ефективно скрапити дані зі складних сайтів (наприклад, Rozetka, Amazon).
3. Технічні деталі
- Бібліотека:
harvester(NPM-пакет). - DSL-синтаксис: Текстовий шаблон, де:
- Вкладеності позначаються двома пробілами.
*— будь-який тег.{propertyName:type}— витягнути текст вказаного типу (string,float,int) у властивістьpropertyName.[attributeName]— витягнути значення атрибута.- Підтримуються кастомні функції для валідації.
- Алгоритм порівняння:
- Шаблон і DOM перетворюються на деревоподібні структури (JSON).
- Алгоритм шукає не точний, а найбільш схожий збіг, перебираючи можливі відповідності між вузлами.
- Кожен потенційний збіг отримує score (бал схожості), що розраховується за таблицею ваг (знайден тег, текст, атрибут тощо).
- Обирається варіант з найвищим
score.
- Оптимізації продуктивності:
- Кешування: Результатів отримання імені тега (
tagName) та батьківського елемента (parent) для DOM-вузлів. - Обмеження пошуку: Заборона алгоритму йти надто вгору або надто глибоко в дереві DOM.
- Score threshold (поріг): Припинення пошуку в гілці, якщо знайдено інший варіант з вищим балом.
- Зважування глибини: Використання чисел Фібоначчі для зменшення ваги (
score) елементів, знайдених на великій глибині.
- Кешування: Результатів отримання імені тега (
- Інтеграція: Бібліотека працює у браузері та інтегрується з Playwright та Puppeteer для автоматизації.
- API: Три основні функції:
harvest(основний алгоритм),harvestPage,harvestPageAll(аналогиquerySelectorтаquerySelectorAll).
4. Практичні поради
- Використовуйте підхід з DSL-шаблонами, коли структура цільової сторінки нестабільна або не має зручних CSS-селекторів.
- Для скрапінга сайтів, які блокують автоматизовані засоби (наприклад, Rozetka), використовуйте режими емуляції "справжнього" браузера в Playwright/Puppeteer (наприклад,
playwright-real-browser), щоб обійти захист. - Бібліотека
harvesterдозволяє створювати скрипти для отримання структурованих даних (у форматі JSON) з новинних сайтів, каталогів товарів тощо, мінімізуючи вплив змін у верстці.
5. Дискусійні моменти
- Ефективність AI-асистентів: Спікер відзначив, що AI-інструменти (на кшталт Cursor, ChatGPT, GitHub Copilot) погано справлялися з написанням та оптимізацією такого специфічного алгоритму порівняння дерев, часто пропонуючи лише наївний brute-force підхід.
- Боротьба з анти-скрапінгом: Під час доповіді виникло питання про те, як боротися з блокуванням скрапінгу деякими сайтами. Рішення — емулювати поведінку людини за допомогою спеціальних плагінів/режимів для браузерів.
- "Чому
var?": У залі поцікавилися, чому в демонстраційному коді спікер використовувавvarзамістьconst/let. Відповідь була прагматичною: у консолі браузераvarдозволяє перевизначати змінні без перезавантаження сторінки, що зручно для швидкого тестування.