рекомендации

вторник, 10 марта 2020 г.

Создание веб-пауков с использованием Scrapy for Python

Перевод. Оригинал: Making Web Crawlers Using Scrapy for Python

Из этого руководства вы узнаете, как использовать Scrapy, который является фреймворком Python, с помощью которого вы можете обрабатывать большие объемы данных! Вы изучите Scrapy, создав веб-паук для магазина AliExpress.com.

Базовые знания HTML и CSS помогут вам лучше понять эту статью. Прочтите эту статью, чтобы узнать больше о HTML и CSS.

Обзор Scrapy



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

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

Scrapy предоставляет мощную основу для извлечения данных, их обработки и последующего сохранения.

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

Scrapy Vs. BeautifulSoup

В этом разделе вы познакомитесь с одним из самых популярных инструментов для просмотра веб-страниц под названием BeautifulSoup и сравните его с Scrapy.

Scrapy - это Python-фреймворк для парсинга, который предоставляет полный пакет для разработчиков, не беспокоясь о поддержке кода.

BeautifulSoup также широко используется для парсинга. Это пакет Python для анализа документов HTML и XML и извлечения данных из них. Он доступен для Python 2.6+ и Python 3.

Вот несколько различий между ними:

Функциональность

Scrapy - это полный пакет для загрузки веб-страниц, их обработки и сохранения в файлах и базах данных. 
BeautifulSoup - это, в основном, анализатор HTML и XML, требующий дополнительных библиотек, таких как requests, urlib2 для открытия URL-адресов и сохранения результата.

Кривая обучения

Scrapy - это мощный инструмент для парсинга веб-страниц и предлагает множество способов парсинга. Требуется больше времени, чтобы понять, как работает Scrapy, но после изучения это облегчает процесс создания веб-сканеров и запуска их из командной строки. Чтобы стать экспертом, может потребоваться некоторая практика и время, чтобы изучить все функциональные возможности. 
BeautifulSoup относительно прост для понимания новичков в программировании и может выполнять мелкие задачи в кратчайшие сроки.

Скорость и нагрузка

С помощью Scrapy можно легко выполнить большую работу. Он может сканировать группу URL-адресов не более, чем за минуту, в зависимости от размера группы, и делает это очень плавно, так как использует Twister, который работает асинхронно. BeautifulSoup эффективно используется для простого парсинга. Это медленнее, чем Scrapy, если вы не используете многопроцессорность.

Расширение функциональности

Scrapy предоставляет конвейеры Item, которые позволяют вам писать функции в вашем пауке, которые могут обрабатывать ваши данные, например выполнять проверку данных, удаление данных и сохранение данных в базе данных. Он предоставляет Contracts для тестирования ваших пауков, а также позволяет создавать типовые и глубокие сканеры. Это позволяет вам управлять множеством переменных, таких как повторные попытки, перенаправление и так далее. 
Если проект не требует больших усложнений, подойдет BeautifulSoup, но если вам нужно много настроек, таких как прокси, управление файлами cookie и конвейерами данных, Scrapy - лучший вариант.

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


Установка Scrapy



С установленным Python 3.0 (и выше), если вы используете anaconda, вы можете использовать conda для установки scrapy. В командной строке anaconda введите следующую команду:

conda install -c conda-forge scrapy

Кроме того, вы можете использовать pip. Это работает для Linux, Mac и Windows:

pip install scrapy

Scrapy Shell

Scrapy также предоставляет веб-оболочку для сканирования, называемую Scrapy Shell, которую разработчики могут использовать для проверки своих предположений о поведении сайта. Давайте возьмем веб-страницу для планшетов на сайте AliExpress. Вы можете использовать оболочку Scrapy, чтобы увидеть, какие компоненты возвращает веб-страница и как их использовать в соответствии с вашими требованиями.

Откройте вашу командную строку и напишите следующую команду:

scrapy shell

Если вы используете anaconda, вы также можете написать приведенную выше команду в приглашении anaconda. Ваш вывод в командной строке или приглашении anaconda будет выглядеть примерно так:


Вы должны запустить сканер на веб-странице, используя команду fetch в оболочке Scrapy. Сканер или паук просматривает веб-страницу, загружая ее текст и метаданные.

fetch(https://www.aliexpress.com/category/200216607/tablets.html)

Примечание: всегда заключайте URL в кавычки, работают одинарные и двойные кавычки.

Вывод будет следующим:


Сканер возвращает ответ, который можно просмотреть с помощью команды view (response) в оболочке:

view(response)

И веб-страница будет открыта в браузере по умолчанию.



Вы можете просмотреть необработанный HTML-скрипт с помощью следующей команды в оболочке Scrapy:

print(response.text)


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

    Tablet name
    Tablet price
    Number of orders
    Name of store

Щелкните правой кнопкой мыши на элементе, который вам нужен, и нажмите «inspect», как показано ниже:



Инструменты разработчика браузера очень помогут вам в поиске в Интернете. Вы можете видеть, что это тег с классом product, а текст содержит название продукта:



Использование селекторов CSS для извлечения информации

Вы можете извлечь это, используя атрибуты элемента или селектор CSS, как классы. Напишите следующее в оболочке Scrapy, чтобы извлечь название продукта:
response.css(".product::text").extract_first()

Вывод:


extract_first() извлекает первый элемент, который удовлетворяет селектору css. Если вы хотите извлечь все названия продуктов, используйте extract():

response.css(".product::text").extract()


Следующий код извлечет ценовой диапазон продуктов:

response.css(".value::text").extract()


Точно так же можно попробовать с количеством заказов и названием магазина.

Использование XPath для извлечения информации

XPath - это язык запросов для выбора узлов в документе XML. Вы можете перемещаться по документу XML, используя XPath. За кулисами Scrapy использует Xpath для перехода к элементам документа HTML. Селекторы CSS, которые вы использовали выше, также конвертируются в XPath, но во многих случаях CSS очень прост в использовании. Но вы должны знать, как работает XPath в Scrapy.

Перейдите в свою оболочку Scrapy и напишите

fetch(https://www.aliexpress.com/category/200216607/tablets.html/)

так же, как и раньше. Попробуйте следующие фрагменты кода:

response.xpath('/html').extract()

Это покажет вам весь код под тегом . / означает прямого потомка узла. Если вы хотите получить теги
под тегом html, напишите:

response.xpath('/html//div').extract()

Для XPath вы должны научиться понимать использование / и //, чтобы знать, как перемещаться по дочерним узлам. Здесь полезное руководство для узлов XPath и несколько примеров, которые можно попробовать.

Если вы хотите получить все теги, вы можете сделать это, развернув файл без использования /html:

response.xpath("//div").extract()

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

response.xpath("//div[@class='quote']/span[@class='text']").extract()

response.xpath("//div[@class='quote']/span[@class='text']/text()").extract()

Используйте text(), чтобы извлечь весь текст внутри узлов

Рассмотрим следующий HTML-код:



Вы хотите получить текст внутри тега , который является дочерним узлом контейнера
класса site-notice-container. Вы можете сделать это следующим образом:

response.xpath('//div[@class="site-notice-container container"]/a[@class="notice-close"]/text()').extract()



Создание проекта Scrapy и пользовательского паука

Парсинг можно использовать для создания агрегатора, который можно использовать для сравнения данных. Например, если вы хотите купить планшет и сравнить товары и цены, вы можете сканировать нужные страницы и сохранять их в файле Excel. Здесь вы будете сканировать aliexpress.com для информации о планшетах.

Теперь вы создадите пользовательского паука для той же страницы. Во-первых, вам нужно создать проект Scrapy, в котором будут храниться ваш код и результаты. Введите следующую команду в командной строке или в командной строке anaconda.

scrapy startproject aliexpress


Эта команда создаст скрытую папку в вашей установке по умолчанию Python или Anaconda. Название папки будет aliexpress. Вы можете дать ей любое имя. Вы можете просматривать содержимое папки напрямую через проводник. Ниже приведена структура папки:




Файл/папка
Назначение
scrapy.cfg
Файл конфигурации
aliexpress/
Модуль проекта Python, вы импортируете свой код отсюда
__init.py__
Файл инициализации
items.py
Файл элементов проекта
pipelines.py
Файл конвейеров проекта
settings.py
Файл настроек проекта
spiders/
Каталог, куда вы позже положите своих пауков
__init.py__
Файл инициализации

Создав проект, вы перейдете во вновь созданный каталог и напишите следующую команду:

[scrapy genspider aliexpress_tablets]
(https://www.aliexpress.com/category/200216607/tablets.html)


Она создает файл шаблона с именем aliexpress_tablets.py в каталоге spiders, как обсуждалось выше. Код в этом файле выглядит следующим образом:

import scrapy class AliexpressTabletsSpider(scrapy.Spider): name = 'aliexpress_tablets' allowed_domains = ['aliexpress.com'] start_urls = ['https://www.aliexpress.com/category/200216607/tablets.html'] def parse(self, response): pass

В приведенном выше коде вы можете увидеть name, allow_domains, sstart_urls и функцию parse.

name: имя это имя паука. Правильные имена помогут вам отследить всех пауков, которых вы делаете. Имена должны быть уникальными, так как они будут использоваться для запуска паука, когда используется scrapy crawl name_of_spider.

allow_domains (необязательно): необязательный список python, содержащий домены, для которых разрешено сканирование. Запросы на URL-адреса, отсутствующие в этом списке, не будут сканироваться. Это должно включать только домен сайта (пример: aliexpress.com), а не весь URL, указанный в start_urls, в противном случае вы получите предупреждения.

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

parse (self, response): эта функция будет вызываться при каждом успешном сканировании URL. Она также называется функцией обратного вызова. Ответ (используемый в оболочке Scrapy), возвращаемый в результате сканирования, передается в эту функцию, и вы пишете в нее код извлечения!

Информация: Вы можете использовать BeautifulSoup внутри функции parse() паука Scrapy для анализа html-документа.

Примечание. Вы можете извлекать данные с помощью селекторов css с помощью response.css(), как описано в разделе оболочки scrapy, но также с помощью XPath(XML), который позволяет получить доступ к дочерним элементам. Вы увидите пример response.xpath() в коде, отредактированном в функции pass().

Вы внесете изменения в файл aliexpress_tablet.py. Я добавил еще один URL в start_urls. Вы можете добавить логику извлечения в функцию pass (), как показано ниже:

# -*- coding: utf-8 -*- import scrapy class AliexpressTabletsSpider(scrapy.Spider): name = 'aliexpress_tablets' allowed_domains = ['aliexpress.com'] start_urls = ['https://www.aliexpress.com/category/200216607/tablets.html', 'https://www.aliexpress.com/category/200216607/tablets/2.html?site=glo&g=y&tag='] def parse(self, response): print("procesing:"+response.url) #Extract data using css selectors product_name=response.css('.product::text').extract() price_range=response.css('.value::text').extract() #Extract data using xpath orders=response.xpath("//em[@title='Total Orders']/text()").extract() company_name=response.xpath("//a[@class='store $p4pLog']/text()").extract() row_data=zip(product_name,price_range,orders,company_name) #Making extracted data row wise for item in row_data: #create a dictionary to store the scraped info scraped_info = { #key:value 'page':response.url, 'product_name' : item[0], 'price_range' : item[1], 'orders' : item[2], 'company_name' : item[3], } #yield or give the scraped info to scrapy yield scraped_info

Информация: zip() принимает n итераций и возвращает список кортежей. i-й элемент кортежа создается с использованием i-го элемента из каждой итерации. 

Ключевое слово yield используется всякий раз, когда вы определяете функцию генератора. Функция генератора похожа на обычную функцию, за исключением того, что она использует ключевое слово yield вместо return. Ключевое слово yield используется всякий раз, когда вызывающей функции требуется значение, а функция, содержащая yield, сохранит свое локальное состояние и продолжит выполнение с того места, на котором остановилась после передачи значения вызывающей функции. Здесь yield выдает сгенерированный словарь Scrapy, который обработает и сохранит!

Теперь вы можете запустить паука:

scrapy crawl aliexpress_tablets

Вы увидите длинный вывод в командной строке, как показано ниже:




Экспорт данных

Вам нужно будет представить данные в формате CSV или JSON, чтобы вы могли в дальнейшем использовать их для анализа. В этом разделе вы узнаете, как сохранить файлы CSV и JSON для этих данных.

Чтобы сохранить файл CSV, откройте файл settings.py из каталога проекта и добавьте следующие строки:

FEED_FORMAT="csv" FEED_URI="aliexpress.csv"

После сохранения файла settings.py повторно запустите программу scrapy crawl aliexpress_tablets в каталоге вашего проекта.


Файл CSV будет выглядеть так:



Примечание. Каждый раз, когда вы запускаете паука, он добавляет файл.

    FEED_FORMAT [5]: Это устанавливает формат, который вы хотите сохранить данные. Поддерживаемые форматы:

         + JSON
         + CSV
         + JSON Lines
         + XML

    FEED_URI [5]: Это дает местоположение файла. Вы можете хранить файл в локальном хранилище файлов или на FTP-сервере.
Feed Export Scrapy также может добавить временную метку и имя паука к имени вашего файла, или вы можете использовать их для определения каталога, в котором вы хотите сохранить данные.

%(time)s: заменяется временной меткой при создании канала 
% (name) s: заменяется именем паука 

Например:

Хранить в FTP, используя один каталог для каждого паука:

ftp://user:password@ftp.example.com/scraping/feeds/%(name)s/%(time)s.json

Изменения в Feed, которые вы вносите в settings.py, будут применяться ко всем паукам в проекте. Вы также можете установить пользовательские настройки для конкретного паука, которые будут переопределять настройки в файле settings.py.

# -*- coding: utf-8 -*- import scrapy class AliexpressTabletsSpider(scrapy.Spider): name = 'aliexpress_tablets' allowed_domains = ['aliexpress.com'] start_urls = ['https://www.aliexpress.com/category/200216607/tablets.html', 'https://www.aliexpress.com/category/200216607/tablets/2.html?site=glo&g=y&tag='] custom_settings={ 'FEED_URI': "aliexpress_%(time)s.json", 'FEED_FORMAT': 'json'} def parse(self, response): print("procesing:"+response.url) #Extract data using css selectors product_name=response.css('.product::text').extract() price_range=response.css('.value::text').extract() #Extract data using xpath orders=response.xpath("//em[@title='Total Orders']/text()").extract() company_name=response.xpath("//a[@class='store $p4pLog']/text()").extract() row_data=zip(product_name,price_range,orders,company_name) #Making extracted data row wise for item in row_data: #create a dictionary to store the scraped info scraped_info = { #key:value 'page':response.url, 'product_name' : item[0], 'price_range' : item[1], 'orders' : item[2], 'company_name' : item[3], } #yield or give the scraped info to Scrapy yield scraped_info

response.url возвращает URL страницы, с которой генерируется ответ. После запуска сканера с помощью scrapy crawl aliexpress_tablets вы можете просмотреть файл json:



Следуя ссылкам

Вы, должно быть, заметили, что в start_urls есть две ссылки. Вторая ссылка - страница 2 тех же результатов поиска планшетов. Будет нецелесообразно добавлять все ссылки. Программа-паук должна иметь возможность сканировать все страницы самостоятельно, и в start_urls должна быть указана только начальная точка.

Если у страницы есть последующие страницы, вы увидите навигатор в конце страницы, который позволит перемещаться вперед и назад по страницам. Если вы реализовали все в соответствии с этим руководством, вы увидите это так:



Вот код, который вы увидите:



Как вы можете видеть, ниже есть тег с классом .ui-pagination-active, который является текущей страницей, на которой вы находитесь, и под которой находятся все теги со ссылками на следующую страницу. Каждый раз вам придется получать теги после этого тега . Здесь немного CSS! В этом случае вы должны получить дочерний узел, поэтому вы должны создать селектор css, который указывает сканеру найти теги , которые следуют после тега с классом .ui-pagination-active.

Помните! Каждая веб-страница имеет свою структуру. Вам придется немного изучить структуру того, как вы можете получить желаемый элемент. Всегда проверяйте response.css (SELECTOR) в Scrapy Shell, прежде чем писать их в коде.

Измените ваш aliexpress_tablets.py как показано ниже:

import scrapy class AliexpressTabletsSpider(scrapy.Spider): name = 'aliexpress_tablets' allowed_domains = ['aliexpress.com'] start_urls = ['https://www.aliexpress.com/category/200216607/tablets.html'] custom_settings={ 'FEED_URI': "aliexpress_%(time)s.csv", 'FEED_FORMAT': 'csv'} def parse(self, response): print("procesing:"+response.url) #Extract data using css selectors product_name=response.css('.product::text').extract() price_range=response.css('.value::text').extract() #Extract data using xpath orders=response.xpath("//em[@title='Total Orders']/text()").extract() company_name=response.xpath("//a[@class='store $p4pLog']/text()").extract() row_data=zip(product_name,price_range,orders,company_name) #Making extracted data row wise for item in row_data: #create a dictionary to store the scraped info scraped_info = { #key:value 'page':response.url, 'product_name' : item[0], 'price_range' : item[1], 'orders' : item[2], 'company_name' : item[3], } #yield or give the scraped info to scrapy yield scraped_info NEXT_PAGE_SELECTOR = '.ui-pagination-active + a::attr(href)' next_page = response.css(NEXT_PAGE_SELECTOR).extract_first() if next_page: yield scrapy.Request( response.urljoin(next_page), callback=self.parse)

В приведенном выше коде:

сначала вы извлекаете ссылку на следующую страницу, используя next_page = response.css (NEXT_PAGE_SELECTOR) .extract_first(), а затем, если переменная next_page получает ссылку и не является пустой, она входит в тело if.

response.urljoin(next_page): метод parse() будет использовать этот метод для создания нового URL-адреса и предоставления нового запроса, который позднее будет отправлен обратному вызову. 

Получив новый URL, он очистит эту ссылку, выполняя тело for, и снова будет искать следующую страницу. Это будет продолжаться до тех пор, пока не появится ссылка на следующую страницу.

Здесь вы можете откинуться на спинку стула и наслаждаться тем, как ваш паук проходит по всем страницам. Здесь будет много информации! Но ваш паук сделает это! Ниже вы можете увидеть, что размер файла достиг 1,1 МБ. 



Scrapy делает это для вас!

Комментариев нет:

Отправить комментарий