CoderCastrov logo
CoderCastrov
Парсер

Парсинг веб-страниц с использованием BeautifulSoup в Python

Парсинг веб-страниц с использованием BeautifulSoup в Python
просмотров
5 мин чтение
#Парсер
Table Of Content

    Привет мир! В этой статье мы рассмотрим основы парсинга веб-страниц на Python. Но сначала важно понять, что такое парсинг и почему нам это важно.

    Представьте, что вы пытаетесь проанализировать данные на электронной коммерческой платформе. Вам нужны данные с этого сайта, чтобы обрабатывать их в своем коде. Обычным способом сделать это было бы отправить запрос к API-конечной точке сайта и получить нужные данные. Но это не всегда возможно, потому что есть сайты, которые не предоставляют удобного API. Также бывают случаи, когда вам приходится платить, чтобы получить доступ к API. Как же мы можем справиться с этим? Вот где нам пригодится парсинг веб-страниц.

    Парсинг позволяет нам быстро и безболезненно получать нужные данные с веб-страницы. Как я уже упоминал, это очень полезно, когда сайт, который вам нужен, не предлагает API для извлечения нужных данных.

    Это не значит, что парсинг веб-страниц не вызывает опасений. На самом деле, существует законодательство, касающееся парсинга, потому что при неправильном использовании он может привести к краже интеллектуальной собственности или нечестной конкурентной выгоде. Это означает, что незаконно получать данные с сайта и создавать на их основе другой сайт. Ниже приведены несколько правил, которым следует придерживаться, когда вам приходится использовать парсинг.

    • Если вы можете найти общедоступное API, которое может получить нужные вам данные, всегда используйте это API вместо парсинга.
    • Вы можете просмотреть файл robot.txt, прежде чем начать парсить, чтобы получить ясное представление о том, что запрещено парсить на веб-сайте. Вы можете просмотреть этот файл, добавив '/robot.txt' к URL-адресу сайта. Например, вот версия файла для GitHub. Он выглядит так:
    • Всегда убедитесь, что запрашиваем данные с разумной скоростью. Для этого можно добавить небольшой интервал времени между запросами.
    • Всегда будьте вежливы и получайте только те данные, которые вам действительно нужны, а не все подряд.

    Теперь давайте перейдем к тому, как на самом деле выполняется парсинг веб-страниц. В Python мы используем модуль под названием bs4 для получения BeautifulSoup, который является его частью. Кроме того, нам нужен модуль requests для отправки фактического HTTP-запроса. После установки модулей bs4 и requests вы можете импортировать их следующим образом:

    from bs4 import BeautifulSoup
    import requests

    Сначала вам нужно отправить запрос на нужный URL и получить ответ от сервера. Есть много сайтов, созданных исключительно для парсинга, и Quotes to scrape и Books to Scrape - лишь некоторые из них. В этом примере я буду использовать сайт Quotes to Scrape. Вам нужно отправить запрос и сохранить ответ следующим образом:

    url = 'https://quotes.toscrape.com/'
    response = requests.get(url)

    Ответ, который мы получаем, является строкой, поэтому мы не можем получить доступ или обработать его так, как хотим. Следующим шагом является создание экземпляра BeautifulSoup, передав полученный ответ:

    soup = BeautifulSoup(response.text, 'html.parser')

    Если вы изучите страницу Quotes to scrape с помощью инструментов разработчика, вы увидите, что детали каждой цитаты находятся внутри div с классом "quote":

    <div class="quote">
      <span class="text">"Цитата"</span>
      <span>— <small class="author">Автор</small></span>
    </div>

    После определения CSS-селекторов контейнера для каждой цитаты все, что вам нужно сделать, это выбрать их. Это можно сделать следующим образом:

    quotes = soup.select('.quote')

    .select() возвращает массив, даже если есть только один результат. В этом случае у нас есть массив div'ов (цитат). Мы можем перебрать массив цитат, который мы только что создали, и извлечь каждую цитату и автора или что-либо еще, что нам нужно. Затем мы добавляем каждую запись в виде словаря в другой массив для удобства использования:

    data = []
    for quote in quotes:
        text = quote.select_one('.text').get_text()
        author = quote.select_one('.author').get_text()
        data.append({'quote': text, 'author': author})

    Текст цитаты находится внутри span с классом "text". Имя автора находится внутри тега small с классом "author". Мы используем метод .get_text() для получения текста элемента. С помощью команды print вы можете увидеть все цитаты и авторов на первой странице сайта в виде массива.

    Но чаще всего нам нужно извлекать данные со всех доступных страниц сайта, верно? Мы хотим нажимать кнопку "Далее" снова и снова и получать все данные, доступные на всех страницах, а не только на одной странице.

    Вот как это делается:

    Сначала нам нужно найти кнопку "Далее" или аналогичную навигацию на следующую страницу на текущей странице. Затем мы выбираем этот следующий URL и продолжаем получать данные, пока этого следующего URL больше нет (это означает, что мы на последней странице).

    Окончательный код для получения всех доступных цитат выглядит следующим образом:

    def scrape_quotes():
        url = 'https://quotes.toscrape.com/'
        data = []
        
        while True:
            response = requests.get(url)
            soup = BeautifulSoup(response.text, 'html.parser')
            quotes = soup.select('.quote')
            
            for quote in quotes:
                text = quote.select_one('.text').get_text()
                author = quote.select_one('.author').get_text()
                data.append({'quote': text, 'author': author})
            
            next_button = soup.select_one('.next > a')
            if not next_button:
                break
            
            url = url + next_button['href']
        
        return data

    В приведенном выше примере я обернул все в функцию для повторного использования. Также, используя функцию, мы можем повторять парсинг только по необходимости, вызывая функцию, а не запуская процесс парсинга каждый раз при запуске файла.

    Обратите внимание, что я добавил задержку в 1 секунду между каждым запросом в блоке try, добавив sleep(1), чтобы не нагружать сервер. Это хорошая практика при парсинге веб-страниц.

    Вы также можете сохранить результат в файл CSV, если хотите, следующим образом:

    Сначала вам нужно импортировать 'DictWriter' из модуля 'csv':

    from csv import DictWriter

    Затем вы можете написать небольшую функцию, которая будет принимать массив цитат, сгенерированный нами, и записывать его в файл CSV:

    def write_quotes_to_csv(quotes):
        with open('quotes.csv', 'w', newline='', encoding='utf-8') as file:
            headers = ['quote', 'author']
            csv_writer = DictWriter(file, fieldnames=headers)
            csv_writer.writeheader()
            csv_writer.writerows(quotes)

    Наконец, вы можете выполнить обе функции следующим образом, чтобы сгенерировать файл CSV со всеми цитатами и авторами:

    quotes = scrape_quotes()
    write_quotes_to_csv(quotes)

    Надеюсь, вы поняли, что такое парсинг веб-страниц и как его делать. Увидимся в следующий раз!