Как извлечь данные с веб-сайтов

В сети много данных. Возможность извлекать из него нужную информацию, несомненно, полезна и даже необходима. Конечно, на таких сайтах, как Kaggle, вы все еще можете загрузить множество наборов данных, но во многих случаях вы не найдете точных данных, необходимых для решения вашей конкретной проблемы. Однако есть вероятность, что где-то в Интернете вы найдете то, что вам нужно, и вам нужно будет извлечь это оттуда.

Веб-скрапинг - это процесс извлечения данных с веб-страниц. В этой статье мы увидим, как выполнять парсинг веб-страниц на Python. Для этой задачи вы можете использовать несколько библиотек. Среди них мы будем использовать Beautiful Soup 4. Эта библиотека заботится об извлечении данных из HTML-документа, а не о его загрузке. Для загрузки веб-страниц нам понадобится другая библиотека: запросы.

Итак, нам понадобится 2 пакета:

  • запросы - для загрузки HTML-кода с заданного URL
  • красивый суп - для извлечения данных из этой HTML-строки

Установка библиотек

Теперь давайте начнем с установки необходимых пакетов. Откройте окно терминала и введите:

python -m pip install requests beautifulsoup4

… Или, если вы используете среду conda:

conda install requests beautifulsoup4

Теперь попробуйте запустить следующее:

import requests
from bs4 import BeautifulSoup

Если вы не получите никаких ошибок, значит, пакеты установлены успешно.

Использование запросов и красивого супа для извлечения данных

Из пакета requests мы будем использовать функцию get() для загрузки веб-страницы с заданного URL:

requests.get(url, params=None, **kwargs)

Где параметры:

  • url - URL желаемой веб-страницы
  • params - необязательный словарь, список кортежей или байтов для отправки в строке запроса.
  • ** kwargs - необязательные аргументы, которые принимает запрос

Эта функция возвращает объект типа requests.Response. Среди атрибутов и методов этого объекта нас больше всего интересует атрибут .content, который состоит из HTML-строки целевой веб-страницы.

Пример:

html_string = requests.get("http://www.example.com").content

После того, как мы получили HTML-код целевой веб-страницы, мы должны использовать конструктор BeautifulSoup() для его анализа и получить объект BeautifulSoup, который мы можем использовать для навигации по дереву документа и извлечения необходимых нам данных.

soup = BeautifulSoup(markup_string, parser)

Где:

  • markup_string - строка нашей веб-страницы
  • парсер - строка, состоящая из названия используемого парсера; здесь мы будем использовать синтаксический анализатор Python по умолчанию: «html.parser»

Обратите внимание, что мы назвали первый параметр «markup_string» вместо «html_string», потому что BeautifulSoup может использоваться и с другими языками разметки, а не только с HTML, но нам нужно указать соответствующий синтаксический анализатор; например мы можем разобрать XML, передав «xml» в качестве парсера.

У объекта BeautifulSoup есть несколько методов и атрибутов, которые мы можем использовать для навигации по проанализированному документу и извлечения из него данных.
Наиболее используемый метод - .find_all():

soup.find_all(name, attrs, recursive, string, limit, **kwargs)
  • name - название тега; например «А», «div», «img»
  • attrs - словарь с атрибутами тега; например {“class”: “nav”, “href”: “#menuitem”}
  • рекурсивный - логический; если false, рассматриваются только прямые дочерние элементы, если true (по умолчанию) все дочерние элементы проверяются в поиске
  • строка - используется для поиска строк в содержимом элемента.
  • limit - ограничить поиск только этим количеством найденных элементов.

Пример:

soup.find_all("a", attrs={"class": "nav", "data-foo": "value"})

Строка выше возвращает список со всеми элементами «a», которые также имеют указанные атрибуты.

Атрибуты HTML, которые нельзя спутать с параметрами этого метода или ключевыми словами Python (например, «класс»), можно использовать непосредственно в качестве параметров функции без необходимости помещать их в attrs словарь. Атрибут HTML class также можно использовать таким же образом, но вместо class=”…” напишите class_=”…”.

Пример:

soup.find_all("a", class_="nav")

Поскольку этот метод является наиболее часто используемым, у него есть ярлык: прямой вызов объекта BeautifulSoup имеет тот же эффект, что и вызов метода .find_all().

Пример:

soup("a", class_="nav")

Метод .find() похож на .find_all(), но он останавливает поиск после того, как найдет первый элемент; элемент, который будет возвращен. Это примерно эквивалентно .find_all(..., limit=1), но вместо возврата списка он возвращает единственный элемент.

Атрибут .contents объекта BeautifulSoup - это список со всеми его дочерними элементами. Если текущий элемент не содержит вложенных элементов HTML, тогда .contents[0] будет просто текстом внутри него. Итак, после того, как мы получили элемент, содержащий нужные нам данные, с помощью методов .find_all() или .find(), все, что нам нужно сделать, чтобы получить данные внутри него, - это получить доступ к .contents[0].

Пример:

soup = BeautifulSoup('''
    <div>
        <span class="rating">5</span>
        <span class="views">100</span>
    </div>
''', "html.parser")
views = soup.find("span", class_="views").contents[0]

Что, если нам нужен фрагмент данных, который находится не внутри элемента, а в качестве значения атрибута? Мы можем получить доступ к значению атрибута элемента следующим образом:

soup['attr_name']

Пример:

soup = BeautifulSoup('''
    <div>
        <img src="./img1.png">
    </div>
''', "html.parser")
img_source = soup.find("img")['src']

Пример парсинга: получить 10 лучших дистрибутивов Linux

Теперь давайте посмотрим на простой пример парсинга веб-страниц с использованием описанных выше концепций. Мы извлечем список из 10 самых популярных дистрибутивов Linux с веб-сайта DistroWatch. DistroWatch (https://distrowatch.com/) - это веб-сайт, на котором публикуются новости о дистрибутивах Linux и программном обеспечении с открытым исходным кодом, которое работает на Linux. Этот веб-сайт имеет в правой части рейтинг самых популярных дистрибутивов Linux. Из этого рейтинга мы извлечем первые 10.

Сначала мы загрузим веб-страницу и создадим из нее объект BeautifulSoup:

import requests
from bs4 import BeautifulSoup

soup = BeautifulSoup(
    requests.get("https://distrowatch.com/").content,
    "html.parser")

Затем нам нужно выяснить, как идентифицировать данные, которые мы хотим внутри HTML-кода. Для этого мы будем использовать инструменты разработчика Chrome. Щелкните правой кнопкой мыши где-нибудь на веб-странице, а затем нажмите «Проверить» или нажмите «Ctrl + Shift + I», чтобы открыть инструменты разработчика Chrome. Должно получиться так:

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

В нашем примере мы видим, что этот рейтинг структурирован в виде таблицы HTML, а имя каждого дистрибутива находится внутри элемента td с классом «phr2». Затем внутри этого элемента td находится ссылка, содержащая текст, который мы хотим извлечь (имя дистрибутива). Вот что мы сделаем в следующих нескольких строках кода:

top_ten_distros = []
distro_tds = soup("td", class_="phr2", limit=10)
for td in distro_tds:
    top_ten_distros.append(td.find("a").contents[0])

И вот что у нас получилось:

Надеюсь, эта информация была для вас полезной, и спасибо за внимание!

Эта статья также размещена на моем собственном сайте здесь. Не стесняйтесь смотреть!