Есть ли какой-нибудь пример того, как использовать элементы dataclass и scrapy?

#python #scrapy #python-dataclasses #scrapy-item

Вопрос:

Я проверял документацию в Scrapy по этому поводу: https://docs.scrapy.org/en/latest/topics/items.html#dataclass-objects

 from dataclasses import dataclass

@dataclass
class CustomItem:
    one_field: str
    another_field: int
 

К сожалению, они не приводят никаких примеров того, как использовать его в пауках. Я определяю свой элемент scrapy, используя этот синтаксис, и я вызываю его таким образом в своем коде:

         product = ProductItem(
            publicName=response.xpath(
                '//title/text()').re(r"(. ?)(?=( v?(CC-V)?(d .?){1,3}))")[0],
            description=None,
            productType=self.get_product_type(response),
            salesPage=response.xpath(
                'normalize-space(//div[@class="sales_page"]/center/a/@href)').get(),
            tags=[],
            developer=response.xpath(
                '//div[@class="website"]/a/div/div/div[@class="head"]/text()').get(),
            developerId=response.xpath(
                '//div[@class="fox-sidebar"]/div[4]/div/ul/li/span/a[@rel="tag"]/@href').re(r"/vendor/(.*)/")[0]
        )
 

Я получаю эту ошибку:
TypeError: 'ProductItem' object is not iterable

PS: Я ожидаю получить ошибку, если, например, определить значение класса в виде строки, когда ожидалось целое число с помощью scrapy.

Комментарии:

1. Это похоже на ошибку в каком-то коде, который не был предоставлен. Что касается PS, в документах говорится, что «Типы полей не применяются во время выполнения»..

Ответ №1:

После некоторых проб и ошибок я добился ожидаемого поведения с помощью валидатора типов классов данных библиотеки python:

код паука:

         product = ProductItem(
            publicName=response.xpath(
                '//title/text()').re(r"(. ?)(?=( v?(CC-V)?(d .?){1,3}))")[0],
            productType=self.get_product_type(response.xpath(
                '//div[@class="pagination-wrapper"]/ul/li/a/text()').get()),
            salesPage=response.xpath(
                'normalize-space(//div[@class="sales_page"]/center/a/@href)').get(),
            developer=response.xpath(
                '//div[@class="website"]/a/div/div/div[@class="head"]/text()').get(),
            developerId=response.xpath(
                '//div[@class="fox-sidebar"]/div[4]/div/ul/li/span/a[@rel="tag"]/@href').re(r"/vendor/(.*)/")[0],
        )
        yield { "product": product.__dict__ }
 

Очень важно, чтобы вы преобразовали экземпляр ProductItem в dict, иначе вы не сможете использовать этот элемент в своем конвейере с адаптером.

items.py код:

 from typing import List
from dataclasses import dataclass, field
from dataclass_type_validator import dataclass_validate

@dataclass_validate()
@dataclass()
class ProductItem():
    publicName: str
    productType: str
    salesPage: str
    developer: str
    developerId: str
    tags: List[str] = field(default_factory=list)
    description: str = ""