Получение Scrapy и pytest для работы с AsyncioSelectorReactor

Чтобы воспроизвести мою проблему

  • питон 3.12.1
  • скрап 2.11.2
  • pytest 8.2.1

В bookspider.py у меня есть:

from typing import Iterable

import scrapy
from scrapy.http import Request


class BookSpider(scrapy.Spider):
    name = None

    def start_requests(self) -> Iterable[Request]:
        yield scrapy.Request("https://books.toscrape.com/")

    def parse(self, response):
        books = response.css("article.product_pod")
        for book in books:
            yield {
                "name": self.name,
                "title": book.css("h3 a::text").get().strip(),
            }

В test_bookspider.py у меня есть:

import json
import os

from pytest_twisted import inlineCallbacks
from scrapy.crawler import CrawlerRunner
from twisted.internet import defer

from bookspider import BookSpider


@inlineCallbacks
def test_bookspider():
    runner = CrawlerRunner(
        settings = {
            "REQUEST_FINGERPRINTER_IMPLEMENTATION": "2.7",
            "FEEDS": {"books.json": {"format": "json"}},
            "TWISTED_REACTOR": "twisted.internet.asyncioreactor.AsyncioSelectorReactor",
            # "TWISTED_REACTOR": "twisted.internet.selectreactor.SelectReactor",
        }
    )
    yield runner.crawl(BookSpider, name = "books")

    with open("books.json", "r") as f:
        books = json.load(f)
    assert len(books) >= 1
    assert books[0]["name"] == "books"
    assert books[0]["title"] == "A Light in the ..."

    os.remove("books.json")

    defer.returnValue(None)

Если "TWISTED_REACTOR": "twisted.internet.asyncioreactor.AsyncioSelectorReactor" раскомментировать, я получаю следующую ошибку:

Exception: The installed reactor (twisted.internet.selectreactor.SelectReactor) does not match the requested one (twisted.internet.asyncioreactor.AsyncioSelectorReactor)

С "TWISTED_REACTOR": "twisted.internet.selectreactor.SelectReactor" без комментариев мой тест пройден.

Может ли кто-нибудь объяснить это поведение и, в более широком смысле, как тестировать CrawlerRunner или CrawlerProcess с помощью pytest?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы используете pytest-twisted, вам нужно указать ему установить соответствующий реактор, передав --reactor=asyncio в команду pytest, иначе он установит реактор по умолчанию. См. https://github.com/pytest-dev/pytest-twisted#using-the-plugin

как протестировать CrawlerRunner или CrawlerProcess с помощью pytest?

Вам не следует использовать CrawlerProcess в таких вещах, как тесты pytest, потому что он запустит и остановит реактор за вас. Если вам действительно нужно их протестировать, вам следует написать тесты, которые используют один процесс для каждого вызова CrawlerProcess.

Другие вопросы по теме

Похожие вопросы

Проблемы с макетом Matplotlib
Я попытался очистить веб-сайт с помощью Selenium Python и сохранить его в CSV, но он распечатал и дублировал только первый результат
Python Tkinter структурирован в класс: могут ли методы находиться в независимом файле?
Как исправить предупреждение Pydantic «Значение по умолчанию не является сериализуемым JSON» при использовании стороннего аннотированного типа? [несериализуемый-по умолчанию]
Убедитесь, что решение удовлетворяет PDE: FiPy
Ошибка AttributeError: объект «DataFrame» не имеет атрибута «append», попробовал pd.concat, но также вызвал ошибку
Ошибка типа при создании пользовательского набора данных с использованием набора данных HuggingFace
Существует ли в Python f-строка, эквивалентная std::quoted в C++?
Selenium — TypeError: невозможно создать экземпляр абстрактного класса Service без реализации абстрактного метода «command_line_args»
Поскольку запросы == 2.32.2 получили SSL/сертификат, проверка не удалась: самозаверяющий сертификат при использовании python-keycloak