#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 = ""