Перейти к содержанию

Как извлечь полезную информацию с сайта через Scrapy

По другому это называется парсинг (parsing) или скрейпинг (scraping). Осторожно - владельцы ресурсов могут быть недовольны!

Задача

Разберём на примере библиотеки Bulma. Она содержит готовые качественные компоненты оформления: кнопки, меню, формы. И всё это можно бесплатно использовать при создании веб-приложений. В общем, экономит кучу времени, полезная штука!

Но документация у них это какой-то балаган. Реклама курсов (тут понятно, проект-то бесплатный), лишних внутренних ссылок и мелких украшательств. А подгрузка ссылок на мутные онлайн-казино уже перебор, см. внизу снимка:

Куча сетевых запросов на вкладке Network

Делать оффлайн-копию такого сайта не имеет смысла, слишком много лишнего. Видно, что сайт работает на движке 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

Тут надо добавить снимок экрана

Ссылки