Как использовать foreach ключевое слово на пользовательских объектах в C#

Верно, что в документации Scrapy четко не указано, где разместить экспонента товаров. Чтобы использовать элемент Экспортер, выполните следующие действия.

  1. Выберите класс Экспортер элемента и импортируйте его в pipeline.py в каталоге проекта. Это может быть предопределенный Item Exporter (например, XmlItemExporter) или определенный пользователем (например, FanItemExporter, определенный в вопросе)
  2. Создайте класс Pipeline Item в pipeline.py. Создайте экземпляр импортированного Item Exporter в этом классе. Подробности будут объяснены в более поздней части ответа.
  3. Теперь зарегистрируйте этот класс конвейера в файле settings.py.

Ниже приводится подробное объяснение каждого шага , Решение вопроса включено в каждый шаг.

Шаг 1

  • При использовании заданного класса Item Exporter импортируйте его из модуля scrapy.exporters. Пример: from scrapy.exporters import XmlItemExporter
  • Если вам нужен пользовательский экспортер, определите пользовательский класс в файле. Я предлагаю поместить класс в файл exporters.py. Поместите этот файл в папку проекта (где settings.py, items.py находятся). При создании нового подкласса всегда рекомендуется импортировать BaseItemExporter. Было бы целесообразно, если мы намерены полностью изменить функциональность. Однако в этом вопросе большая часть функциональности близка к JsonLinesItemExporter.

Следовательно, я прикрепляю две версии одного и того же ItemExporter. Одна версия расширяет класс BaseItemExporter, а другая расширяет JsonLinesItemExporter класс

Версия 1 : Расширение BaseItemExporter

Поскольку BaseItemExporter является родительским класс start_exporting(), finish_exporting(), export_item() должен быть переопределен в соответствии с нашими потребностями.

from scrapy.exporters import BaseItemExporter
from scrapy.utils.serialize import ScrapyJSONEncoder
from scrapy.utils.python import to_bytes

class FanItemExporter(BaseItemExporter):

    def __init__(self, file, **kwargs):
        self._configure(kwargs, dont_fail=True)
        self.file = file
        self.encoder = ScrapyJSONEncoder(**kwargs)
        self.first_item = True

    def start_exporting(self):
        self.file.write(b'{\'product\': [')

    def finish_exporting(self):
        self.file.write(b'\n]}')

    def export_item(self, item):
        if self.first_item:
            self.first_item = False
        else:
            self.file.write(b',\n')
        itemdict = dict(self._get_serialized_fields(item))
        self.file.write(to_bytes(self.encoder.encode(itemdict)))

Версия 2 : Расширение JsonLinesItemExporter

JsonLinesItemExporter обеспечивает точно такую ​​же реализацию метода export_item(). Поэтому переопределяются только методы start_exporting() и finish_exporting().

Реализация JsonLinesItemExporter показана в папке python_dir\pkgs\scrapy-1.1.0-py35_0\Lib\site-packages\scrapy\exporters.py

from scrapy.exporters import JsonItemExporter

class FanItemExporter(JsonItemExporter):

    def __init__(self, file, **kwargs):
        # To initialize the object we use JsonItemExporter's constructor
        super().__init__(file)

    def start_exporting(self):
        self.file.write(b'{\'product\': [')

    def finish_exporting(self):
        self.file.write(b'\n]}')

Примечание: при записи данных в файл, важно отметить, что стандартные классы Item Exporter ожидают двоичные файлы. Следовательно, мы должны открыть файл с двоичным режимом (b). По той же причине метод write() в обеих версиях записывает bytes в файл.

Шаг 2

Создание класса Pipeline Item.

from project_name.exporters import FanItemExporter

class FanExportPipeline(object):
    def __init__(self, file_name):
        # Storing output filename
        self.file_name = file_name
        # Creating a file handle and setting it to None
        self.file_handle = None

    @classmethod
    def from_crawler(cls, crawler):
        # getting the value of FILE_NAME field from settings.py
        output_file_name = crawler.settings.get('FILE_NAME')

        # cls() calls FanExportPipeline's constructor
        # Returning a FanExportPipeline object
        return cls(output_file_name)

    def open_spider(self, spider):
        print('Custom export opened')

        # Opening file in binary-write mode
        file = open(self.file_name, 'wb')
        self.file_handle = file

        # Creating a FanItemExporter object and initiating export
        self.exporter = FanItemExporter(file)
        self.exporter.start_exporting()

    def close_spider(self, spider):
        print('Custom Exporter closed')

        # Ending the export to file from FanItemExport object
        self.exporter.finish_exporting()

        # Closing the opened output file
        self.file_handle.close()

    def process_item(self, item, spider):
        # passing the item to FanItemExporter object for expoting to file
        self.exporter.export_item(item)
        return item

Шаг 3

Теперь, когда мы определили Конвейер экспорта товаров, нам необходимо зарегистрировать конвейер в файле settings.py. Мы также используем поле FILE_NAME из файла settings.py. Это поле содержит имя файла выходного файла.

Добавьте следующие строки в файл settings.py.

FILE_NAME = 'path/outputfile.ext'
ITEM_PIPELINES = {
    'project_name.pipelines.FanExportPipeline' : 600,
}

Если ITEM_PIPELINES уже раскоментирован, добавьте следующую строку в словарь ITEM_PIPELINES.

'project_name.pipelines.FanExportPipeline' : 600,

Таким образом, мы можем создавать настраиваемые конвейеры экспорта товаров и использовать их в нашем проекте.

19
задан George Stocker 30 December 2008 в 01:14
поделиться

2 ответа

Учитывая теги, я предполагаю, что Вы имеете в виду в.NET - и я приму решение говорить о C#, поскольку это - то, о чем я знаю.

foreach оператор (обычно) использует IEnumerable и IEnumerator или их универсальные кузены. Оператор формы:

foreach (Foo element in source)
{
    // Body
}

, где source реализации IEnumerable<Foo> примерно [1 116] эквивалентные:

using (IEnumerator<Foo> iterator = source.GetEnumerator())
{
    Foo element;
    while (iterator.MoveNext())
    {
        element = iterator.Current;
        // Body
    }
}

Примечание, что эти IEnumerator<Foo> расположен в конце, однако выходы оператора. Это важно для блоков итератора.

Для реализации IEnumerable<T> или IEnumerator<T> самостоятельно самый легкий путь состоит в том, чтобы использовать блок итератора. Вместо того, чтобы писать все подробности здесь, вероятно, лучше просто отослать Вас к [1 113] глава 6 C# подробно , который является бесплатной загрузкой. Вся глава 6 находится на итераторах. У меня есть еще несколько статей о моем C# подробно сайт, также:

Как быстрый пример, хотя:

public IEnumerable<int> EvenNumbers0To10()
{
    for (int i=0; i <= 10; i += 2)
    {
        yield return i;
    }
}

// Later
foreach (int x in EvenNumbers0To10())
{
    Console.WriteLine(x); // 0, 2, 4, 6, 8, 10
}

Для реализации IEnumerable<T> для типа можно сделать что-то как:

public class Foo : IEnumerable<string>
{
    public IEnumerator<string> GetEnumerator()
    {
        yield return "x";
        yield return "y";
    }

    // Explicit interface implementation for nongeneric interface
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator(); // Just return the generic version
    }
}
41
ответ дан 30 November 2019 в 02:45
поделиться

(Я принимаю C# здесь)

, Если у Вас есть список пользовательских объектов, можно просто использовать foreach таким же образом, как Вы делаете с любым другим объектом:

List<MyObject> myObjects = // something
foreach(MyObject myObject in myObjects)
{
     // Do something nifty here
}

, Если Вы хотите создать свой собственный контейнер, можно использовать ключевое слово урожая (от.Net 2.0, и вверх я верю) вместе с интерфейсом IEnumerable.

class MyContainer : IEnumerable<int>
{
    private int max = 0;
    public MyContainer(int max)
    {
        this.max = max;
    }

    public IEnumerator<int> GetEnumerator()
    {
        for(int i = 0; i < max; ++i)
            yield return i;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

И затем используют его с foreach:

MyContainer myContainer = new MyContainer(10);
foreach(int i in myContainer)
    Console.WriteLine(i);
7
ответ дан 30 November 2019 в 02:45
поделиться
Другие вопросы по тегам:

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