CoderCastrov logo
CoderCastrov
Парсер веб-страниц

Парсинг данных из Интернета с использованием библиотеки Scrapy

Парсинг данных из Интернета с использованием библиотеки Scrapy
просмотров
11 мин чтение
#Парсер веб-страниц

Привет всем! После того, как я познакомился с миром Medium через свой опыт стажировки, я снова здесь, чтобы рассказать о важной библиотеке на языке Python, которая используется в проектах по обработке больших данных и искусственному интеллекту, и которая, хотя и может показаться сложной в начале, на самом деле очень удобна и позволяет быстро извлекать данные. Это библиотека Scrapy...

В этой статье мы соберем различные данные с сайта Hepsiburada. Мы будем пытаться понять логику извлечения данных и также попрактикуемся в написании кода 😎 Практикуемся, чтобы мы могли учиться.

Существует множество технологий и библиотек для сбора данных из Интернета. Некоторые из них: BeautifulSoup, Selenium и библиотека Request. Возможно, однажды я напишу статью и о них. Однако сегодня мы будем работать с Scrapy, самой популярной, быстрой, мощной и, возможно, наиболее настраиваемой библиотекой для парсинга/извлечения данных на языке программирования Python. Почему я говорю, что она наиболее настраиваемая, вы поймете в дальнейшем в ходе статьи 😉

В конце дня мы напишем небольшой API для веб-скрейпера/веб-парсера. Я надеюсь, что этот программный продукт будет полезен всем, кто интересуется работой с данными. Даже если вы не являетесь таковым, возможно, вы решите стать данным ученым впоследствии 😃

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

Важное замечание: Scrapy является парсером HTML. Он извлекает данные из HTML-кода. Если на странице используется JavaScript для заполнения определенных областей, Scrapy не сможет их извлечь. Существуют различные методы решения этой проблемы, но все они не являются универсальным решением.

Что такое Crawler, Scraper и Spider? Почему используются эти термины?

Слово "Crawl" означает ползать, медленно двигаться. Это действия, предпринимаемые для достижения цели или намеченного плана.

Слово "Scraping" означает скребок, снятие.

При сборе данных вам нужно следовать за ссылками и собирать определенные данные (включая URL следующей страницы, на которую вы отправляете запрос). Переход по ссылкам и сбор требуемых данных во время этого процесса называется Web Crawling, а сбор определенных данных во время этого процесса называется Web Scraping. Как вы могли догадаться, эти процессы очень похожи и часто переплетаются.

Термин "Spider" используется потому, что, перемещаясь по ссылкам и собирая данные с этих адресов, вы фактически создаете сеть. Каждая функция, которую мы написали в коде, на самом деле является нашим "пауком". Иными словами, это наш инструмент или инструменты для создания сети.

Фактическая архитектура работы Scrapy заключается в создании такой сети с помощью ваших "пауков", которые перемещаются между веб-сайтами и собирают данные.

У Scrapy есть отличная структура работы. Одно из отличий заключается в параллельной работе "пауков". Если вы создали сеть между несколькими ссылками, то полученные данные могут не возвращаться в определенном порядке. Наборы данных, которые вы видите на выходе, могут быть результатом работы не только одной ссылки, но и "паука", который связан с другими ссылками. Кроме того, этот процесс происходит очень быстро.

С помощью Scrapy вы можете получить вывод в различных форматах. Вы можете получить вывод в формате CSV, JSON или легко передавать данные в различные базы данных, такие как MongoDB, PostreSQL.

Приходим к вопросу, который никогда не уходит из головы: Является ли сбор данных легальным?

Да, это легально. Сбор данных является законным. Незаконной частью является использование этих данных после их сбора для анализа, интерпретации и продажи продуктов, созданных на основе этих данных.

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

Эти вопросы имеют различные детали. Это долгая история, поэтому лучше вернемся к нашей теме. Но будьте уверены, что наша работа в этой статье полностью законна. 😊

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


Начнем сбор данных!

Если у вас не установлен Scrapy на вашем компьютере, вы можете ознакомиться с руководством по установке. Установка очень простая.

После завершения установки перейдите в каталог, в котором вы хотите работать, откройте терминал и запустите проект Scrapy, как указано ниже. Давайте назовем проект "hepsiburada".

scrapy startproject hepsiburada

Этот фрагмент кода создаст полноценный проект Python в текущем каталоге. Когда вы войдете в каталог или откроете проект в вашей среде разработки Python, вы увидите, что автоматически создаются следующие файлы:

_init.py : Это файл, который будет запускаться только при первом запуске программы и будет запускать паука. Мы добавим наши пауки в папку _spiders.

items.py : Мы создадим объекты для данных, которые мы собираем, внутри этой папки. Пауки будут получать доступ к объектам из этого файла.

pipelines.py : Мы будем использовать этот файл для передачи данных, которые мы собрали, в объекте "item".

settings.py : Это особый файл, который делает Scrapy настраиваемым. Вы можете настроить различные параметры для вашего паука, такие как прокси, user-agent, задержки и т. д. Рекомендую вам изучить его самостоятельно, так как в нем много настроек, которые вы можете настроить для своего паука.

Создаем наш первый Spider

Открываем файл python в папке spiders. Наш Spider должен быть в папке spiders. Я назвал файл hepsiburada_spider, но вы можете выбрать любое имя.

Импортируем библиотеку scrapy в созданный файл. Затем создаем класс, в котором будут написаны функции, которые Spider будет использовать для работы. Этот класс будет наследоваться от класса scrapy.Spider, чтобы использовать его функции. "name" - это имя нашего Spider. Если вы создаете несколько Spider, вы должны дать им разные имена. Имена Spider должны быть уникальными. "start_urls" - это список URL-адресов, с которых мы будем собирать данные. Я собираю данные с раздела "Компьютеры/Планшеты" в категории "Электроника" на сайте Hepsiburada. Поэтому я добавил URL-адрес этой категории. Вы можете добавить несколько URL-адресов в этот список. Вы можете использовать их для перехода между страницами.

start_urls = [
 'http://quotes.toscrape.com/page/1/',
 'http://quotes.toscrape.com/page/2/',
 ]

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

Затем мы создаем функцию "parse", которая начнет парсить элементы веб-сайта. Прежде чем мы решим, какие данные мы собираем, давайте посмотрим на них на странице "https://www.hepsiburada.com/bilgisayarlar-c-2147483646".

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

Как я уже говорил, Scrapy - это Html Parser, поэтому нам нужно указать пути Xpath или CSS для данных, которые мы хотим собрать. Я буду использовать Xpath. Я также рекомендую вам использовать Xpath. Но если вы предпочитаете использовать CSS, вы все равно получите те же результаты.

Я не буду вдаваться в подробности о Xpath и CSS path. Если вы не знакомы с ними или хотите узнать больше, вы можете провести дополнительное исследование, чтобы лучше понять. Главное - это понять коды Html-адресов.

Мы будем использовать Xpath, чтобы найти адрес данных, которые мы хотим собрать. Мы будем делать это для всех данных, которые мы хотим собрать. Теперь вернемся к кодированию.

Перейдите в файл items.py и отредактируйте его следующим образом.

class HepsiburadaItem(scrapy.Item):
    # define the fields for your item here like :
    prod_name = scrapy.Field() 
    prod_old_price = scrapy.Field()
    prod_new_price = scrapy.Field()
    prod_discount_price = scrapy.Field()
    prod_photo = scrapy.Field()
    product_review_no = scrapy.Field()
    prod_url = scrapy.Field()

Затем перейдите в файл HepsiburadaTutorial.py. Чтобы создать объект HepsiburadaItem, который мы определили в файле items.py, сначала нам нужно импортировать этот класс.

from ..items import HepsiburadaItem

Затем определим наши Xpath и присвоим их переменным, а затем присвоим значения этим переменным ключам внутри нашего объекта.

class HepsiburadaTutorial(scrapy.Spider):
    name = 'hepsiburada'
    start_urls = ['https://www.hepsiburada.com/bilgisayarlar-c-2147483646']

    def parse(self, response):
        items = HepsiburadaItem()

        prod_name = response.xpath("//li/div/a/div[@class='product-detail']/h3/@title").extract()

        prod_old_price = response.xpath("//li/div/a/div[@class='product-detail']/div/del/text()").extract()

        prod_new_price = response.xpath("//li/div/a/div[@class='product-detail']/div/span[@class='price old product-old-price']/text() | //li/div/a/div[@class='product-detail']/div/span[@class='price old product-old-price']/text()").extract()

        prod_discount_price = response.xpath("//li/div/a/div[@class='product-detail']/div/div[@class='price-value']/text()").extract()

        prod_photo = response.xpath("//li/div/a/div[@class='product-image-wrapper']/figure/div/img/@data-src").extract()

        product_review_no = response.xpath("//li/div/a/div[@class='product-detail']/div/span[@class='number-of-reviews']/text()").extract()

        prod_url = response.xpath("//li[@class='search-item col lg-1 md-1 sm-1  custom-hover not-fashion-flex']/div/a/@href").extract()

        # Assigning values to the key in the items object
        items['prod_name'] = prod_name
        items['prod_old_price'] = prod_old_price
        items['prod_new_price'] = prod_new_price
        items['prod_discount_price'] = prod_discount_price
        items['prod_photo'] = prod_photo
        items['product_review_no'] = product_review_no
        items['prod_url'] = prod_url

        yield items

Отлично, мы дали нашему Spider адреса данных, которые мы хотим собрать. Теперь мы можем переходить между страницами. Как я уже сказал, хранить количество страниц статически не рекомендуется для постоянно работающего crawler. Поэтому мы определим это внутри нашего Spider и, после получения данных с одной страницы, увеличим значение переменной, хранящей количество страниц, создадим новый URL для следующей страницы и отправим запрос на этот URL. Как это сделать? Давайте закодируем это👇

Сначала определим переменную, хранящую номер страницы.

Хорошо. Теперь создадим серию URL-адресов, которые будут следовать друг за другом. Если вы перейдете на вторую страницу на Hepsiburada, вы получите следующий URL: "https://www.hepsiburada.com/bilgisayarlar-c-2147483646?sayfa=2" - если вы перейдете на третью страницу, вы получите следующий URL: "https://www.hepsiburada.com/bilgisayarlar-c-2147483646?sayfa=3". Как вы видите, единственное изменение - это число в конце. Это означает, что если я могу изменить это число, я могу переходить между страницами. Я сделаю это. Затем я говорю, что пока новый URL возвращает ответ, я буду увеличивать значение переменной, хранящей количество страниц, и продолжать отправлять запрос на новую страницу.

next_page = "https://www.hepsiburada.com/bilgisayarlar-c-2147483646?sayfa={}".format(
    self.page_number)

if next_page:
    self.page_number += 1
    yield response.follow(next_page, callback=self.parse)

Этот процесс завершен, и теперь мы можем запустить наш Spider.

Окончательный код:

import scrapy
from ..items import HepsiburadaItem


class HepsiburadaTutorial(scrapy.Spider):
    name = 'hepsiburada'
    start_urls = ['https://www.hepsiburada.com/bilgisayarlar-c-2147483646']

    page_number = 2

    def parse(self, response):
        items = HepsiburadaItem()

        prod_name = response.xpath("//li/div/a/div[@class='product-detail']/h3/@title").extract()

        prod_old_price = response.xpath("//li/div/a/div[@class='product-detail']/div/del/text()").extract()

        prod_new_price = response.xpath(
            "//li/div/a/div[@class='product-detail']/div/span[@class='price old product-old-price']/text() | //li/div/a/div[@class='product-detail']/div/span[@class='price old product-old-price']/text()").extract()

        prod_discount_price = response.xpath(
            "//li/div/a/div[@class='product-detail']/div/div[@class='price-value']/text()").extract()

        prod_photo = response.xpath(
            "//li/div/a/div[@class='product-image-wrapper']/figure/div/img/@data-src").extract()

        product_review_no = response.xpath(
            "//li/div/a/div[@class='product-detail']/div/span[@class='number-of-reviews']/text()").extract()

        prod_url = response.xpath(
            "//li[@class='search-item col lg-1 md-1 sm-1  custom-hover not-fashion-flex']/div/a/@href").extract()

        # Assigning values to the key in the items object
        items['prod_name'] = prod_name
        items['prod_old_price'] = prod_old_price
        items['prod_new_price'] = prod_new_price
        items['prod_discount_price'] = prod_discount_price
        items['prod_photo'] = prod_photo
        items['product_review_no'] = product_review_no
        items['prod_url'] = prod_url

        yield items

        next_page = "https://www.hepsiburada.com/bilgisayarlar-c-2147483646?sayfa={}".format(
            self.page_number)

        if next_page:
            self.page_number += 1
            yield response.follow(next_page, callback=self.parse)

Теперь откройте терминал в папке с файлом. Напишите следующее👇

scrapy crawl hepsiburada

Через некоторое время вы увидите, что ваши данные выводятся в терминале.

I have only shown a part of the result because it is too long.

Да, вы видите, что мы получили данные, которые мы хотели, и вывели их в терминале. Теперь давайте получим эти результаты в формате JSON.

scrapy crawl hepsiburada -o data.json

Да, вы видите, что у нас есть файл data.json. Вы можете изучить его содержимое. Вы также можете использовать эту команду для получения данных в формате .csv.

scrapy crawl hepsiburada -o data.csv

Да, друзья, мы собрали наши данные, и мы заканчиваем эту статью. Мы написали очень простой Web Scraper. Но, на мой взгляд, это было хорошее начало. Надеюсь, вам понравилось, вы не заскучали и это было полезно для вас. Увидимся в следующей статье.

Для тех, кто заинтересован, я предоставлю небольшую дополнительную информацию о Scrapy в конце этой статьи.

Scrapy (Продвинутый уровень)

Как я уже сказал, мы только что написали очень простой веб-краулер/скрейпер. Мы даже не использовали файл settings.py. Но вы должны знать, что при написании подобных ботов, есть вероятность, что сайт забанит вас. Поэтому разумно будет настроить User-Agent, настроить Proxy, добавить случайные задержки между запросами, чтобы усложнить обнаружение нашего бота системой. Эти настройки можно сделать внутри файла settings.py. Мы не использовали их в этом уроке, потому что нам это не требовалось.

Еще одна заметная вещь: мы не создали отдельный объект для каждого продукта, вы заметили? То есть все свойства мы поместили в соответствующее поле/ключ объекта. Например, все названия продуктов находились в поле/ключе "prod_name" объекта item. Это, конечно, не очень удобно. Было бы удобнее видеть свойства каждого продукта внутри одного объекта. Например, такой вид данных будет более удобным для моделей и анализа.

**prod_name: Dell G515 AMD Ryzen 5 4600H 8GB 512GB SSD Radeon RX 5600M Windows 10 Home 15.6" FHD Taşınabilir Bilgisayarprod_old_price: 9.999,00 TLprod_new_price: 8.999,00 TLprod_discount_price: 8.598,99 TLprod_photo: **https://productimages.hepsiburada.net/s/41/280-413/10698877993010.jpgproduct_review_no:(13)prod_url:/dell-g515-amd-ryzen-5–4600h-8gb-512gb-ssd-radeon-rx-5600m-windows-10-home-15–6-fhd-tasinabilir-bilgisayar-p-HBV00000VZ7N1

Чтобы получить данные в таком виде с помощью Scrapy, нам нужно использовать Item Loader. И для этого нам нужно создать надежный, быстрый и избегающий ненужных операций API, используя базы данных.

В итоге, если вы хотите написать мощные веб-скрейперы с помощью Scrapy, вам нужно хорошо понимать концепции XPath и ItemLoader, а также использовать базы данных для усиления функционала. Особенно разумно использовать NoSQL базы данных. Вы можете найти API веб-скрейпера на основе Scrapy, разработанный с использованием этих функций, в моем репозитории на GitHub.

До свидания...


Каталог источников:

Учебник по Scrapy - Документация Scrapy 2.4.0

В этом учебнике мы предполагаем, что Scrapy уже установлен на вашей системе. Если это не так, см. ...

docs.scrapy.or

Репозиторий на Github:

ByUnal - Обзор

Разработчик программного обеспечения Big Data и исследователь машинного обучения | Студент...

github.com