我正在定义一个将项目推送到消息队列的项目导出器。以下是代码。
from scrapy.contrib.exporter import JsonLinesItemExporter
from scrapy.utils.serialize import ScrapyJSONEncoder
from scrapy import log
from scrapy.conf import settings
from carrot.connection import BrokerConnection, Exchange
from carrot.messaging import Publisher
log.start()
class QueueItemExporter(JsonLinesItemExporter):
def __init__(self, **kwargs):
log.msg("Initialising queue exporter", level=log.DEBUG)
self._configure(kwargs)
host_name = settings.get('BROKER_HOST', 'localhost')
port = settings.get('BROKER_PORT', 5672)
userid = settings.get('BROKER_USERID', "guest")
password = settings.get('BROKER_PASSWORD', "guest")
virtual_host = settings.get('BROKER_VIRTUAL_HOST', "/")
self.encoder = settings.get('MESSAGE_Q_SERIALIZER', ScrapyJSONEncoder)(**kwargs)
log.msg("Connecting to broker", level=log.DEBUG)
self.q_connection = BrokerConnection(hostname=host_name, port=port,
userid=userid, password=password,
virtual_host=virtual_host)
self.exchange = Exchange("scrapers", type="topic")
log.msg("Connected", level=log.DEBUG)
def start_exporting(self):
spider_name = "test"
log.msg("Initialising publisher", level=log.DEBUG)
self.publisher = Publisher(connection=self.q_connection,
exchange=self.exchange, routing_key="scrapy.spider.%s" % spider_name)
log.msg("done", level=log.DEBUG)
def finish_exporting(self):
self.publisher.close()
def export_item(self, item):
log.msg("In export item", level=log.DEBUG)
itemdict = dict(self._get_serialized_fields(item))
self.publisher.send({"scraped_data": self.encoder.encode(itemdict)})
log.msg("sent to queue - scrapy.spider.naukri", level=log.DEBUG)
我遇到了一些问题。这些项目未提交到队列。我已将以下内容添加到我的设置中:
FEED_EXPORTERS = {
"queue": 'scrapers.exporters.QueueItemExporter'
}
FEED_FORMAT = "queue"
LOG_STDOUT = True
代码不会引发任何错误,也无法看到任何日志消息。我的智慧结束了如何调试它。
非常感谢任何帮助。
答案 0 :(得分:5)
“Feed Exporters”是快速(以某种程度上是脏的)快捷方式来调用某些“标准”项目导出器。不是根据设置设置Feed导出器,而是将自定义项导出器硬连接到自定义管道,如http://doc.scrapy.org/en/0.14/topics/exporters.html#using-item-exporters所述:
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
from scrapy.contrib.exporter import XmlItemExporter
class MyPipeline(object):
def __init__(self):
...
dispatcher.connect(self.spider_opened, signals.spider_opened)
dispatcher.connect(self.spider_closed, signals.spider_closed)
...
def spider_opened(self, spider):
self.exporter = QueueItemExporter()
self.exporter.start_exporting()
def spider_closed(self, spider):
self.exporter.finish_exporting()
def process_item(self, item, spider):
# YOUR STUFF HERE
...
self.exporter.export_item(item)
return item
答案 1 :(得分:1)
提示:从官方文档开始的Writing Items to MongoDb就是一个很好的例子。
我做过类似的事情。我创建了一个管道,将每个项目放入类似S3的服务(我在这里使用Minio,但你明白了)。它为每个蜘蛛创建一个新的存储桶,并将每个项目放入一个具有随机名称的对象中。 完整的源代码可以在my repo中找到。
从教程中的简单引号spider开始:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = ['http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/1/']
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text':quote.css('span.text::text').extract_first(),
'author':quote.css('span small::text').extract_first(),
'tags':quote.css('div.tags a.tag::text').extract()
}
next_page = response.css('li.next a::attr(href)').extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
在settings.py
:
ITEM_PIPELINES = {
'scrapy_quotes.pipelines.ScrapyQuotesPipeline': 300,
}
在scrapy_quotes/pipelines.py
中创建管道和项目导出器:
import uuid
from StringIO import StringIO
from scrapy.contrib.exporter import BaseItemExporter
from scrapy.conf import settings
from scrapy import signals
from scrapy.xlib.pydispatch import dispatcher
from scrapy import log
from scrapy.utils.python import to_bytes
from scrapy.utils.serialize import ScrapyJSONEncoder
class S3ItemExporter(BaseItemExporter):
def __init__(self, bucket, **kwargs):
self._configure(kwargs)
self.bucket = bucket
kwargs.setdefault('ensure_ascii', not self.encoding)
self.encoder = ScrapyJSONEncoder(**kwargs)
def start_exporting(self):
self.client = connect()
create_bucket(self.client, self.bucket)
def finish_exporting(self):
log.msg("Done from S3 item exporter", level=log.DEBUG)
def export_item(self, item):
log.msg("S3 item exporter got item: %s" % item, level=log.DEBUG)
itemdict = dict(self._get_serialized_fields(item))
data = self.encoder.encode(itemdict)
size = len(data)
object_data = StringIO(data)
name = str(uuid.uuid4())
put_object(self.client, self.bucket, name, object_data, size)
class ScrapyQuotesPipeline(object):
"""Export scraped items, to different buckets,
one per spider"""
@classmethod
def from_crawler(cls, crawler):
pipeline = cls()
crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
return pipeline
def spider_opened(self, spider):
self.exporter = S3ItemExporter(spider.name)
self.exporter.start_exporting()
def spider_closed(self, spider):
self.exporter.finish_exporting()
def process_item(self, item, spider):
self.exporter.export_item(item)
return item
# S3 Related
from minio import Minio
import os
from minio.error import ResponseError
def connect():
return Minio('192.168.1.111:9000',
access_key='0M6PYKBBAVQVQGVWVZKQ',
secret_key='H6vPxz0aHSMZPgagZ3G0lJ6CbhN8RlTtD78SPsL8',
secure=False)
def create_bucket(client, name):
client.make_bucket(name)
def put_object(client, bucket_name, object_name, object_data, size):
client.put_object(bucket_name, object_name, object_data, size)
答案 2 :(得分:0)
我遇到了同样的问题,尽管可能会有一些版本更新。为我解决这个问题的小细节是在FEED_URI = "something"
中设置settings.py
。如果没有这个,FEED_EXPORTERS
中的条目就完全没有得到尊重。