Как извлечь полезную информацию с сайта через Scrapy
По другому это называется парсинг (parsing) или скрейпинг (scraping). Осторожно - владельцы ресурсов могут быть недовольны!
Задача
Разберём на примере библиотеки Bulma. Она содержит готовые качественные компоненты оформления: кнопки, меню, формы. И всё это можно бесплатно использовать при создании веб-приложений. В общем, экономит кучу времени, полезная штука!
Но документация у них это какой-то балаган. Реклама курсов (тут понятно, проект-то бесплатный), лишних внутренних ссылок и мелких украшательств. А подгрузка ссылок на мутные онлайн-казино уже перебор, см. внизу снимка:
Делать оффлайн-копию такого сайта не имеет смысла, слишком много лишнего. Видно, что сайт работает на движке Jekyll, доступен репозиторий с кодом, возможно есть способ отключить лишние блоки и собрать как нужно, но у меня не получилось, плохо понимаю язык Руби. Так что будем извлекать только нужное.
План работы
- Наиболее популярная Python-библиотека по теме - Scrapy, берём её.
- Ещё нужно очищать HTML от лишних
Код парсера
Кода не так уж много, основная сложность - найти в коде страницы привязки к нужным блокам (CSS-селекторы), в коде это строки в аргументах метода .css(...)
:
import scrapy
from bulma_docs.items import BulmaPage
ROOT_URL = "https://bulma.io/documentation/"
def get_filename(url: str) -> str:
"""Перевод адресов страниц в плоский вид"""
return url[len(ROOT_URL) :].strip("/").replace("/", "--") + ".html"
class DocsSpider(scrapy.Spider):
name = "docs"
start_urls = [ROOT_URL]
def parse_page(self, response):
prev = response.css(".bd-pagination-prev").attrib
prev_href = prev.get("href")
next = response.css(".bd-pagination-next").attrib
next_href = next.get("href")
return BulmaPage(
url=response.url,
filename=get_filename(response.url),
title=response.css("h1~p::text").get(), ## "h1 p::text" не работает
subtitle=response.css("h2~p").get(), ## "h2 p" не работает
content=response.css(".bd-docs-content").get(),
previous_link=get_filename(prev_href) if prev_href else None,
previous_page=prev.get("title"),
next_link=get_filename(next_href) if next_href else None,
next_page=next.get("title"),
)
def parse(self, response):
for item in response.css(".bd-menu-list .bd-menu-link"):
yield scrapy.Request(item.xpath("@href").get(), callback=self.parse_page)
Результат
Warning
Тут надо добавить снимок экрана
Ссылки
- Официальная документация Scrapy
- Веб-скрапинг с Scrapy на Python - статья на Хабре от компании OTUS