• Главная
  • Блог
  • Как создать парсер на python c помощью scrapy пошагово.

Как создать парсер на python c помощью scrapy пошагово.

Для 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() для извлечения всего текста в узлах

Создание проекта Scrapy и собственного робота (Spider)

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

Создадим робота (Spider) для страницы. В первую очередь необходимо создать проект Scrapy, где будут храниться код и результаты. Напишите следующее в терминале или anaconda.

scrapy startproject aliexpress

Это создаст скрытую папку в директории с Python или Anaconda по умолчанию. Она будет называться aliexpress, но можно выбрать любое название. Структура директории следующая:









































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

После создания проекта нужно перейти в новую папку и написать следующую команду:

scrapy genspider aliexpress_tabletswww.aliexpress/category/200216607/tablets.html

Это создает файл шаблона с названием aliexpress_tables.py в папке spiders, как и было описано выше. Вот код из этого файла:

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

В коде можно увидеть name, allowed_domains, start_urls и функцию parse.

name — это имя робота. Удачные и правильно подобранные имена позволят проще отслеживать всех имеющихся роботов. Они должны быть уникальны, ведь именно они используются для запуска командой scrapy crawl name_of_spider.
allowed_domains (опционально) — список разрешенных для парсинга доменов. Запрос к URL, не указанным в этом списке, не будет выполнен. Он должен включать только домен сайта (например, aliexpress), а не целый 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():

import scrapy
class AliexpressTabletsSpider(scrapy.Spider):
name = 'aliexpress_tablets'
allowed_domains = ['aliexpress']
start_urls = ['www.aliexpress/category/200216607/tablets.html',
'www.aliexpress/category/200216607/tablets/2.html?site=glo&g=y&tag=']
def parse(self, response):
print(""procesing:""+response.url)
# Извлечение данных с помощью селекторов CSS
product_name=response.css('.item-title::text').extract()
price_range=response.css('.price-current::text').extract()
# Извлечение данных с использованием 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)
# извлечение данных строки
for item in row_data:
# создать словарь для хранения извлеченной информации
scraped_info = {
'page': response.url,
'product_name': item[0], # item[0] означает продукт в списке и т. д., индекс указывает, какое значение назначить
'price_range': item[1],
'orders': item[2],
'company_name': item[3],
}
# генерируем очищенную информацию для скрапа
yield scraped_info

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

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

Теперь можно запустить робота и посмотреть результат:

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

Данные должны быть представлены в форматах CSV или JSON, чтобы их можно было анализировать. Этот раздел руководства посвящен тому, как получить такой файл из имеющихся данных.

Для сохранения файла CSV откройте settings.py в папке проекта и добавьте следующие строки:

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

После сохранения settings.py снова запустите scrapy crawl aliexpress_tablets в папке проекта. Будет создан файл aliexpress.csv.

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

FEED_FORMAT — настройка необходимого формата сохранения данных. Поддерживаются следующие:
+ JSON
+ CSV
+ JSON Lines
+ XML
FEED_URI — местоположение файла. Его можно сохранить в локальном хранилище или по FTP.

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

%(time)s — заменяется на временную метку при создании ленты
%(name)s — заменяется на имя робота

Например:

Сохранить по FTP используя по одной папке на робота:

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

import scrapy
class AliexpressTabletsSpider(scrapy.Spider):
name = 'aliexpress_tablets'
allowed_domains = ['aliexpress']
start_urls = ['www.aliexpress/category/200216607/tablets.html',
'www.aliexpress/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)
# Извлечение данных с помощью селекторов CSS
product_name=response.css('.item-title::text').extract()
price_range=response.css('.price-current::text').extract()
# Извлечение данных с использованием 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)
# извлечение данных строки
for item in row_data:
# создать словарь для хранения извлеченной информации
scraped_info = {
'page': response.url,
'product_name': item[0], # item[0] означает продукт в списке и т. д., индекс указывает, какое значение назначить
'price_range': item[1],
'orders': item[2],
'company_name': item[3],
}
# генерируем очищенную информацию для скрапа
yield scraped_info

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

Следующие страницы, пагинация

Вы могли обратить внимание на две ссылки в start_urls. Вторая — это страница №2 результатов поиска планшетов. Добавлять все ссылки непрактично. Робот должен быть способен исследовать все страницы сам, а в start_urls указывается только одна стартовая точка.

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

Вот такой код:

Предыдущая
1
...
7
След. стр.
Всего 24 стрПерейти на страницуОК

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

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

Измените aliexpress_tabelts.py следующим образом:

import scrapy
class AliexpressTabletsSpider(scrapy.Spider):
name = 'aliexpress_tablets'
allowed_domains = ['aliexpress']
start_urls = ['www.aliexpress/category/200216607/tablets.html']
custom_settings={ 'FEED_URI': ""aliexpress_%(time)s.json"",
'FEED_FORMAT': 'json'}
def parse(self, response):
print(""procesing:""+response.url)
# Извлечение данных с помощью селекторов CSS
product_name=response.css('.item-title::text').extract()
price_range=response.css('.price-current::text').extract()
# Извлечение данных с использованием 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)
# извлечение данных строки
for item in row_data:
# создать словарь для хранения извлеченной информации
scraped_info = {
'page': response.url,
'product_name': item[0], # item[0] означает продукт в списке и т. д., индекс указывает, какое значение назначить
'price_range': item[1],
'orders': item[2],
'company_name': item[3],
}
# генерируем очищенную информацию для скрапа
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(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 на высоком уровне, нужно разобраться со всеми его функциями, но вы уже как минимум знаете, как эффективно парсить группы веб-страниц.

Нужен парсинг данных?

Собираем открытые данные с любых веб-сайтов: цены, названия, артикулы, описания, свойства, категории, фото, отзывы, ссылки, тел.номера, e-mail и многое другое.

Написать
img