🟣 Selectolax. Парсинг HTML
selectolax одна з найшвидших бібліотек для парсингу html. Для пошуку тегів використовується css selectors.
Вона швидша за BeautifulSoup4 і немає проблем з анотаціями типів.
Давайте розглянемо задачу коли треба з html спарсити всі фрукти з такої html сторінки
Для початку створимо об'єкт парсеру:
Шукаєм один тег по id
⚠️ Якщо тег не знайдено метод парсеру вертає None тому завжди варто перевіряти цей момент щоб отримати помилку зі зрозумілим описом. Для цього можна використовувати assert або використати if і кидати Exception.
В середині знайденого тегу шукаємо список по імені тегу:
Використовуємо пошук по імені класу тега щоб знайти всі елементи списку
🔺 strip=True - видаляє зайві пробіли всередині тексту дочірніх тегів
🔺 separator - задає розділювач між текстами з різних дочірніх тегів
🔺 .strip() - обрізає пробіли (та переводи рядків) з початку і кінця рядка
Вивід коду:
#selectolax #parsing #scraping
selectolax одна з найшвидших бібліотек для парсингу html. Для пошуку тегів використовується css selectors.
Вона швидша за BeautifulSoup4 і немає проблем з анотаціями типів.
Давайте розглянемо задачу коли треба з html спарсити всі фрукти з такої html сторінки
html_content = """
<html>
<body>
<section id="fruits">
<h2>Fruits</h2>
<ul>
<li class="item red-item">🍎 Apple</li>
<li class="item">🍌 Banana</li>
<li class="item"> 🍊 <span style="color: orange;">Orange</span> </li>
</ul>
</section>
<section id="vegetables">
<h2>Vegetables</h2>
<ul>
<li class="item">🥕 Carrot</li>
<li class="item" data-id="42">🥔 Potato</li>
<li class="item" data-id="69">🍆 Eggplant</li>
</ul>
</section>
<a href="https://t.me/Python_Materials_For_Beginners/170">Parsing</a>
</body>
</html>
"""
Для початку створимо об'єкт парсеру:
from selectolax.lexbor import LexborHTMLParser, LexborNode
parser = LexborHTMLParser(html_content)
Шукаєм один тег по id
container_el: LexborNode | None = parser.css_first("section#fruits")
assert container_el, "Fruits container not found!"⚠️ Якщо тег не знайдено метод парсеру вертає None тому завжди варто перевіряти цей момент щоб отримати помилку зі зрозумілим описом. Для цього можна використовувати assert або використати if і кидати Exception.
В середині знайденого тегу шукаємо список по імені тегу:
list_el = container_el.css_first("ul")
assert list_el, "List of fruits not found!"Використовуємо пошук по імені класу тега щоб знайти всі елементи списку
item_els: list[LexborNode] = list_el.css("li.item")
for item_el in item_els:
text = item_el.text(strip=True, separator="-").strip()
print(text)🔺 strip=True - видаляє зайві пробіли всередині тексту дочірніх тегів
🔺 separator - задає розділювач між текстами з різних дочірніх тегів
🔺 .strip() - обрізає пробіли (та переводи рядків) з початку і кінця рядка
Вивід коду:
🍎 Apple
🍌 Banana
🍊-Orange-
#selectolax #parsing #scraping
🟠 Selectolax. Парсинг HTML. Частина 2.
🔺 Поєднанний пошук.
Пошук по CSS-селекторах дозволяє одразу поєднувати все в одному рядку запиту:
❗️ Але я наполегливо не рекомендував би цим зловживати. Короткий запис — це добре, але у випадку помилки буде важко зрозуміти, з яким саме тегом проблема.
🔺 Пошук тега який має декілька класів
🔺 Атрибути тегу
Для отримання атрибуту тегу :
▪️attributes – це read-only словник. Ти можеш з нього читати, але не змінювати напряму.
▪️attrs – це mutable dict-like (звичайний словник), який можна змінювати.
🔺 Пошук по атрибуту:
#selectolax #parsing #scraping
🔺 Поєднанний пошук.
Пошук по CSS-селекторах дозволяє одразу поєднувати все в одному рядку запиту:
item_els = parser.css("section#fruits ul li.item")
for item_el in item_els:
text = item_el.text(strip=True, separator=" ").strip()
print(text)❗️ Але я наполегливо не рекомендував би цим зловживати. Короткий запис — це добре, але у випадку помилки буде важко зрозуміти, з яким саме тегом проблема.
🔺 Пошук тега який має декілька класів
# <li class="item red-item"> ... </li>
red_item_el = parser.css_first("li.item.red-item")
assert red_item_el
print(red_item_el.text()) # 🍎 Apple
🔺 Атрибути тегу
# <a href=" ... ">Parsing</a>
link_el = parser.css_first("a")
assert link_el
url = link_el.attributes["href"]
print(url) # https://t.me/Python_Materials_For_Beginners/170
Для отримання атрибуту тегу :
▪️attributes – це read-only словник. Ти можеш з нього читати, але не змінювати напряму.
▪️attrs – це mutable dict-like (звичайний словник), який можна змінювати.
🔺 Пошук по атрибуту:
data_els = parser.css("li.item[data-id]")
for data_el in data_els:
data_id = data_el.attributes["data-id"]
print(data_id) # 42 69data_el = parser.css_first("li.item[data-id='42']")
assert data_el
print(data_el.html) # <li class="item" data-id="42"> ... Potato</li>#selectolax #parsing #scraping
👍1
🟢 Selectolax. Парсинг HTML. Підсумки та рекомендації.
Для пошуку тегів ми можемо використовувати:
▪️ id тега
▪️ назву тега
▪️ клас тега
▪️ атрибути тега
❗️ У коректному HTML id завжди повинен бути унікальним, тому пошук по ньому — найнадійніший.
Якщо ж шукати по назві/класу/атрибутам, результатів може бути кілька, і серед них можуть траплятися елементи, які ви не очікували знайти.
У нашому прикладі, якщо ми хочемо тільки фрукти й напишемо:
То отримаємо не лише фрукти, а й овочі — це видно одразу у нашому простому HTML-коду. Реальні html-сторінки по розміру значно більші і можна не помітити десь ще на сторінці використовуються схожі теги але у зовсім іншому контексті, як наслідок — незрозумілі помилки у коді.
👉 Тому рекомендую завжди звужувати пошук: спершу знайдіть найближчий батьківський елемент із логічним id, класом чи атрибутом, а вже потім отримуйте потрібні дочірні теги.
👉 Важливо, щоб назви класів, id чи атрибутів, до яких ви прив’язуєтеся, були логічними та «говорили самі за себе». Так менша ймовірність отримати помилкові результати, а код буде легше читати й підтримувати.
👉 Є певна термінологія в HTML: тег зазвичай називають елементом (DOM element) або нодою (Node). Я відповідно додаю суфікс
#selectolax #parsing #scraping
Для пошуку тегів ми можемо використовувати:
▪️ id тега
▪️ назву тега
▪️ клас тега
▪️ атрибути тега
❗️ У коректному HTML id завжди повинен бути унікальним, тому пошук по ньому — найнадійніший.
Якщо ж шукати по назві/класу/атрибутам, результатів може бути кілька, і серед них можуть траплятися елементи, які ви не очікували знайти.
У нашому прикладі, якщо ми хочемо тільки фрукти й напишемо:
item_els = parser.css("li.item") То отримаємо не лише фрукти, а й овочі — це видно одразу у нашому простому HTML-коду. Реальні html-сторінки по розміру значно більші і можна не помітити десь ще на сторінці використовуються схожі теги але у зовсім іншому контексті, як наслідок — незрозумілі помилки у коді.
👉 Тому рекомендую завжди звужувати пошук: спершу знайдіть найближчий батьківський елемент із логічним id, класом чи атрибутом, а вже потім отримуйте потрібні дочірні теги.
👉 Важливо, щоб назви класів, id чи атрибутів, до яких ви прив’язуєтеся, були логічними та «говорили самі за себе». Так менша ймовірність отримати помилкові результати, а код буде легше читати й підтримувати.
👉 Є певна термінологія в HTML: тег зазвичай називають елементом (DOM element) або нодою (Node). Я відповідно додаю суфікс
_el або _els до змінних, які містять об’єкти тегів. Це не принципово, але, на мою думку, так код читається краще й спрощується іменування змінних.#selectolax #parsing #scraping
👍1
💎 httpx+selectolax. Data scraping.
Розглянимо приклад коду який наводив у чаті . Код достатньо довгий тому Git-Gist
1️⃣ Часті запити на сайт можуть призвести до:
▪️ відповіді HTTP 429 Too Many Requests
▪️ обриву з'єднання сервером
▪️ появу капчі
▪️ блокуванню по IP
Тому варто обмежувати кількість запитів у секунду. Для цього існує бібліотека asynciolimiter яка дає можливість це зробити за допомогою Limiter: перед кожним запитом варто викликати його метод limiter.wait()
2️⃣ При скрапінгу даних використовуємо сесії. Це пришвидшує виконання запитів і дає підтримку cookie.
3️⃣ Щоб згрупувати дані разом варто використовувати класи, dataclasses, NamedTuple або як я моделі pydantic
4️⃣ Код варто розбивати на функції, класи, модулі і пакети уникаючи награмодження коду. В даному прикладі я показую розбиття на ф-ції але можна було всю роботу з сайтом винести у модуль або пакет. Також можна було зробити клас QuoteScraper з відповідними методами (це дозволило б не передавати постійно session та limiter у параметрах).
📦
┣━━ 📜
┣━━ ⚙️
┣━━ 🧾
┣━━ 🔎
┗━━ 🕷
📜
Структура має бути не обов'язково така сама, але вона має
бути. Коли весь проєкт у одному файлі — це не норм.
5️⃣ Особисто я використовую такий неймінг:
5.1. Функції які займаютья парсингом HTML назвиваю як
parse_ *
5.2. Функціїї які роблять запити: scrape_*
також можна назвивати get_* або fetch_*
6️⃣ Для перевірки наявності потрібних використовую assert але можна також кидати Exception/RuntimeError
7️⃣ Використання logging дає змогу налаштовувати кількість/рівень повідомлень у консоль як власного коду так і коду використаних бібліотек.
8️⃣ Використання генераторів та ітераторів дає можливість більш гнучко використовувати написаний код. (наприклад зупинити ітерацію по сторінкам коли знайдена потрібна цитата)
#httpx #selectolax #parsing #scraping
Розглянимо приклад коду який наводив у чаті . Код достатньо довгий тому Git-Gist
1️⃣ Часті запити на сайт можуть призвести до:
▪️ відповіді HTTP 429 Too Many Requests
▪️ обриву з'єднання сервером
▪️ появу капчі
▪️ блокуванню по IP
Тому варто обмежувати кількість запитів у секунду. Для цього існує бібліотека asynciolimiter яка дає можливість це зробити за допомогою Limiter: перед кожним запитом варто викликати його метод limiter.wait()
2️⃣ При скрапінгу даних використовуємо сесії. Це пришвидшує виконання запитів і дає підтримку cookie.
3️⃣ Щоб згрупувати дані разом варто використовувати класи, dataclasses, NamedTuple або як я моделі pydantic
4️⃣ Код варто розбивати на функції, класи, модулі і пакети уникаючи награмодження коду. В даному прикладі я показую розбиття на ф-ції але можна було всю роботу з сайтом винести у модуль або пакет. Також можна було зробити клас QuoteScraper з відповідними методами (це дозволило б не передавати постійно session та limiter у параметрах).
📦
quote_scraper┣━━ 📜
__init__.py ┣━━ ⚙️
config.py - константи, наприклад BASE_URL ┣━━ 🧾
schemas.py - моделі даних┣━━ 🔎
parsers.py - функції для парсингу html┗━━ 🕷
scrapers.py - функції для запит+парсинг 📜
main.pyСтруктура має бути не обов'язково така сама, але вона має
бути. Коли весь проєкт у одному файлі — це не норм.
5️⃣ Особисто я використовую такий неймінг:
5.1. Функції які займаютья парсингом HTML назвиваю як
parse_ *
5.2. Функціїї які роблять запити: scrape_*
також можна назвивати get_* або fetch_*
6️⃣ Для перевірки наявності потрібних використовую assert але можна також кидати Exception/RuntimeError
7️⃣ Використання logging дає змогу налаштовувати кількість/рівень повідомлень у консоль як власного коду так і коду використаних бібліотек.
8️⃣ Використання генераторів та ітераторів дає можливість більш гнучко використовувати написаний код. (наприклад зупинити ітерацію по сторінкам коли знайдена потрібна цитата)
#httpx #selectolax #parsing #scraping
👍1