scrapy-playwright не работает через celery в проекте django

Такая проблема - мне необходимо приложение на Scrapy-playwright для парсинга некоторых сайтов. В данном случае - ББР банка (Задание учебное, поэтому валюты подсасываются парсингом - задание препода)

Написал сначала отдельно и проверил - работает ли парсер. Работал и работает дальше. Правда пока пытался найти ошибку поломал и тот код, но там и другие пауки присутствуют, так что не проблема

Добавил задачу в celery (Весь код приложу ниже), все настроил. Мне нужно хранить валюты в виде json внутри redis для дальнейшего пересчёта цен. И вот проблема в том, что паук то запускается, но вот когда доходит до начала парсинга - он не находит страницы. Playwright её просто не подгружает. Перерыл кучу источников, но так и не нашел ответа. Подскажите пж, в чем ошибка?

Ошибка

2025-01-18 06:09:48 [scrapy.utils.log] INFO: Scrapy 2.12.0 started (bot: scrapybot)
2025-01-18 06:09:48 [scrapy.utils.log] INFO: Versions: lxml 5.3.0.0, libxml2 2.11.7, cssselect 1.2.0, parsel 1.9.1, w3lib 2.2.1, Twisted 24.11.0, Python 3.11.5 (tags/v3.11.5:cce6ba9, Aug 24 2023, 14:38:34) [MSC v.1936 64 bit (AMD64)], pyOpenSSL 24.3.0 (OpenSSL 3.4.0 22 Oct 2024), cryptography 44.0.0, Platform Windows-10-10.0.22621-SP0
Соединение с Redis установлено успешно.
2025-01-18 06:09:48 [scrapy.addons] INFO: Enabled addons:
[]
2025-01-18 06:09:48 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.selectreactor.SelectReactor
2025-01-18 06:09:48 [scrapy.extensions.telnet] INFO: Telnet Password: ecbd6048a80cea89
2025-01-18 06:09:48 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.logstats.LogStats']
2025-01-18 06:09:48 [scrapy.crawler] INFO: Overridden settings:
{}
2025-01-18 06:09:49 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2025-01-18 06:09:49 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2025-01-18 06:09:49 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2025-01-18 06:09:49 [scrapy.core.engine] INFO: Spider opened
2025-01-18 06:09:49 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2025-01-18 06:09:49 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2025-01-18 06:09:49 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://bbr.ru/> (referer: None)
2025-01-18 06:09:50 [scrapy.core.scraper] ERROR: Spider error processing <GET https://bbr.ru/> (referer: None)
Traceback (most recent call last):
  File "C:\Users\malay\Documents\GitHub\Web\venv\Lib\site-packages\twisted\internet\defer.py", line 2017, in _inlineCallbacks
    result = context.run(gen.send, result)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\malay\Documents\GitHub\Web\ScrapyParsers\ScrapyParsers\spiders\BBR_Currensy.py", line 36, in parse
    page = response.meta["ScrapyParsers"]
           ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
KeyError: 'ScrapyParsers'
2025-01-18 06:09:50 [scrapy.core.engine] INFO: Closing spider (finished)
2025-01-18 06:09:50 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 207,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 31771,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'elapsed_time_seconds': 1.090688,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2025, 1, 17, 20, 9, 50, 218415, tzinfo=datetime.timezone.utc),
 'httpcompression/response_bytes': 201174,
 'httpcompression/response_count': 1,
 'items_per_minute': None,
 'log_count/DEBUG': 2,
 'log_count/ERROR': 1,
 'log_count/INFO': 10,
 'response_received_count': 1,
 'responses_per_minute': None,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'spider_exceptions/KeyError': 1,
 'start_time': datetime.datetime(2025, 1, 17, 20, 9, 49, 127727, tzinfo=datetime.timezone.utc)}
2025-01-18 06:09:50 [scrapy.core.engine] INFO: Spider closed (finished)

Паук

import scrapy
import redis
import json


class BbrCurrensySpider(scrapy.Spider):
    name = "BBR_Currensy"
    allowed_domains = ["bbr.ru"]
    start_urls = ["https://bbr.ru/"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Настроим соединение с Redis
        self.redis_client = redis.StrictRedis(
            host='localhost',
            port=6379,
            db=0,
            decode_responses=True
        )

        # Проверим подключение
        try:
            self.redis_client.ping()  # Проверяет соединение
            print("Соединение с Redis установлено успешно.")
        except redis.ConnectionError:
            print("Ошибка подключения к Redis.")

    def start_requests(self):
        yield scrapy.Request(
            self.start_urls[0],
            meta={"playwright": True, "playwright_include_page": True},
            callback=self.parse
        )

    async def parse(self, response):
        page = response.meta["ScrapyParsers"]
        if not page:
            self.logger.error("Page not found in meta!")
            return

        self.logger.info(f"Page found: {page.url}")
        # Закрываем страницу после выполнения
        html_content = await page.content()
        await page.close()

        # Передаём контент в Scrapy для дальнейшего парсинга
        response = scrapy.http.HtmlResponse(
            url=page.url, body=html_content, encoding='utf-8'
        )

        new_rates = {}

        for review in response.css(".css-13tn1x7.e314cwc4"):
            exchange_rate = review.css('span.css-11ctayd.exmh6wy0::text').get().replace(",", ".")
            currency_name = review.css('span.css-90qv05.e314cwc2::text').get()

            new_rates[currency_name] = float(exchange_rate)
            try:
                self.redis_client.set("exchange_rates", json.dumps(new_rates))
                print("Данные успешно сохранены в Redis.")
            except redis.RedisError as e:
                print(f"Ошибка при сохранении данных в Redis: {e}")

celery.py

import os
from celery import Celery
from ScrapyParsers.ScrapyParsers.spiders.BBR_Currensy import BbrCurrensySpider


# Установка переменной окружения для Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TomikoTradeProject.settings')

app = Celery('TomikoApp')

# Загрузка настроек из Django
app.config_from_object('django.conf:settings', namespace='CELERY')

app.autodiscover_tasks()

@app.task
def crawl_spider():
    from scrapy.crawler import CrawlerProcess
    from scrapy.utils.project import get_project_settings

    settings = get_project_settings()
    process = CrawlerProcess(settings)
    process.crawl(BbrCurrensySpider)
    process.start()

tasks.py

from celery import shared_task
from celery import Celery
from TomikoTradeProject.celery import crawl_spider
from cars.models import Cars
from TomikoTradeProject.celery import app
import redis
import json
import scrapy
from scrapy.crawler import CrawlerProcess
from ScrapyParsers.ScrapyParsers.spiders.BBR_Currensy import BbrCurrensySpider


redis_client = redis.StrictRedis(host="localhost", port=6379, db=0)

app = Celery('tasks')
@app.task
def run_scrapy_spider():
    crawl_spider()

Пример рабочего паука

import scrapy

class VkClipsSpider(scrapy.Spider):
    name = "VK_clips"
    allowed_domains = ["vk.com"]
    start_urls = ["https://vk.com/clips/tomiko_trade"]

    def start_requests(self):
        yield scrapy.Request(
            self.start_urls[0],
            meta={"playwright": True, "playwright_include_page": True},
            callback=self.parse_with_playwright
        )

    async def parse_with_playwright(self, response):
        page = response.meta["parsers"]

        # Закрываем страницу после выполнения
        html_content = await page.content()
        await page.close()

        # Передаём контент в Scrapy для дальнейшего парсинга
        response = scrapy.http.HtmlResponse(
            url=page.url, body=html_content, encoding='utf-8'
        )
        for review in response.css(".vkitGridItem__root--6OepO"):
            yield {
                "Link" : self.start_urls[0] + review.css('a::attr(href)').get(),
                "Prewiew" : review.css('img.vkuiImageBase__img.vkuiImageBase__img--objectFit-cover::attr(src)').get())
            }

Решение было найдено. По какой-то причине паук "не подсасывал" настройки. По итогу их всего-то и надо было прописать внутри паука.

А вот и рабочий и допиленный паучок:

import scrapy
import redis
import json


class BbrCurrensySpider(scrapy.Spider):
    name = "BBR_Currensy"
    allowed_domains = ["bbr.ru"]
    start_urls = ["https://bbr.ru/"]
    custom_settings = {
        "TWISTED_REACTOR": "twisted.internet.asyncioreactor.AsyncioSelectorReactor",
        "DOWNLOAD_HANDLERS": {
            "https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
            "http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
        }
    }
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Настроим соединение с Redis
        self.redis_client = redis.StrictRedis(
            host='localhost',
            port=6379,
            db=0,
            decode_responses=True
        )

        # Проверим подключение
        try:
            self.redis_client.ping()  # Проверяет соединение
            print("Соединение с Redis установлено успешно.")
        except redis.ConnectionError:
            print("Ошибка подключения к Redis.")

    def start_requests(self):
        yield scrapy.Request(
            self.start_urls[0],
            meta=dict(
                playwright=True,
                playwright_include_page=True
            )

        )

    async def parse(self, response):
        page = response.meta["playwright_page"]
        if not page:
            self.logger.error("Page not found in meta!")
            return

        self.logger.info(f"Page found: {page.url}")
        # Закрываем страницу после выполнения
        html_content = await page.content()
        await page.close()

        # Передаём контент в Scrapy для дальнейшего парсинга
        response = scrapy.http.HtmlResponse(
            url=response.url, body=html_content, encoding='utf-8'
        )

        new_rates = {}

        for review in response.css(".css-13tn1x7.e314cwc4"):
            exchange_rate = review.css('span.css-11ctayd.exmh6wy0::text').get().replace(",", ".")
            currency_name = review.css('span.css-90qv05.e314cwc2::text').get()

            new_rates[currency_name] = float(exchange_rate)
            try:
                self.redis_client.set("exchange_rates", json.dumps(new_rates))
                print("Данные успешно сохранены в Redis.")
            except redis.RedisError as e:
                print(f"Ошибка при сохранении данных в Redis: {e}")


Ответы (0 шт):