Начать заниматься веб-скрейпингом очень просто, за исключением тех случаев, когда это не так, поэтому вы, вероятно, и находитесь здесь. Но не волнуйтесь – мы всегда готовы помочь!
На этот раз посмотрите наш пошаговый видеоурок Python Web Scraping на Youtube:
Или прочитайте статью ниже!
- Введение
- Создание веб-скрапера: Подготовка к работе с Python
- Доступ к библиотекам
- Библиотека Requests
- Beautiful Soup
- lxml
- Selenium
- Сравнение библиотек Python для веб-скрейпинга
- Веб-драйверы и браузеры
- Поиск уютного места для нашего веб-скрапера Python
- Импорт и использование библиотек
- Выбор URL-адреса
- Определение объектов и построение списков
- Извлечение данных с помощью нашего веб-скрапера Python
- Экспорт данных
- Больше списков. Больше!
- Веб-скрейпинг с помощью лучших практик Python
- Заключение
Введение
Python – один из самых простых способов начать работу, поскольку это объектно-ориентированный язык. Классы и объекты в Python значительно проще в использовании, чем в любом другом языке. Кроме того, существует множество библиотек, которые позволяют создать инструмент для веб-скрейпинга на Python без особых усилий.
В этом учебнике по веб-скрейпингу на Python мы расскажем обо всем, что необходимо для начала работы с простым приложением. Оно будет получать текстовые данные из источников страниц, сохранять их в файл и сортировать вывод в соответствии с заданными параметрами. Мы также рассмотрим варианты более продвинутых функций при использовании Python. Следуя нашему подробному руководству, вы сможете понять, как выполнять веб-скрейпинг.
Во-первых, что мы называем веб-скрейпингом?
Веб-скрейпинг – это автоматизированный процесс сбора общедоступных данных. Скрапер веб-страниц автоматически извлекает большое количество открытых данных с целевых веб-сайтов за считанные секунды.
Примечание: Этот учебник по веб-скрейпингу на Python будет работать для всех операционных систем. Будут небольшие различия при установке Python или среды разработки, но не во всем остальном.
Создание веб-скрапера: Подготовка к работе с Python
Во всем этом учебнике по веб-скрейпингу будет использоваться Python версии 3.4+. В частности, мы использовали 3.8.3, но любая версия 3.4+ будет работать отлично.
Для Windows-инсталляций при установке Python убедитесь, что отмечен пункт “Установка PATH”. Установка PATH добавляет исполняемые файлы в поиск исполняемых файлов в командной строке Windows по умолчанию. После этого Windows будет распознавать такие команды, как “pip” или “python”, не требуя от пользователя указывать на каталог исполняемого файла (например, C:/tools/python/…/python.exe). Если вы уже установили Python, но не отметили этот флажок, просто повторно запустите установку и выберите изменить. На втором экране выберите “Добавить в переменные среды”.
Доступ к библиотекам
Одним из преимуществ Python является большой выбор библиотек для веб-скрейпинга. Эти библиотеки для веб-скрейпинга являются частью тысяч существующих проектов Python – только на PyPI сегодня насчитывается более 300 000 проектов. Примечательно, что существует несколько типов
Python библиотек для веб-скрейпинга, из которых вы можете выбирать:
- Requests
- Beautiful Soup
- lxml
- Selenium
Библиотека Requests
Веб-скрейпинг начинается с отправки HTTP-запросов, таких как POST или GET, на сервер сайта, который возвращает ответ, содержащий необходимые данные. Однако стандартные HTTP-библиотеки Python сложны в использовании и, для эффективности, требуют громоздких строк кода, что еще больше усугубляет и без того проблемный вопрос.
В отличие от других HTTP-библиотек, библиотека Requests упрощает процесс выполнения таких запросов, сокращая количество строк кода, что, по сути, делает код более понятным и отлаживаемым без ущерба для его эффективности. Библиотеку можно установить из терминала с помощью команды pip:
pip install requests
Библиотека запросов предоставляет простые методы для отправки HTTP GET и POST запросов. Например, функция для отправки HTTP Get запроса имеет меткое название get():
import requests
response = requests.get("https://oxylabs.io/”)
print(response.text)
Если необходимо разместить форму, это можно легко сделать с помощью метода post(). Данные формы могут быть отправлены в виде словаря следующим образом:
form_data = {'key1': 'value1', 'key2': 'value2'}
response = requests.post("https://oxylabs.io/ ", data=form_data)
print(response.text)
Библиотека запросов также позволяет легко использовать прокси-серверы, требующие аутентификации.
proxies={'http': 'http://user:password@proxy.oxylabs.io'}
response = requests.get('http://httpbin.org/ip', proxies=proxies)
print(response.text)
Но у этой библиотеки есть ограничение – она не разбирает извлеченные HTML-данные, то есть не может преобразовать их в более читаемый формат для анализа. Кроме того, ее нельзя использовать для сканирования веб-сайтов, написанных исключительно на JavaScript.
Beautiful Soup
Beautiful Soup – это библиотека Python, которая работает с парсером для извлечения данных из HTML и может превратить даже некорректную разметку в дерево разбора. Однако эта библиотека предназначена только для разбора и не может запрашивать данные с веб-серверов в виде HTML-документов/файлов. По этой причине она чаще всего используется вместе с библиотекой Python Requests. Обратите внимание, что Beautiful Soup упрощает запрос и навигацию по HTML, но все равно требует наличия парсера. Следующий пример демонстрирует использование модуля html.parser, который является частью стандартной библиотеки Python.
#Часть 1 – Получение HTML с помощью запросов
import requests
url='https://oxylabs.io/blog'
response = requests.get(url)
#Часть 2 – Поиск элемента
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
print(soup.title)
Это выведет элемент заголовка следующим образом:
<h1 class="blog-header">Oxylabs Blog</h1>
Благодаря простым способам навигации, поиска и модификации дерева разбора, Beautiful Soup идеально подходит даже для новичков и обычно экономит разработчикам часы работы. Например, чтобы вывести все заголовки блогов с этой страницы, можно использовать метод findAll(). На этой странице все заголовки блогов находятся в элементах h2 с атрибутом class, установленным в blog-card__content-title. Эту информацию можно передать методу findAll следующим образом:
blog_titles = soup.findAll('h2', attrs={"class":"blog-card__content-title"})
for title in blog_titles:
print(title.text)
# Output:
# Prints all blog tiles on the page
BeautifulSoup также упрощает работу с селекторами CSS. Если вы знаете CSS-селектор, нет необходимости изучать методы find() или find_all(). Ниже приведен тот же пример, но с использованием селекторов CSS:
blog_titles = soup.select('h2.blog-card__content-title')
for title in blog_titles:
print(title.text)
Хотя парсинг broken-HTML является одной из главных особенностей этой библиотеки, она также предлагает множество функций, включая тот факт, что она может определять кодировку страницы, что повышает точность данных, извлекаемых из HTML-файла.
Более того, ее можно легко настроить с помощью всего нескольких строк кода для извлечения любых пользовательских общедоступных данных или для определения определенных типов данных.
lxml
lxml – это библиотека синтаксического анализа. Это быстрая, мощная и простая в использовании библиотека, которая работает как с HTML, так и с XML файлами. Кроме того, lxml идеально подходит для извлечения данных из больших наборов данных. Однако, в отличие от Beautiful Soup, эта библиотека подвержена влиянию плохого дизайна HTML, что затрудняет ее возможности по разбору.
Библиотеку lxml можно установить из терминала с помощью команды pip:
pip install lxml
Эта библиотека содержит модуль html для работы с HTML. Однако библиотеке lxml сначала требуется строка HTML. Эта строка HTML может быть получена с помощью библиотеки Requests, как обсуждалось в предыдущем разделе. После получения HTML дерево может быть построено с помощью метода fromstring следующим образом:
# After response = requests.get()
from lxml import html
tree = html.fromstring(response.text)
Теперь этот объект дерева можно запросить с помощью XPath. Продолжая пример, рассмотренный в предыдущем разделе, чтобы получить название блогов, XPath будет выглядеть следующим образом:
//h2[@class="blog-card__content-title"]/text()
Этот XPath можно передать функции tree.xpath(). Она вернет все элементы, соответствующие этому XPath. Обратите внимание на функцию text() в XPath. Она извлечет текст внутри элементов h2.
blog_titles = tree.xpath('//h2[@class="blog-card__content-title"]/text()')
for title in blog_titles:
print(title)
Предположим, вы хотите научиться использовать эту библиотеку и интегрировать ее в свои усилия по веб-скрейпингу или даже получить дополнительные знания в дополнение к уже имеющимся. В этом случае наш подробный учебник по lxml – отличное место для начала.
Selenium
Как мы уже говорили, некоторые веб-сайты написаны с использованием JavaScript, языка, который позволяет разработчикам динамически заполнять поля и меню. Это создает проблему для библиотек Python, которые могут извлекать данные только из статичных веб-страниц. Фактически, библиотека Requests – это не вариант, когда речь идет о JavaScript. Именно здесь на помощь приходит Selenium web scraping.
Эта веб-библиотека Python представляет собой инструмент автоматизации браузера с открытым исходным кодом (веб-драйвер), который позволяет автоматизировать такие процессы, как вход в платформу социальных сетей. Selenium широко используется для выполнения тестовых примеров или сценариев тестирования веб-приложений. Его преимущество при веб-скрейпинге заключается в способности инициировать рендеринг веб-страниц, как и любой браузер, с помощью JavaScript – стандартные веб-краулеры не могут использовать этот язык программирования. Тем не менее, в настоящее время он широко используется разработчиками.
Selenium требует наличия трех компонентов:
- Веб-браузер – Поддерживаемые браузеры: Chrome, Edge, Firefox и Safari.
- Драйвер для браузера – ссылки на драйверы см. на этой странице.
- Пакет selenium
Пакет selenium можно установить из терминала:
pip install selenium
После установки вы готовы импортировать соответствующий класс для браузера. После импорта необходимо будет создать объект класса. Обратите внимание, что для этого потребуется путь к исполняемому файлу драйвера. Пример для браузера Chrome выглядит следующим образом:
from selenium.webdriver import Chrome
driver = Chrome(executable_path='/path/to/driver')
Теперь любая страница может быть загружена в браузер с помощью метода get().
driver.get('https://oxylabs.io/blog')
Selenium позволяет использовать селекторы CSS и XPath для извлечения элементов. Следующий пример печатает все заголовки блогов, используя селекторы CSS:
blog_titles = driver.get_elements_by_css_selector(' h2.blog-card__content-title')
for title in blog_tiles:
print(title.text)
driver.quit() # closing the browser
По сути, выполняя JavaScript, Selenium работает с любым содержимым, отображаемым динамически, и впоследствии делает содержимое веб-страницы доступным для разбора встроенными методами или даже Beautiful Soup. Более того, он может имитировать поведение человека.
Единственным недостатком использования Selenium для веб-скрейпинга является то, что он замедляет процесс, поскольку сначала должен выполнить код JavaScript для каждой страницы, прежде чем сделать ее доступной для анализа. В результате он не подходит для крупномасштабного извлечения данных. Но если вы хотите извлекать данные в меньших масштабах или недостаток скорости не является недостатком, Selenium – отличный выбор.
Сравнение библиотек Python для веб-скрейпинга
Запросы | Beautiful Soup | lxml | Selenium | |
Назначение | Упростить выполнение HTTP-запросов | Парсинг | Парсинг | Упрощение выполнения HTTP-запросов |
Простота использования | Высокий | Высокий | Средний | Средний |
Скорость | Быстрая | Быстро | Очень быстро | Медленно |
Кривая обучения | Очень легкий (удобный для начинающих) | Очень легкий (удобный для начинающих) | Легко | Легко |
Документация | Отлично | Отлично | Хорошо | Хорошо |
Поддержка JavaScript | Нет | Нет | Нет | Да |
Использование процессора и памяти | Низкий | Низкий | Низкий | Высокая |
Размер поддерживаемого проекта веб-скрапинга | Большой и маленький | Большой и маленький | Большой и маленький | Маленький |
В этом учебнике по веб-скрейпингу на Python мы будем использовать три важные библиотеки – BeautifulSoup v4, Pandas и Selenium. В дальнейших шагах мы предполагаем успешную установку этих библиотек. Если вы получите сообщение “NameError: имя * не определено”, то, скорее всего, одна из этих библиотек была установлена неудачно.
Веб-драйверы и браузеры
Каждый веб-скрапер использует браузер, поскольку ему необходимо подключиться к целевому URL. Для целей тестирования мы настоятельно рекомендуем использовать обычный браузер (или не headless), особенно новичкам. Видеть, как написанный код взаимодействует с приложением, позволяет легко устранять неполадки и отлаживать, а также дает возможность лучше понять весь процесс.
Безголовые браузеры могут быть использованы позже, поскольку они более эффективны для сложных задач. В этом учебнике мы будем использовать браузер Chrome, хотя весь процесс практически идентичен работе с Firefox.
Чтобы начать работу, используйте предпочитаемую поисковую систему, чтобы найти “webdriver for Chrome” (или Firefox). Обратите внимание на текущую версию вашего браузера. Загрузите веб-драйвер, соответствующий версии вашего браузера.
Если применимо, выберите необходимый пакет, скачайте и распакуйте его. Скопируйте исполняемый файл драйвера в любую легкодоступную директорию. Все ли было сделано правильно, мы сможем узнать только позже.
Поиск уютного места для нашего веб-скрапера Python
Прежде чем перейти к программированию, необходимо сделать последний шаг: использовать хорошую среду кодирования. Существует множество вариантов, от простого текстового редактора, в котором достаточно просто создать файл *.py и записать код напрямую, до полнофункциональной IDE (интегрированной среды разработки).
Если у вас уже установлен Visual Studio Code, то выбор этой IDE будет самым простым вариантом. В противном случае, я бы настоятельно рекомендовал PyCharm для любого новичка, поскольку у него очень низкий барьер для входа и интуитивно понятный пользовательский интерфейс. Мы будем считать, что PyCharm будет использоваться до конца этого учебника по веб-скрейпингу.
В PyCharm щелкните правой кнопкой мыши на области проекта и выберите “New -> Python File”. Дайте ему красивое имя!
Импорт и использование библиотек
Пришло время использовать все те питоны, которые мы установили ранее:
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
PyCharm может отобразить эти импорты серым цветом, так как он автоматически помечает неиспользуемые библиотеки. Не принимайте его предложение удалить неиспользуемые библиотеки (по крайней мере, пока).
Мы должны начать с определения нашего браузера. В зависимости от веб-драйвера, который мы выбрали в разделе “WebDriver и браузеры”, мы должны ввести:
driver = webdriver.Chrome(executable_path='c:pathtowindowswebdriverexecutable.exe')
ИЛИ
driver = webdriver.Firefox(executable_path='/nix/path/to/webdriver/executable')
Выбор URL-адреса
Перед выполнением первого теста необходимо выбрать URL. Поскольку это руководство по веб-скрейпингу предназначено для создания элементарного приложения, мы настоятельно рекомендуем выбрать простой целевой URL:
- Избегайте данных, скрытых в элементах Javascript. Иногда они должны быть вызваны выполнением определенных действий, чтобы отобразить необходимые данные. Скраппинг данных из элементов Javascript требует более сложного использования Python и его логики.
- Избегайте соскабливания изображений. Изображения могут быть загружены непосредственно с помощью Selenium.
- Перед проведением любых действий по скраппингу убедитесь, что вы скрапируете общедоступные данные и никоим образом не нарушаете права третьих лиц. Также не забудьте проверить файл robots.txt на предмет указания.
Выберите целевую страницу, которую вы хотите посетить, и введите URL-адрес в параметр driver.get(‘URL’). Selenium требует, чтобы был указан протокол подключения. Поэтому к URL всегда необходимо присоединять “http://” или “https://”.
driver.get('https://your.url/here?yes=brilliant')
Попробуйте выполнить тест, нажав на зеленую стрелку в левом нижнем углу или щелкнув правой кнопкой мыши на среде кодирования и выбрав “Run”.
Если вы получаете сообщение об ошибке, в котором говорится, что файл отсутствует, проверьте, совпадает ли путь, указанный в драйвере “webdriver.*”, с расположением исполняемого файла webdriver. Если вы получите сообщение о несоответствии версии, скачайте заново правильный исполняемый файл webdriver.
Определение объектов и построение списков
Python позволяет программистам создавать объекты без задания точного типа. Объект можно создать, просто набрав его название и присвоив значение.
# Object is “results”, brackets make the object an empty list.
# We will be storing our data here.
results = []
Списки в Python упорядочены, изменяемы и допускают дублирование членов. Можно использовать и другие коллекции, такие как множества или словари, но списки наиболее просты в использовании. Пора создавать новые объекты!
# Add the page source to the variable `content`.
content = driver.page_source
# Load the contents of the page, its source, into BeautifulSoup
# class, which analyzes the HTML as a nested data structure and allows to select
# its elements by using various selectors.
soup = BeautifulSoup(content)
Прежде чем мы продолжим, давайте вспомним, как должен выглядеть наш код на данный момент:
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')
results = []
content = driver.page_source
soup = BeautifulSoup(content)
Попробуйте запустить приложение еще раз. Не должно быть никаких ошибок. Если таковые возникнут, несколько возможных вариантов устранения неполадок были описаны в предыдущих главах.
Извлечение данных с помощью нашего веб-скрапера Python
Наконец-то мы подошли к самой интересной и сложной части – извлечению данных из HTML-файла. Поскольку почти во всех случаях мы извлекаем небольшие фрагменты из разных частей страницы и хотим сохранить их в списке, мы должны обработать каждый небольшой фрагмент, а затем добавить его в список:
# Loop over all elements returned by the 'findAll' call. It has the filter 'attrs' given
# to it in order to limit the data returned to those elements with a given class only.
for element in soup.findAll(attrs={'class': 'list-item'}):
...
“soup.findAll” принимает широкий набор аргументов. Для целей этого руководства мы используем только “attrs” (атрибуты). Это позволяет нам сузить поиск, задав утверждение “если атрибут равен X, то…”. Классы легко найти и использовать, поэтому мы будем использовать именно их.
Прежде чем продолжить, давайте посетим выбранный URL в реальном браузере. Откройте источник страницы с помощью CTRL+U (Chrome) или щелкните правой кнопкой мыши и выберите “View Page Source”. Найдите “ближайший” класс, в котором вложены данные. Другой вариант – нажать F12, чтобы открыть DevTools и выбрать Element Picker. Например, данные могут быть вложены как:
<h4 class="title">
<a href="...">This is a Title</a>
</h4>
Тогда наш атрибут “class” будет иметь значение “title”. Если вы выбрали простую цель, в большинстве случаев данные будут вложены аналогично приведенному выше примеру. Сложные цели могут потребовать больше усилий для извлечения данных. Давайте вернемся к кодированию и добавим класс, который мы нашли в источнике:
# Change ‘list-item’ to ‘title’.
for element in soup.findAll(attrs={'class': 'title'}):
...
Теперь наш цикл будет перебирать все объекты с классом “title” в источнике страницы. Мы обработаем каждый из них:
name = element.find('a')
Давайте посмотрим, как наш цикл проходит через HTML:
<h4 class="title">
<a href="...">This is a Title</a>
</h4>
Наш первый оператор (в самом цикле) находит все элементы, соответствующие тегам, атрибут “class” которых содержит “title”. Затем мы выполняем другой поиск внутри этого класса. Следующий поиск находит все теги <a>
в документе (<a>
включается, а частичные совпадения, такие как <span>
– нет). Наконец, объект присваивается переменной “name”.
Затем мы могли бы присвоить имя объекта нашему ранее созданному массиву списков “results”, но это привело бы к тому, что весь тег <a href...>
с текстом внутри него оказался бы в одном элементе. В большинстве случаев нам нужен только сам текст без дополнительных тегов.
# Add the object of “name” to the list “results”.
Наш цикл просмотрит весь источник страницы, найдет все вхождения перечисленных выше классов, а затем добавит вложенные данные в наш список:
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')
results = []
content = driver.page_source
soup = BeautifulSoup(content)
for element in soup.findAll(attrs={'class': 'title'}):
name = element.find('a')
results.append(name.text)
Обратите внимание, что два утверждения после цикла имеют отступ. Циклы требуют отступов для обозначения вложенности. Любой последовательный отступ будет считаться законным. Циклы без отступов выдадут сообщение “IndentationError”, при этом на ошибочное утверждение будет указывать “стрелка”.
Экспорт данных
Даже если при выполнении нашей программы не возникнет синтаксических ошибок или ошибок времени выполнения, все равно могут возникнуть семантические ошибки. Необходимо проверить, действительно ли мы получаем данные, назначенные нужному объекту, и правильно ли они перемещаются в массив.
Один из самых простых способов проверить, правильно ли собираются данные, которые вы получили во время предыдущих шагов, – использовать “print”. Поскольку массивы имеют множество различных значений, часто используется простой цикл, чтобы выделить каждую запись в отдельную строку в выводе:
for x in results:
print(x)
Как “print”, так и “for” должны быть понятны на данном этапе. Мы запускаем этот цикл только для быстрого тестирования и отладки. Вполне возможно распечатать результаты напрямую:
print(results)
Пока что наш код должен выглядеть следующим образом:
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')
results = []
content = driver.page_source
soup = BeautifulSoup(content)
for a in soup.findAll(attrs={'class': 'class'}):
name = a.find('a')
if name not in results:
results.append(name.text)
for x in results:
print(x)
Запуск нашей программы теперь не должен вызывать ошибок и отображать полученные данные в окне отладчика. Хотя “print” отлично подходит для тестирования, он не так хорош для разбора и анализа данных.
Вы могли заметить, что “import pandas” пока что остается серым. Наконец-то мы начнем использовать библиотеку по назначению. Я рекомендую пока убрать цикл “print”, так как мы будем делать нечто подобное, но перемещать данные в файл csv.
df = pd.DataFrame({'Names': results})
df.to_csv('names.csv', index=False, encoding='utf-8')
Наши два новых утверждения основаны на библиотеке pandas. Наш первый оператор создает переменную “df” и превращает ее объект в двумерную таблицу данных. “Names” – это имя нашего столбца, а “results” – это список, который будет выведен на печать. Обратите внимание, что pandas может создавать несколько колонок, просто у нас нет достаточного количества списков, чтобы использовать эти параметры (пока).
Наш второй оператор перемещает данные переменной “df” в файл определенного типа (в данном случае “csv”). Наш первый параметр присваивает имя нашему будущему файлу и расширение. Добавление расширения необходимо, так как “pandas” в противном случае выведет файл без расширения, и его придется менять вручную. “index” может быть использован для присвоения определенных начальных номеров столбцам. “Кодировка” используется для сохранения данных в определенном формате. UTF-8 будет достаточно почти во всех случаях.
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')
results = []
content = driver.page_source
soup = BeautifulSoup(content)
for a in soup.findAll(attrs={'class': 'class'}):
name = a.find('a')
if name not in results:
results.append(name.text)
df = pd.DataFrame({'Names': results})
df.to_csv('names.csv', index=False, encoding='utf-8')
Никаких импортов теперь не должно быть, а запуск нашего приложения должен вывести файл “names.csv” в каталог нашего проекта. Обратите внимание, что предупреждение “Guessed At Parser” остается. Мы можем убрать его, установив сторонний парсер, но для целей этого учебника по веб-скрейпингу на Python отлично подойдет вариант HTML по умолчанию.
Больше списков. Больше!
Во многих операциях веб-скрейпинга необходимо получить несколько наборов данных. Например, извлечение только названий товаров, перечисленных на сайте электронной коммерции, редко бывает полезным. Чтобы собрать значимую информацию и сделать из нее выводы, необходимо как минимум две точки данных.
Для целей этого учебника мы попробуем несколько иной подход. Поскольку получение данных из того же класса будет означать лишь добавление в дополнительный список, мы должны попытаться извлечь данные из другого класса, но при этом сохранить структуру нашей таблицы.
Очевидно, что нам понадобится еще один список для хранения данных.
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
driver = ``webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')`
`results = []
other_results = []
for b in soup.findAll(attrs={'class': 'otherclass'}):`
`# Assume that data is nested in ‘span’.
name2 = b.find('span')
other_results.append(name.text)
Поскольку мы будем извлекать дополнительную точку данных из другой части HTML, нам понадобится дополнительный цикл. При необходимости мы также можем добавить еще одно условие “if” для контроля дубликатов записей:
Наконец, нам нужно изменить способ формирования таблицы данных:
df = pd.DataFrame({'Names': results, 'Categories': other_results})
Пока что самая новая итерация нашего кода должна выглядеть примерно так:
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')
results = []
other_results = []
content = driver.page_source
for a in soup.findAll(attrs={'class': 'class'}):
name = a.find('a')
if name not in results:
results.append(name.text)
for b in soup.findAll(attrs={'class': 'otherclass'}):
name2 = b.find('span')
other_results.append(name.text)
df = pd.DataFrame({'Names': results, 'Categories': other_results})
df.to_csv('names.csv', index=False, encoding='utf-8')
Если вам повезет, то выполнение этого кода не приведет к ошибке. В некоторых случаях “pandas” выдаст сообщение “ValueError: arrays must all be the same length”. Проще говоря, длина списков “results” и “other_results” неодинакова, поэтому pandas не может создать двумерную таблицу.
Существуют десятки способов устранения этого сообщения об ошибке. От заполнения самого короткого списка “пустыми” значениями, до создания словарей, до создания двух серий и их перечисления. Мы воспользуемся третьим вариантом:
series1 = pd.Series(results, name = 'Names')
series2 = pd.Series(other_results, name = 'Categories')
df = pd.DataFrame({'Names': series1, 'Categories': series2})
df.to_csv('names.csv', index=False, encoding='utf-8')
Обратите внимание, что данные не будут совпадать, так как списки имеют неодинаковую длину, но создание двух серий – самое простое решение, если нужны две точки данных. Наш окончательный код должен выглядеть примерно так:
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable')
driver.get('https://your.url/here?yes=brilliant')
results = []
other_results = []
content = driver.page_source
soup = BeautifulSoup(content)
for a in soup.findAll(attrs={'class': 'class'}):
name = a.find('a')
if name not in results:
results.append(name.text)
for b in soup.findAll(attrs={'class': 'otherclass'}):
name2 = b.find('span')
other_results.append(name.text)
series1 = pd.Series(results, name = 'Names')
series2 = pd.Series(other_results, name = 'Categories')
df = pd.DataFrame({'Names': series1, 'Categories': series2})
df.to_csv('names.csv', index=False, encoding='utf-8')
Его запуск должен создать файл csv с именем “names” с двумя колонками данных.
Веб-скрейпинг с помощью лучших практик Python
Теперь наш первый веб-скрапер должен быть полностью функциональным. Конечно, он настолько базовый и упрощенный, что для серьезного сбора данных потребуется значительная модернизация. Прежде чем переходить на новые пастбища, я настоятельно рекомендую поэкспериментировать с некоторыми дополнительными функциями:
- Создать согласованное извлечение данных, создав цикл, который будет создавать списки четной длины.
- Соскребать несколько URL за один раз. Существует множество способов реализовать такую функцию. Один из самых простых вариантов – просто повторить приведенный выше код и каждый раз менять URL. Это было бы довольно скучно. Создайте цикл и массив URL для посещения.
- Другой вариант – создать несколько массивов для хранения разных наборов данных и вывести их в один файл с разными строками. Скраппинг нескольких различных типов информации одновременно является важной частью сбора данных электронной коммерции.
- После запуска удовлетворительного веб-скрапера вам больше не нужно наблюдать, как браузер выполняет свои действия. Приобретите безголовые версии браузеров Chrome или Firefox и используйте их для сокращения времени загрузки.
- Создайте шаблон для скраппинга. Подумайте, как обычный пользователь просматривает Интернет, и попытайтесь автоматизировать его действия. Определенно потребуются новые библиотеки. Используйте “import time” и “from random import randint” для создания времени ожидания между страницами. Добавьте “scrollto()” или используйте определенные клавиши для перемещения по браузеру. Почти невозможно перечислить все возможные варианты, когда дело доходит до создания шаблона скраппинга.
- Создайте процесс мониторинга. Данные на некоторых сайтах могут быть чувствительны ко времени (или даже к пользователю). Попробуйте создать длительный цикл, который будет перепроверять определенные URL-адреса и собирать данные через заданные промежутки времени. Убедитесь, что полученные данные всегда свежие.
- Используйте библиотеку Python Requests. Requests – это мощный актив в любом наборе инструментов для веб-скрейпинга, поскольку она позволяет оптимизировать HTTP-методы, отправляемые на серверы.
- Наконец, интегрируйте прокси в ваш веб-скрепер. Использование источников запросов, специфичных для конкретного местоположения, позволяет получать данные, которые в противном случае могут быть недоступны.
Заключение
Итак, в этом обширном руководстве по Python мы описали все шаги, которые необходимо выполнить, чтобы начать работу с простым приложением.
Но дальше вы будете действовать самостоятельно. Создание веб-скрейперов на Python, сбор данных и получение выводов из больших объемов информации – это интересный и сложный процесс.
Мы надеемся, что это руководство было ценным для вас и призываем вас следить за новыми информативными постами от Oxylabs!