Селектор — це адреса значення на сторінці. Коли ви налаштовуєте парсинг сайту, ви не показуєте програмі колонку з ціною, як у файловому прайсі, а пишете, в якому місці розмітки ця ціна написана. Ця стаття — довідник таких адрес: що підтримує наш розбір, як виглядає робочий селектор під кожне поле товару й чому найчастіше не знаходиться нічого.
Порядок налаштування правил, вкладки, кнопки тесту й помічники описані окремо — у статті про парсинг сайтів. Тут лише мова селекторів і приклади.
Дві мови: CSS і XPath
Селектор пишуть однією з двох мов. За замовчуванням у комірці чекають CSS-селектор — той самий, яким верстальники описують стилі. Якщо зручніше XPath, у тому самому рядку правила ставлять галочку «XPath».
1
Селектор операції2
Позначка XPath3
Поле «Ціна»- Колонка «Селектор операції» — сюди вписують адресу значення на сторінці.
- Позначка «XPath» у рядку — без неї XPath обриває розбір усієї сторінки, а не просто не знаходить значення.
- Рядок поля «Ціна» — у кожного поля свій селектор, налаштовуються вони незалежно.
Галочка не косметична. XPath, вписаний у рядок без неї, не «нічого не знаходить» — розбір цієї сторінки обривається з помилкою. У журналі при цьому буде код відповіді 200, тобто зовні все ніби добре, а даних немає. Так само обривається розбір на CSS-селекторі з синтаксичною помилкою: зайва дужка коштує цілої сторінки.
Різниця між «нічого не знайшов» і «помилка» важлива для пошуку причини. Селектор, який просто не знайшов елемента, дає порожній результат і йде далі — інші поля з тієї ж сторінки приїдуть нормально. Селектор із помилкою зупиняє всю сторінку.
Базовий набір: тег, клас, атрибут
Чотири способи вказати елемент, з яких складається майже будь-який робочий селектор:
| Запис | Що вибирає |
|---|---|
h1 | усі теги h1 на сторінці |
.price | усе з класом price |
#product-card | елемент із таким id |
span[itemprop=price] | span із таким атрибутом |
div.card > a | посилання, яке лежить безпосередньо в div.card |
div.card a | посилання будь-де всередині div.card, хоч на п'ятому рівні вкладеності |
У квадратних дужках працює не лише точна рівність. Перед знаком рівності ставлять символ, який змінює правило порівняння:
| Оператор | Умова | Приклад |
|---|---|---|
= | значення точно таке | a[rel=nofollow] |
^= | починається з | a[href^=/product/] |
$= | закінчується на | img[src$=.jpg] |
*= | містить підрядок | a[href*=catalog] |
!= | значення інше | input[type!=hidden] |
~= | містить таке слово у списку через пробіл | div[class~=in-stock] |
|= | дорівнює або починається з «значення-» | span[lang|=uk] |
Оператор *= рятує на сайтах, де класи згенеровані складачем і виглядають як price__value_a7f3: div[class*=price__value] переживе зміну хвоста, а div.price__value_a7f3 — ні.
Повний перелік псевдокласів
Псевдоклас звужує вибірку за позицією або вмістом. Наш розбір підтримує рівно цей набір — усе інше, що можна побачити в довідниках CSS, тут не спрацює:
| Псевдоклас | Що робить |
|---|---|
:first-child, :last-child | перший або останній серед сусідів |
:nth-child(n), :nth-last-child(n) | n-й за порядком, від початку або від кінця |
:first-of-type, :last-of-type, :nth-of-type(n) | те саме, але рахуються лише елементи того ж тега |
:only-child | єдина дитина в батька |
:empty, :not-empty | порожній / непорожній елемент |
:contains(текст) | містить текст |
:has(селектор) | всередині є елемент за селектором |
:not(селектор) | усе, крім того, що підходить під селектор |
:checked, :disabled, :enabled | стан елементів форми |
У :contains() є два необов'язкові уточнення. Другий аргумент вмикає й вимикає врахування регістру, третій вимагає збігу цілком, а не входження:
td:contains(Гарантія)— містить це слово, регістр важливий;td:contains(гарантія, false)— регістр не важливий;td:contains(Гарантія, true, true)— текст комірки дорівнює саме цьому слову.
:contains() дивиться на власний текст елемента, а не на текст усіх нащадків разом. Якщо в розмітці <div><span>Гарантія</span></div>, то div:contains(Гарантія) не знайде нічого, а span:contains(Гарантія) знайде. Це найчастіша причина «псевдоклас не працює».
Забрати атрибут, а не текст
За замовчуванням із знайденого елемента береться його текст. Щоб узяти значення атрибута, до селектора дописують ::attr(ім'я). Без цього половина сайтів не збирається — ціна й наявність часто лежать не в тексті, а в розмітці для пошукових систем.
| Завдання | Селектор |
|---|---|
| Посилання на товар | a.product-link::attr(href) |
| Ціна з мікророзмітки | meta[itemprop=price]::attr(content) |
| Фото з відкладеним завантаженням | img.photo::attr(data-src) |
| Фото з набору розмірів | img.photo::attr(srcset) |
| Артикул із службового атрибута | div[data-sku]::attr(data-sku) |
srcset обробляється по-різному на різних кроках. В операції «Картка товару» програма сама вибирає з набору посилання з найбільшою шириною — тобто повний розмір, а не прев'ю. У списку товарів такого відбору немає: там береться останнє посилання з набору. Якщо з лістингу приїжджають маленькі картинки, беріть інший атрибут — зазвичай поруч є data-src або src із повним розміром.
Рецепти під поля товару
Типові випадки, з яких складається більшість налаштувань. Класи в прикладах — вигадані, підставляйте свої; цінна тут форма запису.
| Що треба | Як зазвичай написано в розмітці | Селектор |
|---|---|---|
| Назва товару | єдиний h1 на сторінці | h1 |
| Назва в лістингу | текст посилання на картку | div.catalog a.name |
| Ціна | окремий блок із валютою поруч | div.price-current |
| Ціна в мікророзмітці | атрибут, тексту немає | meta[itemprop=price]::attr(content) |
| Стара ціна — щоб її НЕ взяти | лежить поруч із чинною | div.price:not(.price-old) |
| Артикул | рядок «Код: 12345» | span.sku + «Регулярний вираз» у тому ж рядку правила |
| Наявність | підпис «Є в наявності» | div.stock |
| Наявність за класом | клас змінюється, тексту немає | div[class*=in-stock] |
| Усі фото галереї | посилання на повний розмір | a[data-fancybox=gallery]::attr(href) |
| Тільки ті картки, де є картинка | у списку трапляються рядки-заглушки | div.card:has(img) a::attr(href) |
| Значення характеристики | таблиця «назва — значення» | tr:contains(Вага) td:last-child |
| Опис | блок із розміткою, яку треба зберегти | div.description + галочка «Отримувати HTML» |
| Посилання на другу сторінку розділу | нумерація внизу | ul.pagination a:not(.active)::attr(href) |
Останній рядок таблиці з характеристикою варто прочитати уважно: tr:contains(Вага) td:last-child бере рядок таблиці, у якому є слово «Вага», і з нього — останню комірку. Це надійніше, ніж рахувати рядки за номером: у різних товарів набір характеристик різний, і tr:nth-child(4) у кожного другого товару вкаже не туди.
Коли потрібен XPath
CSS вистачає у більшості випадків, і починати краще з нього — він коротший і його простіше прочитати через півроку. XPath беруть тоді, коли треба піднятися вгору по дереву або перевірити умову, якої в CSS немає.
| Завдання | XPath |
|---|---|
| Взяти батька знайденого елемента | //span[@class="sku"]/.. |
| Комірка праворуч від комірки з текстом | //td[text()="Вага"]/following-sibling::td[1] |
| Другий блок із класом | (//div[@class="price"])[2] |
| Елемент за точним текстом | //a[normalize-space(text())="Купити"] |
Не забудьте про галочку «XPath» у тому ж рядку — без неї сторінка не розбереться взагалі.
Чому селектор нічого не знаходить
| Симптом | Найімовірніша причина | Що зробити |
|---|---|---|
| Порожньо на всіх полях сторінки | у якомусь із правил синтаксична помилка або XPath без галочки — розбір обірвався | перевірте всі правила операції, а не тільки те, яке «не працює» |
| Порожньо в одному полі | селектор не знайшов елемента | подивіться розмітку сторінки очима: клас міг бути з іншим написанням або взагалі згенерованим |
| Приїхала порожня назва, хоча на сайті вона є | значення промальовується скриптом уже в браузері, у вихідній розмітці його немає | увімкніть режим із виконанням скриптів у налаштуваннях джерела |
| Замість тексту — сміття з розмітки | увімкнена галочка «Отримувати HTML» | зніміть її або звузьте список дозволених тегів |
| Замість ціни приїхав нуль | селектор вказує на блок, де ціна написана словами або лежить в атрибуті | візьміть ::attr(content) з мікророзмітки |
| Беруться всі фото разом із іконками | селектор занадто широкий, наприклад просто img | звузьте до контейнера галереї: div.gallery img::attr(src) |
| Селектор працював, а після оновлення сайту зламався | довгий ланцюжок на кшталт div:nth-child(3) > div > span ламається від зайвого банера | перепишіть коротше — за класом або атрибутом |
Псевдоклас :contains() не спрацьовує | текст лежить у вкладеному тегу, а не у власному тексті елемента | вкажіть той тег, у якому текст написаний безпосередньо |
Часті питання
Звідки взяти селектор, якщо я не верстальник?
Найпростіше — відкрити сторінку в браузері, натиснути на потрібному значенні правою кнопкою й вибрати «Переглянути код». Браузер підсвітить рядок розмітки: у ньому видно тег, клас і атрибути, з яких складається селектор. У самій програмі поруч із правилами є ШІ-помічник: йому віддають шматок розмітки, він відповідає готовим селектором.
Браузер дає дуже довгий селектор. Його можна вставляти?
Технічно так, працюватиме. Практично — він проживе до першої перемальовки сайту: ланцюжок із :nth-child ламається навіть від зайвого банера в блоці. Візьміть із цього ланцюжка найближчий клас або атрибут і напишіть коротко.
Що буде, якщо селектор знайшов кілька елементів?
Вони склеюються через роздільник, заданий у тому ж рядку правила в колонці «Розділювач значення». За замовчуванням це кома, для категорій — скісна риска з пробілами, для фото — три вертикальні риски. Для полів, де потрібне одне значення, звужуйте селектор.
CSS чи XPath — що обрати?
Починайте з CSS: коротше й зрозуміліше. XPath потрібен, коли треба піднятися до батьківського елемента або взяти сусідню комірку таблиці за текстом — у CSS таких засобів немає.
Селектор бере «Код: 12345», а потрібні лише цифри. Як бути?
Це вже не завдання селектора. У тому самому рядку правила є колонка «Регулярний вираз» — вона витягає шматок зі знайденого значення. Поруч працюють «Знайти» / «Замінити» і «Текст для очищення», якщо достатньо простої заміни.
Як перевірити селектор, не запускаючи весь збір?
У рядку правила є кнопка тесту: вона відкриває сторінку, адресу якої ви вказали в колонці «Посилання для тестування», і показує, що повернув селектор. Порожня колонка з адресою — і кнопка просто нічого не зробить, без жодного повідомлення.
Суміжні теми
- Парсинг сайтів — де саме вписуються ці селектори, як влаштований обхід і як читати журнал.
- Що саме забирає парсер із картки товару — повний перелік полів, які можна зібрати.
- Розширення Elbuz для Chrome — коли збір іде з браузера, а не з сервера.

