Парсинг веб-страниц с использованием BeautifulSoup в Python
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)
Надеюсь, вы поняли, что такое парсинг веб-страниц и как его делать. Увидимся в следующий раз!