scrapyd несколько пауков, пишущих элементы в один файл

У меня есть сервер scrapyd с несколькими запущенными пауками одновременно, я запускаю пауков одного за другим, используя конечную точку schedule.json. Все пауки пишут содержимое в общий файл, используя конвейер

class JsonWriterPipeline(object):

def __init__(self, json_filename):
    # self.json_filepath = json_filepath
    self.json_filename = json_filename
    self.file = open(self.json_filename, 'wb')

@classmethod
def from_crawler(cls, crawler):
    save_path='/tmp/'
    json_filename=crawler.settings.get('json_filename', 'FM_raw_export.json')
    completeName = os.path.join(save_path, json_filename) 
    return cls(
        completeName
    )

def process_item(self, item, spider):
    line = json.dumps(dict(item)) + "\n"
    self.file.write(line)
    return item

После запуска пауков я вижу, как они правильно собирают данные, элементы хранятся в файлах XXXX.jl и пауки работают правильно, однако просканированное содержимое не отражается в общем файле. Пауки, кажется, работают хорошо, однако конвейер плохо выполняет свою работу и не собирает данные в общий файл.

Я также заметил, что только один паук пишет в файл одновременно.

1 ответ

Решение

Я не вижу веских причин делать то, что вы делаете:) Вы можете изменить json_filename установка путем установки аргументов на вашем скрепиде schedule.json Запрос. Затем вы можете заставить каждого паука генерировать немного разные файлы, которые вы объединяете с пост-обработкой или во время запроса. Вы также можете написать JSON-файлы, аналогичные тем, которые вы имеете, просто установив FEED_URI значение ( пример). Если вы пишете в один файл одновременно из нескольких процессов (особенно когда вы открываете с 'wb' режим) вы ищете поврежденные данные.

Редактировать:

После того, как вы немного лучше поймете, что вам нужно - в данном случае - это беспроблемный запуск нескольких обходов с разными пауками, каждый из которых сканирует свой веб-сайт. Процесс потребителя постоянно отслеживает один файл.

Есть несколько решений, в том числе:

  • именованные трубы

Относительно прост в реализации и подходит только для очень маленьких предметов ( см. Здесь)

  • RabbitMQ или какой-либо другой механизм организации очередей

Отличное решение, но может быть немного излишним

  • База данных, например, решение на основе SQLite

Красиво и просто, но, вероятно, требует некоторого кодирования (пользовательский потребитель)

  • Хороший inotifywaitили другое решение для мониторинга файловой системы

Хороший и, вероятно, простой в реализации

Последний вариант кажется мне наиболее привлекательным. когда scrapy crawl заканчивает ( сигнал spider_closed), перемещает, копирует или создает мягкую ссылку для FEED_URL файл в каталог, который вы отслеживаете с помощью скрипта, как это. mv или же ln это атомарная операция Unix, так что вы должны быть в порядке. Взломайте скрипт, чтобы добавить новый файл на ваш tmp файл, который вы передаете один раз в вашу потребительскую программу.

Используя этот способ, вы используете экспортеры каналов по умолчанию для записи ваших файлов. Конечное решение настолько простое, что вам не нужен конвейер. Простое расширение должно отвечать всем требованиям.

На extensions.py в том же каталоге, что и settings.py:

from scrapy import signals
from scrapy.exceptions import NotConfigured

class MoveFileOnCloseExtension(object):

    def __init__(self, feed_uri):
        self.feed_uri = feed_uri

    @classmethod
    def from_crawler(cls, crawler):
        # instantiate the extension object
        feed_uri = crawler.settings.get('FEED_URI')
        ext = cls(feed_uri)

        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)

        # return the extension object
        return ext

    def spider_closed(self, spider):
        # Move the file to the proper location
        # os.rename(self.feed_uri, ... destination path...)

На ваше settings.py:

EXTENSIONS = {
    'myproject.extensions.MoveFileOnCloseExtension': 500,
}
Другие вопросы по тегам