Узнайте, как использовать Scrapy в реальных проектах, используя его возможности и преодолевая его ограничения с помощью таких инструментов, как Playwright.
Scrapy — это фреймворк для парсинга с открытым исходным кодом, написанный на языке Python, который предоставляет простой в использовании API для парсинга, а также встроенную функциональность для обработки крупномасштабных проектов парсинга, поддержку различных типов извлечения данных и возможность работы с различными веб-протоколами.
СФЕРА РАЗВЛЕЧЕНИЙ
ОПТОВАЯ ТОРГОВЛЯ
ОБЕСПЕЧЕНИЕ ЭЛЕКТРИЧЕСКОЙ ЭНЕРГИЕЙ, ГАЗОМ И ПАРОМ
База всех компаний в категории: ОКВЭД 35.14 — ТОРГОВЛЯ ЭЛЕКТРОЭНЕРГИЕЙ
ОБРАБАТЫВАЮЩИЕ ПРОИЗВОДСТВА
База всех компаний в категории: ОКВЭД 28.29.43 — ПРОИЗВОДСТВО ТОРГОВЫХ АВТОМАТОВ
ПРОЕКТИРОВАНИЕ И СТРОИТЕЛЬСТВО
Scrapy является предпочтительным инструментом для крупномасштабных проектов парсинга благодаря своим преимуществам перед другими популярными библиотеками Python для веб-парсинга, такими как BeautifulSoup. BeautifulSoup — это в первую очередь библиотека парсеров, в то время как Scrapy — это полноценный фреймворк для парсинга с удобными встроенными функциями, такими как специальные типы спайдеров для различных задач парсинга и возможность расширения функциональности Scrapy за счет использования промежуточного программного обеспечения и экспорта данных в различные форматы.
Некоторые реальные примеры, где Scrapy может быть полезен, включают:
Важно отметить, что Scrapy имеет некоторые ограничения. Например, он не может парсить сайты с большим количеством JavaScript. Однако мы можем легко преодолеть это ограничение, используя Scrapy вместе с другими инструментами, такими как Selenium или Playwright, для работы с этими сайтами. Итак, теперь, когда мы имеем представление о том, что такое Scrapy и почему он полезен, давайте углубимся в его основные возможности.
Одной из ключевых особенностей Scrapy является возможность создавать различные типы спайдеров. Спайдеры, по сути, являются основой Scrapy и отвечают за разбор веб-сайтов и извлечение данных. В Scrapy существует три основных типа спайдеров:
Ниже приведен пример создания базового спайдера в Scrapy:
import scrapy
class MySpider(scrapy.Spider):
name = "myspider"
start_urls = ["http://example.com"]
def parse(self, response):
# extract data from response
Этот спайдер, названный myspider, начнет с запроса URL http://example.com. Метод parse — это то место, где вы напишете код для извлечения данных из ответа.
Вот пример того, как создать CrawlSpider в Scrapy:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class MyCrawlSpider(CrawlSpider):
name = "mycrawlspider"
start_urls = ["http://example.com"]
rules = [
Rule(LinkExtractor(), callback='parse_item', follow=True)
]
def parse_item(self, response):
# extract data from response
Этот спайдер, названный mycrawlspider, начнет работу с запроса URL http://example.com. Список правил содержит один объект Rule, который указывает спайдеру перейти по всем ссылкам и вызвать метод parse_item для каждого ответа.
Middlewares позволяют нам расширить функциональность Scrapy. Scrapy поставляется с несколькими встроенными промежуточными модулями, которые можно использовать из коробки. Кроме того, мы можем написать собственное промежуточное ПО для выполнения таких задач, как изменение заголовков запросов, логирование или обработка исключений. Итак, давайте рассмотрим некоторые из наиболее часто используемых промежуточных программ Scrapy:
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
'scrapy.downloadermiddlewares.useragent': 500,
}
В этом примере мы используем приоритет 500 для встроенной программы UserAgentMiddleware, чтобы обеспечить ее запуск перед другими программами-загрузчиками. По умолчанию UserAgentMiddleware устанавливает в заголовке User-Agent для каждого запроса случайно выбранную строку агента пользователя. Вы можете настроить используемые строки агента пользователя, задав параметр USER_AGENT в настройках Scrapy.
Обратите внимание, что мы сначала установили UserAgentMiddleware на None, прежде чем добавить его к параметру DOWNLOADER_MIDDLEWARES с другим приоритетом. Это связано с тем, что по умолчанию UserAgentMiddleware в Scrapy устанавливает общую строку агента пользователя для всех запросов, что может быть не идеальным для некоторых сценариев парсинга. Если нам нужно использовать пользовательскую строку агента пользователя, нам нужно будет настроить UserAgentMiddleware.
Поэтому, установив для UserAgentMiddleware значение None, мы указываем Scrapy удалить UserAgentMiddleware по умолчанию из параметра DOWNLOADER_MIDDLEWARES, прежде чем добавлять наш собственный экземпляр промежуточного ПО с другим приоритетом.
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
}
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,
'myproject.middlewares.ProxyMiddleware': 100,
}
PROXY_POOL_ENABLED = True
Это включит HttpProxyMiddleware, а также включит ProxyMiddleware, который мы определим. Это промежуточное ПО будет выбирать случайный прокси для каждого запроса из пула прокси, предоставленного пользователем.
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
}
Теперь мы можем использовать CookiesMiddleware для обработки файлов cookie, отправленных веб-сайтом:
from scrapy import Spider, Request
class MySpider(Spider):
name = 'myspider'
start_urls = ['<https://www.example.com/>']
def start_requests(self):
for url in self.start_urls:
# Send an initial request without cookies
yield Request(url, cookies={}, callback=self.parse)
def parse(self, response):
# Extract cookies from the response headers
cookies = {}
for cookie in response.headers.getlist('Set-Cookie'):
key, value = cookie.decode('utf-8').split('=', 1)
cookies[key] = value.split(';')[0]
# Send a new request with the cookies received
yield Request('<https://www.example.com/protected>', cookies=cookies, callback=self.parse_protected)
def parse_protected(self, response):
# Process the protected page here
pass
Когда спайдер отправляет первоначальный запрос на https://www.example.com/, мы еще не отправляем никаких файлов cookie. Когда мы получаем ответ, мы извлекаем куки из заголовков ответа и отправляем новый запрос на защищенную страницу с полученными куки. Это лишь несколько вариантов использования промежуточных модулей в Scrapy. Прелесть промежуточных модулей заключается в том, что мы можем писать свои собственные промежуточные модули, чтобы продолжать расширять возможности Scrapy и выполнять дополнительные задачи для наших конкретных случаев использования.
Scrapy предоставляет встроенную поддержку для экспорта собранных данных в различные форматы, такие как CSV, JSON и XML. Вы также можете создавать свои собственные экспортеры для хранения данных в различных форматах.
Вот пример того, как сохранить спарсенные данные в CSV-файл в Scrapy:
Обратите внимание, что это очень простой пример, и метод closed может быть модифицирован для обработки ошибок и обеспечения правильного закрытия файла. Кроме того, код является просто пояснением, и вам придется адаптировать его, чтобы он работал в вашем случае.
import scrapy
from scrapy.exporters import CsvItemExporter
class MySpider(scrapy.Spider):
name = 'example'
start_urls = ['<https://www.example.com>']
def parse(self, response):
items = response.xpath('//div[@class="item"]')
for item in items:
yield {
'title': item.xpath('.//h2/text()').get(),
'description': item.xpath('.//p/text()').get(),
}
def closed(self, reason):
filename = "example.csv"
with open(filename, 'w+b') as f:
exporter = CsvItemExporter(f)
exporter.fields_to_export = ['title', 'description']
exporter.export_item(item for item in self.parse())
В этом примере мы определяем спайдера, который начинает работу с поиска URL-адреса «https://www.example.com». URL. Затем мы определяем метод разбора, который извлекает название, цену и описание для каждого товара на странице. Наконец, в закрытом методе мы определяем имя файла CSV и экспортируем извлеченные данные с помощью CsvItemExporter. Другой способ экспорта извлеченных данных в различные форматы с помощью Scrapy — использовать команду scrapy crawl и указать желаемый формат файла нашего вывода. Это можно сделать, добавив флаг -o, за которым следует имя файла и расширение выходного файла.
Например, если мы хотим вывести собранные данные в формате JSON, мы используем следующую команду:
scrapy crawl myspider -o output.json
Это сохранит собранные данные в файле с именем output.json в том же каталоге, где была выполнена команда. Аналогично, если мы хотим вывести данные в формате CSV, мы используем следующую команду:
scrapy crawl myspider -o output.csv
Это сохранит собранные данные в файле с именем output.csv в том же каталоге, где была выполнена команда. В целом, Scrapy предоставляет несколько способов хранения и экспорта отсканированных данных, давая нам возможность выбрать наиболее подходящий метод для нашей конкретной ситуации. Теперь, когда мы лучше понимаем, что возможно с помощью Scrapy, давайте рассмотрим, как мы можем использовать этот фреймворк для извлечения данных с реальных веб-сайтов. Для этого мы создадим несколько небольших проектов, каждый из которых продемонстрирует различные возможности Scrapy.
В этом разделе мы узнаем, как настроить проект Scrapy и создать базового спайдера для поиска заголовка, автора, URL и пунктов всех статей, отображаемых на первой странице сайта Hacker News.
Прежде чем мы сможем создать спайдер, нам нужно создать новый проект Scrapy. Для этого мы воспользуемся терминалом. Откройте окно терминала и перейдите в каталог, где вы хотите создать проект. Начните с установки Scrapy:
pip install scrapy
Затем выполните следующую команду:
scrapy startproject hackernews
Эта команда создаст новый каталог под названием «hackernews» с базовой структурой проекта Scrapy.
Теперь, когда у нас есть проект Scrapy, мы можем создать спайдера для поиска нужных нам данных. В том же окне терминала перейдите в каталог проекта с помощью команды cd hackernews и выполните следующую команду:
scrapy genspider hackernews_spider news.ycombinator.com
Эта команда создаст нового спайдера в каталоге spiders нашего проекта. Мы назвали спайдера hackernews_spider и установили начальный URL на news.ycombinator.com, который является нашим целевым сайтом.
Далее откроем файл hackernews_spider.py в каталоге spiders нашего проекта. Мы увидим базовый шаблон для Scrapy-спайдера.
import scrapy
class HackernewsSpiderSpider(scrapy.Spider):
name = 'hackernews_spider'
allowed_domains = ['news.ycombinator.com']
start_urls = ['http://news.ycombinator.com/']
def parse(self, response):
pass
Прежде чем двигаться дальше, давайте быстро разберем, что мы видим:
Отлично, теперь самое интересное. Давайте добавим немного кода в метод parse, чтобы получить нужные нам данные.
import scrapy
class HackernewsSpiderSpider(scrapy.Spider):
name = 'hackernews_spider'
allowed_domains = ['news.ycombinator.com']
start_urls = ['http://news.ycombinator.com/']
def parse(self, response):
articles = response.css('tr.athing')
for article in articles:
yield {
"URL": article.css(".titleline a::attr(href)").get(),
"title": article.css(".titleline a::text").get(),
"rank": article.css(".rank::text").get().replace(".", "")
}
В этом коде мы используем метод css для извлечения данных из ответа. Мы выбираем все статьи на странице с помощью CSS-селектора tr.athing, а затем извлекаем заголовок, URL и рейтинг для каждой статьи с помощью более конкретных селекторов. Наконец, мы используем ключевое слово yield, чтобы вернуть словарь Python с собранными данными.
Теперь, когда наш спайдер готов, давайте запустим его и посмотрим, как он работает. По умолчанию данные выводятся на консоль, но мы также можем экспортировать их в другие форматы, такие как JSON, CSV или XML, указав формат вывода при запуске парсера. Чтобы продемонстрировать это, давайте запустим наш спайдер и экспортируем извлеченные данные в файл JSON:
scrapy crawl hackernews -o hackernews.json
Это сохранит данные в файл с именем **hackernews.json** в корневом каталоге проекта. Вы можете использовать ту же команду для экспорта данных в другие форматы, заменив расширение файла на нужный формат (например, o hackernews.csv для формата CSV). На этом запуск спайдера закончен. В следующем разделе мы рассмотрим, как можно использовать CrawlSpider в Scrapy для извлечения данных со всех страниц сайта Hacker News.
В предыдущем разделе было показано, как парсить данные с одной страницы с помощью базового спайдера. Хотя можно написать код для постраничного просмотра остальных страниц и спарсить все статьи на HN с помощью базового Spider, Scrapy предлагает нам лучшее решение: CrawlSpider. Итак, без лишних слов, давайте перейдем непосредственно к коду.
Для начала создадим новый проект Scrapy под названием hackernews_crawlspider с помощью следующей команды в терминале:
scrapy startproject hackernews_crawlspider
Далее давайте создадим нового спайдера, используя шаблон CrawlSpider. CrawlSpider является подклассом класса Spider и предназначен для рекурсивного перехода по ссылкам и сбора данных с нескольких страниц.
scrapy genspider -t crawl hackernews_spider https://news.ycombinator.com/
Эта команда создает нового спайдера под названием «hackernews_spider» в каталоге «spiders» вашего проекта Scrapy. Она также указывает, что спайдер должен использовать шаблон CrawlSpider и начать с поиска главной страницы Hacker News.
Наша цель в этом парсере — извлечь из каждой статьи те же данные, которые мы извлекли в предыдущем разделе: URL, заголовок и рейтинг. Разница в том, что теперь мы определим набор правил для парсера, которым он будет следовать при просмотре сайта. Например, мы определим правило, указывающее парсеру, где он может найти правильные ссылки для постраничного просмотра содержимого HN.
Вот как будет выглядеть окончательный вариант кода для нашего сценария использования:
# Add imports CrawlSpider, Rule and LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
# Change the spider from "scrapy.Spider" to "CrawlSpider"
class HackernewsSpider(CrawlSpider):
name = 'hackernews'
allowed_domains = ['news.ycombinator.com']
start_urls = ['<https://news.ycombinator.com/news>']
custom_settings = {
'DOWNLOAD_DELAY': 1 # Add a 1-second delay between requests
}
# Define a rule that should be followed by the link extractor.
# In this case, Scrapy will follow all the links with the "morelink" class
# And call the "parse_article" function on every crawled page
rules = (
Rule(LinkExtractor(allow=[r'news\.ycombinator\.com/news$']), callback='parse_article'),
Rule(LinkExtractor(restrict_css='.morelink'), callback='parse_article', follow=True),
)
# When using the CrawlSpider we cannot use a parse function called "parse".
# Otherwise, it will override the default function.
# So, just rename it to something else, for example, "parse_article"
def parse_article(self, response):
for article in response.css('tr.athing'):
yield {
"URL": article.css(".titleline a::attr(href)").get(),
"title": article.css(".titleline a::text").get(),
"rank": article.css(".rank::text").get().replace(".", "")
}
Теперь давайте разберем код, чтобы понять, что CrawlSpider делает для нас в этом сценарии. Вы можете заметить, что некоторые части этого кода уже были сгенерированы CrawlSpider, в то время как другие части очень похожи на то, что мы делали при написании базового Spider. Первая отличительная часть кода, которая может привлечь ваше внимание, — это включенный нами атрибут custom_settings. Он добавляет 1-секундную задержку между запросами. Поскольку сейчас мы отправляем несколько запросов для доступа к различным страницам сайта, дополнительная задержка между запросами может быть полезна для предотвращения перегрузки целевого сайта слишком большим количеством запросов одновременно.
Далее мы определили набор правил, которым нужно следовать при просмотре сайта, используя атрибут rules:
rules = (
Rule(LinkExtractor(allow=[r'news\.ycombinator\.com/news$']), callback='parse_article'),
Rule(LinkExtractor(restrict_css='.morelink'), callback='parse_article', follow=True),
)
Каждое правило определяется с помощью класса Rule, который принимает два аргумента: экземпляр LinkExtractor, определяющий, по каким ссылкам нужно следовать, и функцию обратного вызова, которая будет вызываться для обработки ответа от каждой просмотренной страницы. В данном случае у нас есть два правила:
Наконец, мы определили функцию parse_article, которая принимает в качестве аргумента объект ответа. Эта функция вызывается для обработки ответа от каждой страницы, которая соответствует одному из правил, определенных в атрибуте rules.
def parse_article(self, response):
for article in response.css('tr.athing'):
yield {
"URL": article.css(".titleline a::attr(href)").get(),
"title": article.css(".titleline a::text").get(),
"rank": article.css(".rank::text").get().replace(".", "")
}
В этой функции мы используем метод response.css для извлечения данных из HTML страницы. В частности, мы ищем все элементы tr с классом athing и извлекаем URL, заголовок и рейтинг каждой статьи. Затем мы используем ключевое слово yield, чтобы вернуть словарь Python с этими данными. Помните, что ключевое слово yield используется вместо return, потому что Scrapy обрабатывает ответ асинхронно, и функция может быть вызвана несколько раз. Также стоит отметить, что мы назвали функцию parse_article вместо стандартной функции parse, которая используется в Scrapy Spiders.
Это связано с тем, что когда вы используете класс CrawlSpider, функция разбора по умолчанию используется для разбора ответа от первой просмотренной страницы. Если вы определите собственную функцию разбора в CrawlSpider, она переопределит функцию по умолчанию, и ваш спайдер не будет работать так, как ожидалось. Чтобы избежать этой проблемы, считается хорошей практикой всегда называть наши пользовательские функции разбора как-то иначе, чем parse. В данном случае мы назвали нашу функцию parse_article, но вы можете выбрать любое другое имя, подходящее для вашего спайдера.
Отлично, теперь, когда мы понимаем, что происходит в нашем коде, пришло время испытать нашего спайдера на практике, запустив его с помощью следующей команды:
scrapy crawl hackernews -o hackernews.json
Это позволит запустить спайдера и спарсить данные со всех новостей на всех страницах сайта Hacker News. Мы также уже воспользовались возможностью указать Scrapy выводить все спарсенные данные в JSON-файл, что облегчит нам визуализацию полученных результатов.
Парсинг веб-сайтов, содержащих JavaScript, может оказаться сложной задачей, поскольку Scrapy в первую очередь предназначен для парсинга статических HTML-страниц. Однако мы можем обойти это ограничение, используя безголовый браузер, такой как Playwright, в сочетании со Scrapy для парсинга динамических веб-страниц. Playwright — это библиотека, которая предоставляет высокоуровневый API для управления безголовыми браузерами Chrome, Firefox и Safari. Используя Playwright, мы можем программно взаимодействовать с целевой веб-страницей для имитации действий пользователя и извлечения данных из динамически загружаемых элементов.
Чтобы использовать Playwright в Scrapy, нам необходимо создать пользовательское промежуточное ПО, которое инициализирует экземпляр браузера Playwright и получает HTML-содержимое веб-страницы с помощью Playwright. Затем промежуточное ПО может передать HTML-содержимое в Scrapy для разбора и извлечения данных. К счастью, библиотека scrapy-playwright позволяет нам легко интегрировать Playwright со Scrapy. В следующем разделе мы построим небольшой проект с использованием этой комбинации для извлечения данных с сайта Mint Mobile, перегруженного JavaScript. Но прежде чем двигаться дальше, давайте вкратце рассмотрим целевую веб-страницу и поймем, почему мы не сможем извлечь нужные нам данные с помощью одной только Scrapy.
Mint Mobile требует JavaScript для загрузки значительной части содержимого, отображаемого на странице продукта, что делает его идеальным сценарием для использования Playwright в контексте парсинга:
Страница продукта Mint Mobile с отключенным JavaScript:
Страница продукта Mint Mobile с включенным JavaScript:
Как видите, без включенного JavaScript мы потеряем значительную часть данных, которые хотим извлечь. Поскольку Scrapy не может загружать JavaScript, вы можете считать первое изображение с отключенным JavaScript «представлением Scrapy», а второе изображение с включенным JavaScript — «представлением Playwright». Отлично, теперь, когда мы знаем, почему нам нужна библиотека автоматизации браузера, такая как Playwright, чтобы спарсить эту страницу, пришло время воплотить эти знания в код, создав наш следующий проект: парсер Mint Mobile.
Мы начнем с создания каталога для размещения нашего проекта и установки необходимых зависимостей:
# Create new directory and move into it
mkdir scrapy-playwright
cd scrapy-playwright
Установка:
# Install Scrapy and scrapy-playwright
pip install scrapy scrapy-playwright
# Install the required browsers if you are running Playwright for the first time
playwright install
Далее мы запускаем проект Scrapy и генерируем спайдер:
scrapy startproject scrapy_playwright_project
scrapy genspider mintmobile https://www.mintmobile.com/
Теперь давайте активируем scrapy-playwright, добавив несколько строк конфигурации в наше промежуточное ПО DOWNLOAD_HANDLERS.
# scrapy-playwright configuration
DOWNLOAD_HANDLERS = {
"http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
"https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
}
Отлично! Теперь мы готовы написать код для поиска нашего целевого сайта.
import scrapy
from scrapy_playwright.page import PageMethod
class MintmobileSpider(scrapy.Spider):
name = 'mintmobile'
def start_requests(self):
yield scrapy.Request('<https://www.mintmobile.com/product/google-pixel-7-pro-bundle/>',
meta= dict(
# Use Playwright
playwright = True,
# Keep the page object so we can work with it later on
playwright_include_page = True,
# Use PageMethods to wait for the content we want to scrape to be properly loaded before extracting the data
playwright_page_methods = [
PageMethod('wait_for_selector', 'div.m-productCard--device')
]
))
def parse(self, response):
yield {
"name": response.css("div.m-productCard__heading h1::text").get().strip(),
"memory": response.css("div.composited_product_details_wrapper > div > div > div:nth-child(2) > div.label > span::text").get().replace(':', '').strip(),
"pay_monthly_price": response.css("div.composite_price_monthly > span::text").get(),
"pay_today_price": response.css("div.composite_price p.price span.amount::attr(aria-label)").get().split()[0],
};
В методе start_requests спайдер делает один HTTP-запрос к странице продукта мобильного телефона на сайте Mint Mobile. Мы инициализируем этот запрос с помощью класса scrapy.Request, передавая мета-словарь, задающий опции, которые мы хотим использовать для Playwright при сканировании страницы. Эти параметры включают playwright, установленный в True, чтобы указать, что Playwright должен быть использован, затем playwright_include_page также установлен в True, чтобы мы могли сохранить объект страницы, чтобы его можно было использовать позже, и playwright_page_methods, установленный в список объектов PageMethod.
В данном случае имеется только один объект PageMethod, который использует метод Playwright wait_for_selector для ожидания появления на странице определенного CSS-селектора. Это делается для того, чтобы убедиться, что страница правильно загрузилась, прежде чем мы начнем извлекать ее данные. В методе разбора спайдер использует селекторы CSS для извлечения данных со страницы. Извлекаются четыре части данных: название продукта, объем его памяти, цена_за_месяц, а также цена_за_день.
Наконец, давайте запустим нашего спайдера с помощью команды scrapy crawl mintmobile -o data.json, чтобы извлечь целевые данные и сохранить их в файле data.json:
[
{
"name": "Google Pixel 7 Pro",
"memory": "128GB",
"pay_monthly_price": "50",
"pay_today_price": "589"
}
]
Далее мы узнаем, как развернуть спайдеров Scrapy в облаке с помощью Apify. Это позволит нам настроить их запуск по расписанию и получить доступ ко многим другим возможностям платформы. Чтобы продемонстрировать это, мы воспользуемся Apify SDK для Python и выберем шаблон разработки Scrapy, который поможет нам запустить процесс настройки. Затем мы изменим сгенерированный код шаблона для запуска нашего парсера CrawlSpider Hacker News. Давайте приступим.
Чтобы начать работу с Apify CLI, нам нужно сначала установить его. Это можно сделать двумя способами: через менеджер пакетов Homebrew на macOS или Linux или через менеджер пакетов Node.js (NPM).
Через homebrew
На macOS (или Linux) вы можете установить Apify CLI через менеджер пакетов Homebrew.
brew install apify/tap/apify-cli
Через NPM
Установите или обновите Apify CLI, выполнив команду:
npm -g install apify-cli
После установки Apify CLI на ваш компьютер просто выполните следующую команду в терминале:
apify create scrapy-actor
Затем выберите Python → Scrapy → Установить шаблон
Эта команда создаст новую папку с именем scrapy-actor, установит все необходимые зависимости и создаст шаблонный код, который мы можем использовать для начала разработки с использованием Scrapy и Apify SDK для Python. Наконец, перейдите в только что созданную папку и откройте ее с помощью предпочитаемого редактора кода, в данном примере я использую VS Code.
cd scrapy-actor
code .
Шаблон уже создает полностью функциональный парсинг. Вы можете запустить его с помощью команды apify run. Если вы хотите попробовать его до того, как мы изменим код, результаты парсинга будут храниться в разделе storage/datasets. Теперь, когда мы знакомы с шаблоном, мы можем изменить его, чтобы приспособить к нашему парсеру HackerNews.
Чтобы внести первую поправку, нам нужно заменить код шаблона в src/spiders/title_spider.py на наш собственный код. После замены ваш код должен выглядеть следующим образом:
# Add imports CrawlSpider, Rule and LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
# Change the spider from "scrapy.Spider" to "CrawlSpider"
class HackernewsSpider(CrawlSpider):
name = 'hackernews'
allowed_domains = ['news.ycombinator.com']
start_urls = ['<https://news.ycombinator.com/news>']
custom_settings = {
'DOWNLOAD_DELAY': 1 # Add a 1-second delay between requests
}
# Define a rule that should be followed by the link extractor.
# In this case, Scrapy will follow all the links with the "morelink" class
# And call the "parse_article" function on every crawled page
rules = (
Rule(LinkExtractor(allow=[r'news\.ycombinator\.com/news$']), callback='parse_article'),
Rule(LinkExtractor(restrict_css='.morelink'), callback='parse_article', follow=True),
)
# When using the CrawlSpider we cannot use a parse function called "parse".
# Otherwise, it will override the default function.
# So, just rename it to something else, for example, "parse_article"
def parse_article(self, response):
for article in response.css('tr.athing'):
yield {
"URL": article.css(".titleline a::attr(href)").get(),
"title": article.css(".titleline a::text").get(),
"rank": article.css(".rank::text").get().replace(".", "")
}
Наконец, перед запуском Actor нам необходимо внести некоторые изменения в файл main.py, чтобы привести его в соответствие с теми изменениями, которые мы внесли в исходный шаблон спайдера.
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from apify import Actor
from .pipelines import ActorDatasetPushPipeline
from .spiders.hackernews_spider import HackernewsSpider
async def main():
async with Actor:
actor_input = await Actor.get_input() or {}
max_depth = actor_input.get('max_depth', 1)
start_urls = [start_url.get('url') for start_url in actor_input.get('start_urls', [{ 'url': '<https://news.ycombinator.com/news>' }])]
settings = get_project_settings()
settings['ITEM_PIPELINES'] = { ActorDatasetPushPipeline: 1 }
settings['DEPTH_LIMIT'] = max_depth
process = CrawlerProcess(settings, install_root_handler=False)
# If you want to run multiple spiders, call `process.crawl` for each of them here
process.crawl(HackernewsSpider, start_urls=start_urls)
process.start()
Отлично! Теперь мы готовы запустить наш актор Scrapy. Для этого давайте введем в терминале команду apify run. Через несколько секунд хранилище/datasets будет заполнено данными, взятыми из Hacker News.
Перед развертыванием Actor в Apify нам нужно сделать последнюю настройку. Перейдите в .actor/input_schema.json и измените URL prefill на https://news.ycombinator.com/news. Это изменение важно при запуске парсера на платформе Apify.
Теперь, когда мы знаем, что наш Actor работает так, как ожидалось, пришло время развернуть его на платформе Apify. Для этого вам необходимо зарегистрировать бесплатную учетную запись Apify. Как только вы зарегистрируете учетную запись Apify, выполните команду apify login в терминале. Вам будет предложено ввести токен API Apify. Его можно найти в Apify Console в разделе Настройки → Интеграции. Последним шагом будет выполнение команды apify push. Это запустит сборку Актора, и через несколько секунд вы сможете увидеть только что созданного Актора в Apify Console в разделе Actors → My actors.
Отлично! Ваш парсер готов к работе на платформе Apify. Чтобы начать работу, нажмите кнопку Start. После завершения работы вы можете просмотреть и загрузить свои данные в различных форматах на вкладке Storage.
Краткое саммари: опасная иллюзия легких лидов В мире жесткой конкуренции идея быстро пополнить клиентскую базу,…
Краткое резюме: как превратить сеть сайтов в стабильный источник дохода Создание сети информационных сайтов —…
Знаете ли вы, что невидимые технические ошибки могут «съедать» до 90% вашего потенциального трафика из…
Введение: почему мониторинг цен — необходимость, а защита — не преграда Представьте, что вы пытаетесь…
Значительная часть трафика на любом коммерческом сайте — это не люди. Это боты, которые могут…
Систематический мониторинг цен конкурентов — это не просто способ избежать ценовых войн, а доказанный инструмент…