Закройте открытый файл csv в конвейере экспорта CSV scrapy - PullRequest
0 голосов
/ 26 мая 2020

Я пытаюсь очистить статьи по 100 компаниям, и я хочу сохранить содержимое из нескольких статей в отдельный файл CSV для каждой компании. У меня есть сборщик и конвейер экспорта csv, и он отлично работает, однако паук открывает новый файл csv для каждой компании (как и должно), не закрывая файл, открытый для предыдущей компании.

Файлы csv закрываются после закрытия паука, но из-за объема данных, которые я очищаю для каждой компании, размеры файлов значительны и вызывают нагрузку на память моих машин и не могут масштабироваться реалистично, учитывая, что если бы я хотел увеличить количество компаний (что я в конечном итоге хочу сделать), я в конечном итоге столкнусь с ошибкой из-за того, что одновременно открыто слишком много файлов. Ниже представлен мой конвейер экспорта CSV. Я хотел бы найти способ закрыть один CSV-файл для текущей компании, прежде чем переходить к следующей компании в том же пауке:

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

Я уверен, что есть это решение, но я не смог его понять. Был бы очень признателен за помощь в решении этой проблемы.

class PerTickerCsvExportPipeline:
    """Distribute items across multiple CSV files according to their 'ticker' field"""

    def open_spider(self, spider):
        self.ticker_to_exporter = {}

    def close_spider(self, spider):
        for exporter in self.ticker_to_exporter.values():
            exporter.finish_exporting()

    def _exporter_for_item(self, item):
        ticker = item['ticker']
        if ticker not in self.ticker_to_exporter:
            f = open('{}_article_content.csv'.format(ticker), 'wb')
            exporter = CsvItemExporter(f)
            exporter.start_exporting()
            self.ticker_to_exporter[ticker] = exporter
        return self.ticker_to_exporter[ticker]

    def process_item(self, item, spider):
        exporter = self._exporter_for_item(item)
        exporter.export_item(item)
        return item

1 Ответ

0 голосов
/ 26 мая 2020

Проблема, вероятно, в том, что вы держите все ItemExporter файлы и файлы открытыми до тех пор, пока паук не закроется. Я предлагаю вам попробовать закрыть CsvItemExporter и соответствующий файл для предыдущей компании, прежде чем открывать новую.

def open_spider(self, spider):
    self.ticker_to_exporter = {}
    self.files = []

def close_exporters(self):
    for ticker, exporter in self.ticker_to_exporter.items():
        exporter.finish_exporting()
        del self.ticker_to_exporter[ticker]

def close_files(self):
    for i, f in enumerate(self.files):
        f.close()
        del self.files[i]

def close_spider(self, spider):
    self.close_exporters()
    self.close_files()

def _exporter_for_item(self, item):
    ticker = item['ticker']
    if ticker not in self.ticker_to_exporter:
        self.close_exporters()
        self.close_files()
        f = open('{}_article_content.csv'.format(ticker), 'a')
        self.files.append(f)
        exporter = CsvItemExporter(f)
        exporter.start_exporting()
        self.ticker_to_exporter[ticker] = exporter
    return self.ticker_to_exporter[ticker]
...