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,
}