Создание парсеров с помощью Scrapy и Python
Научимся писать парсеры с помощью Scrapy, мощного фреймворка для извлечения, обработки и хранения данных.
В этом руководстве вы узнаете, как использовать фреймворк Python, Scrapy, с помощью которого можно обрабатывать большие объемы данных. Обучение будет основано на процессе построения скрапера для интернет-магазина Aliexpress.com.
Базовые знания HTML и CSS помогут лучше и быстрее освоить материал.
Обзор Scrapy
Веб-скрапинг (парсинг) стал эффективным путем извлечения информации из сети для последующего принятия решений и анализа. Он является неотъемлемым инструментом в руках специалиста в области data science. Дата сайентисты должны знать, как собирать данные с веб-страниц и хранить их в разных форматах для дальнейшего анализа.
Любую страницу в интернете можно исследовать в поисках информации, а все, что есть на странице — можно извлечь. У каждой страницы есть собственная структура и веб-элементы, из-за чего необходимо писать собственных сканеров для каждой страницы.
Scrapy предоставляет мощный фреймворк для извлечения, обработки и хранения данных.
Scrapy использует Spiders — автономных сканеров с определенным набором инструкций. С помощью фреймворка легко разработать даже крупные проекты для скрапинга, так чтобы и другие разработчики могли использовать этот код.
Scrapy vs. Beautiful Soup
В этом разделе будет дан обзор одного из самых популярных инструментов для парсинга, BeautifulSoup, и проведено его сравнение со Scrapy.
Scrapy — это Python-фреймворк, предлагающий полноценный набор инструментов и позволяющий разработчикам не думать о настройке кода.
BeautifulSoup также широко используется для веб-скрапинга. Это пакет Python для парсинга документов в форматах HTML и XML и извлечения данных из них. Он доступен для Python 2.6+ и Python 3.
Вот основные отличия между ними:
Scrapy | BeautifulSoup |
---|---|
Функциональность | |
Scrapy — это самый полный набор инструментов для загрузки веб-страниц, их обработки и сохранения в файлы и базы данных | BeautifulSoup — это в принципе просто парсер HTML и XML, требующий дополнительных библиотек, таких как requests и urlib2 для открытия ссылок и сохранения результатов. |
Кривая обучения | |
Scrapy — это движущая сила веб-сканирования, предлагающая массу способов парсинга страниц. Обучение тому, как он работает, требует много времени, но после освоения процесс сканирования превращается в одну строку кода. Потребуется время, чтобы стать экспертом в Scrapy и изучить все его особенности | BeautifulSoup относительно прост для понимания новичкам в программировании и позволяет решать маленькие задачи за короткий срок. |
Скорость и нагрузка | |
Scrapy с легкостью выполняет крупную по объему работу. Он может сканировать несколько ссылок одновременно менее чем за минуту в зависимости от общего количества. Это происходит плавно благодаря Twister, который работает асинхронно (без блокировки) | BeautifulSoup используется для простого и эффективного парсинга. Он работает медленнее Scrapy, если не использовать multiprocessing . |
Расширяемость | |
Scrapy предоставляет функциональность Item pipelines , с помощью которой можно писать функции для веб-сканера. Они будут включать инструкции о том, как робот должен проверять, удалять и сохранять данные в базу данных. Spider Contracts используются для проверки парсеров, благодаря чему можно создавать как базовые, так и глубокие парсеры. Он же позволяет настраивать множество переменных: повторные попытки, перенаправление и т. д. | Если проект не предполагает большого количества логики, BeautifulSoup отлично для этого подходит, но если нужна настраиваемость, например прокси, управление куки и распределение данных, то Scrapy справляется лучше. |
Синхронность означает, что необходимо ждать, пока процесс завершит работу, прежде чем начинать новый, а асинхронный позволяет переходить к следующему процессу, пока предыдущий еще не завершен.
Установка Scrapy
С установленным Python 3.0 (и новее) при использовании Anaconda можно применить команду conda для установки scrapy . Напишите следующую команду в Anaconda:
Чтобы установить Anaconda, посмотрите эти руководства PythonRu для Mac и Windows.
Также можно использовать установщик пакетов pyhton pip. Это работает в Linux, Mac и Windows:
Scrapy Shell
Scrapy предоставляет оболочку веб-сканера Scrapy Shell, которую разработчики могут использовать для проверки своих предположений относительно поведения сайта. Возьмем в качестве примера страницу с планшетами на сайте Aliexpress. С помощью Scrapy можно узнать, из каких элементов она состоит и понять, как это использовать в конкретных целях.
Откройте командную строку и напишите следующую команду:
При использовании Anaconda можете написать эту же команду прямо в anaconda prompt . Вывод будет выглядеть приблизительно вот так:
Необходимо запустить парсер на странице с помощью команды fetch в оболочке. Он пройдет по странице, загружая текст и метаданные.
fetch(“https://www.aliexpress.com/category/200216607/tablets.html”)
Примечание: всегда заключайте ссылку в кавычки, одинарные или двойные
Парсер возвращает response (ответ), который можно посмотреть с помощью команды view(response) . А страница откроется в браузере по умолчанию.
С помощью команды print(response.text) можно посмотреть сырой HTML.
Отобразится скрипт, который генерирует страницу. Это то же самое, что вы видите по нажатию правой кнопкой мыши в пустом месте и выборе «Просмотр кода страница» или «Просмотреть код». Но поскольку нужна конкретная информация, а не целый скрипт, с помощью инструментов разработчика в браузере необходимо определить требуемый элемент. Возьмем следующие элементы:
- Название планшета
- Цена планшета
- Количество заказов
- Имя магазина
Нажмите правой кнопкой по элементу и кликните на «Просмотреть код».
Инструменты разработчика сильно помогут при работе с парсингом. Здесь видно, что есть тег с классом item-title , а сам текст включает название продукта:
Использование CSS-селекторов для извлечения
Извлечь эту информацию можно с помощью атрибутов элементов или CSS-селекторов в виде классов. Напишите следующее в оболочке Scrapy, чтобы получить имя продукта:
extract_first() извлекает первый элемент, соответствующий селектору css. Для извлечения всех названий нужно использовать extract() :
Следующий код извлечет ценовой диапазон этих продуктов:
То же можно повторить для количества заказов и имени магазина.
Использование XPath для извлечения
XPath — это язык запросов для выбора узлов в документах типа XML. Ориентироваться по документу можно с помощью XPath. Scrapy использует этот же язык для работы с объектами документа HTML. Использованные выше CSS-селекторы также конвертируются в XPath, но в большинстве случаев CSS очень легко использовать. И тем не менее важно значить, как язык работает в Scrapy.
Откройте оболочку и введите fetch(«https://www.aliexpress.com/category/200216607/tablets.html/») как и раньше. Попробуйте написать следующий код:
Он покажет весь код в теге . / указывает на прямого потомка узла. Если нужно получить теги
Для XPath важно научиться понимать, как используются / и // , чтобы ориентироваться в дочерних узлах.
Если необходимо получить все теги
Можно и дальше фильтровать начальные узлы, чтобы получить нужные узлы с помощью атрибутов и их значений. Это синтаксис использования классов и их значений.
Используйте text() для извлечения всего текста в узлах
Создание проекта Scrapy и собственного робота (Spider)
Парсинг хорошо подходит для создания агрегатора, который будет использоваться для сравнения данных. Например, нужно купить планшет, предварительно сравнив несколько продуктов и их цены. Для этого можно исследовать все страницы и сохранить данные в файл Excel. В этом примере продолжим парсить aliexpress.com на предмет информации о планшетах.
Создадим робота (Spider) для страницы. В первую очередь необходимо создать проект Scrapy, где будут храниться код и результаты. Напишите следующее в терминале или anaconda.
Это создаст скрытую папку в директории с Python или Anaconda по умолчанию. Она будет называться aliexpress , но можно выбрать любое название. Структура директории следующая:
Файл/папка | Назначение |
---|---|
scrapy.cfg | Файл настройки развертывания |
aliexpress/ | Модуль Python проекта, отсюда импортируется код |
__init.py__ | Файл инициализации |
items.py | Python файл с элементами проекта |
pipelines.py | Файл, который содержит пайплайн проекта |
settings.py | Файл настроек проекта |
spiders/ | Папка, в которой будут храниться роботы |
__init.py__ | Файл инициализации |
После создания проекта нужно перейти в новую папку и написать следующую команду:
Это создает файл шаблона с названием aliexpress_tables.py в папке spiders , как и было описано выше. Вот код из этого файла:
В коде можно увидеть name, allowed_domains, start_urls и функцию parse .
- name — это имя робота. Удачные и правильно подобранные имена позволят проще отслеживать всех имеющихся роботов. Они должны быть уникальны, ведь именно они используются для запуска командой scrapy crawl name_of_spider .
- allowed_domains (опционально) — список разрешенных для парсинга доменов. Запрос к URL, не указанным в этом списке, не будет выполнен. Он должен включать только домен сайта (например, aliexpress.com), а не целый URL, указанный в start_urls , иначе возникнут ошибки.
- start_urls — запрос к упомянутым URL. С них робот начнет проводить поиск, если конкретный URL не указан. Первыми загруженными страницами будут те, что указаны здесь. Последующие запросы будут генерироваться последовательно из данных, сохраненных в начальных URL.
- parse — эта функция вызывается, когда парсинг URL успешно выполнен. Ее еще называют функцией обратного вызова. Response (используемый в оболочке Scrapy) возвращается как результат парсинга, передается этой функции, а внутри нее находится код для извлечения.
можно использовать функцию parse() из BeautifulSoup в Scrapy для парсинга HTML-документа.
Примечание: извлечь данные можно с помощью css-селекторов, используя как response.css() , так и XPath (XML), что позволит получить доступ к дочерним элементам. Пример response.xpath() будет описан в коде функции pass() .
Добавим изменения в файл aliexpress_tablet.py . В start_urls теперь еще один URL. Логику извлечения можно указать в функции pass() :
zip() берет n элементов итерации и возвращает список кортежей. Элемент с индексом i в кортеже создается с помощью элемента с индексом i каждого элемента итерации.
yield используется каждый раз при определении функции генератора. Функция генератора — это обычная функция, отличие которой в том, что она использует yield вместо return . yield используется каждый раз, когда вызывающая функция требует значения. Функция с yield сохраняет свое локальное состояние при выполнении и продолжает исполнение с того момента, где остановилась после того, как выдала одно значение. В данном случае yield возвращает Scrapy сгенерированный словарь, который будет обработан и сохранен.
Теперь можно запустить робота и посмотреть результат:
Экспорт данных
Данные должны быть представлены в форматах CSV или JSON, чтобы их можно было анализировать. Этот раздел руководства посвящен тому, как получить такой файл из имеющихся данных.
Для сохранения файла CSV откройте settings.py в папке проекта и добавьте следующие строки:
После сохранения settings.py снова запустите scrapy crawl aliexpress_tablets в папке проекта. Будет создан файл aliexpress.csv .
Примечание: при каждом запуске паука он будет добавлять файл.
- FEED_FORMAT — настройка необходимого формата сохранения данных. Поддерживаются следующие:
- FEED_URI — местоположение файла. Его можно сохранить в локальном хранилище или по FTP.
Feed Export также может добавить временную метку в имя файла. Или его можно использовать для выбора папки, куда необходимо сохранить данные.
- %(time)s — заменяется на временную метку при создании ленты
- %(name)s — заменяется на имя робота
- Сохранить по FTP используя по одной папке на робота:
Изменения для FEED, сделанные в settings.py , будут применены ко всем роботам в проекте. Можно указать и отдельные настройки для конкретного робота, которые перезапишут те, что есть в settings.py .
response.url вернет URL страницы, с которой был сгенерирован ответ. После запуска парсера с помощью scrapy crawl aliexpress_tables можно просмотреть json-файл в каталоге проекта.
Следующие страницы, пагинация
Вы могли обратить внимание на две ссылки в start_urls . Вторая — это страница №2 результатов поиска планшетов. Добавлять все ссылки непрактично. Робот должен быть способен исследовать все страницы сам, а в start_urls указывается только одна стартовая точка.
Если у страницы есть последующие, в ее конце всегда будут навигационные элементы, которые позволяют перемещаться вперед и назад.
Запомните! У каждой веб-страницы собственная структура. Нужно будет изучить ее, чтобы получить желаемый элемент. Всегда экспериментируйте с response.css(SELECTOR) в Scrapy Shell, прежде чем переходить к коду.
Измените aliexpress_tabelts.py следующим образом:
- Сначала извлекается ссылка следующей страницы с помощью next_page = response.css(NET_PAGE_SELECTOR).extract_first() , а потом, если переменная next_page получает ссылку и она не пустая, запускается тело if .
- response.urljoin(next_page) — метод parse() будет использовать этот метод для построения нового URL и получения нового запроса, который будет позже направлен вызову.
- После получения нового URL он парсит ссылку, исполняя тело for и снова начинает искать новую страницу. Так будет продолжаться до тех пор, пока страницы не закончатся.
Теперь можно просто расслабиться и смотреть, как робот парсит страницы. Этот извлечет все из последующих страниц. Процесс займет много времени, а размер файла будет 1,1 МБ.
Scrapy сделает для вас все!
Из этого руководства вы узнали о Scrapy, о его отличиях от BeautifulSoup, о Scrapy Shell и о создании собственных проектов. Scrapy перебирает на себя весь процесс написания кода: от создания файлов проекта и папок до обработки дублирующихся URL. Весь процесс парсинга занимает минуты, а Scrapy предоставляет поддержку всех распространенных форматов данных, которые могут быть использованы в других программах.
Теперь вы должны лучше понимать, как работает Scrapy, и как использовать его в собственных целях. Чтобы овладеть Scrapy на высоком уровне, нужно разобраться со всеми его функциями, но вы уже как минимум знаете, как эффективно парсить группы веб-страниц.
Источник статьи: http://pythonru.com/biblioteki/sozdanie-parserov-s-pomoshhju-scrapy-i-python