CoderCastrov logo
CoderCastrov
Парсер

Парсинг данных с веб-сайта с использованием библиотек Requests и BeautifulSoup, Часть 1

Парсинг данных с веб-сайта с использованием библиотек Requests и BeautifulSoup, Часть 1
просмотров
4 мин чтение
#Парсер

Время от времени клиенты обращаются к вам с просьбой спарсить определенные данные из Интернета. Возможно, вам нужно просто скачать простой файл с веб-страницы или спарсить страницу, чтобы найти интересующую информацию. В этом случае на помощь приходят инструменты, такие как Requests, Beautiful Soup и Selenium. У каждой из упомянутых библиотек есть свои плюсы и минусы, но мы не будем рассматривать их в этой статье. Вместо этого мы более подробно рассмотрим, как скачать фактические HTML-данные с веб-страницы и записать результат в файл CSV.

Прежде чем мы приступим к парсингу, нам сначала нужно найти подходящую страницу, с которой мы можем скачать информацию. Хотя парсинг веб-страниц не запрещен, поскольку информация находится в открытом доступе в Интернете, я решил создать простое веб-приложение Django для этой цели. Само приложение можно скачать из моего репозитория на Github.

Само приложение довольно простое - это одна веб-страница с HTML-таблицей, содержащей информацию, которую мы ищем. Вот снимок экрана того, как выглядит страница:

Fig. 1. HTML-таблица для парсинга информации

Мы хотим спарсить всю эту HTML-таблицу и вывести информацию в файл CSV. Для этой цели мы будем использовать две библиотеки - Requests и Beautiful Soup. Модуль Requests будет использоваться для получения сырого HTML с нашей страницы, а Beautiful Soup - для извлечения только интересующей нас информации.

Поскольку Requests и BS - внешние библиотеки, их нужно скачать с помощью pip и импортировать в наш проект:

pip install requests
pip install beautifulsoup4

После установки мы создадим основной файл нашего проекта, назовем его main.py и импортируем эти библиотеки. Мы также импортируем модуль csv, потому что нам понадобится он для записи скачанных данных в файл.

import requests
import csv
from bs4 import BeautifulSoup

После импорта всех необходимых библиотек мы начнем с получения сырого HTML-файла.

def get_page(url):
    return requests.get(url).text

Функция выше довольно понятна. Она принимает один параметр, в нашем случае это URL, выполняет GET-запрос к этому URL и возвращает текст с этой страницы.

Наша следующая функция немного сложнее, потому что она обходит текст из get_page() и создает вложенный список с интересующей нас информацией. Ниже приведена сама функция.

def get_data(html_page):

    soup = BeautifulSoup(html_page, 'html.parser')

    outputHead = []
    for th in soup.find_all('th'):
        outputHead.append(th.text)

    outputRows = []
    for tr in soup.find_all('tr'):
        tableColumns = tr.find_all('td')
        outputRow = []
        for tc in tableColumns:
            outputRow.append(tc.text)
        outputRows.append(outputRow)

    outputRows.insert(0, outputHead)

    return outputRows

Функция get_data() принимает один параметр - HTML-страницу, возвращенную из предыдущей функции get_page(), и передает этот параметр конструктору BeautifulSoup, который разбирает документ с использованием HTML-парсера, если вы не указываете иное. Основная логика разделена на два раздела - первый раздел извлекает заголовок таблицы, а второй раздел обходит все строки таблицы. Мы используем функцию find_all() для поиска элементов, которые мы ищем, и записываем их в списки вывода. Список outputHead содержит заголовки, а outputRows содержит все строки таблицы. Одно важное замечание здесь заключается в том, что при использовании функции find_all() для поиска определенного элемента мы должны преобразовать его в текст, иначе мы добавим сырой HTML-код в наши списки. Вот снимок экрана, иллюстрирующий разницу между ними.

# Без преобразования в текст
outputHead = [
<th scope=”col”>#</th>, 
<th scope=”col”>Название продукта</th>, 
<th scope=”col”>Цена</th>, 
<th scope=”col”>Скидка</th>
]# С преобразованием в текст
['#', 'Название продукта', 'Цена', 'Скидка']

Поскольку мы работаем с двумя независимыми списками, перед тем, как вернуть результат из функции, мы должны вставить список outputHead на первую позицию в outputRows.

Наша следующая функция записывает возвращенные строки из get_data() в указанный пользователем файл. Вот как выглядит эта функция.

def write_csv(filename, rows):

    with open(f'{filename}.csv', 'w', newline = '') as file:
        writer = csv.writer(file)
        writer.writerows(rows)

Она принимает два параметра - имя файла и строки для вставки. Мы используем менеджер контекста для обработки всех задач с файлом (открытие, закрытие и т. д.). Функция довольно понятна. В основном мы создаем объект writer и передаем ему строки. Во-первых, мы открываем файл с указанным именем в режиме записи ('w' для строк), и нам нужно добавить newline='', иначе после добавления строки мы получим пустую строку. Во-вторых, мы создаем объект writer и передаем открытый файл, и, наконец, передаем строки в функцию writer.writerows нашего writer, чтобы добавить их в наш файл.

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

if __name__ == "__main__":

    URL = 'http://127.0.0.1:8000/scraper'

    html_text = get_page(URL)
    rows = get_data(html_text)
    write_csv('scrape-tutorial', rows)

Приложение Django, называемое scraper, работает на локальном хосте внутри виртуальной среды (если вы хотите узнать о venv, вы можете посетить еще один пост моего блога, где я объясняю, что такое venv и как его использовать), поэтому URL 127.0.0.1:8000/scraper. Вы можете скачать весь исходный код из моего репозитория на Github.

С этим мы завершаем эту статью. Надеюсь, она была полезной для вас, и я хотел бы поблагодарить вас за чтение. Удачного парсинга!