如何在scrapy spid中访问管道数据库池

2024-10-05 12:24:20 发布

您现在位置:Python中文网/ 问答频道 /正文

首先,我要做的是:

我有一个XMLFeedSpider,它遍历XML文件中的产品列表(节点),并创建以管道形式保存到数据库中的项。当我第一次看到一个产品时,我需要创建一个请求来对产品的url字段进行一些抓取以获取图像等。如果我看到相同的产品,我不想浪费时间/资源来做这件事,只想跳过这些额外的请求。要查看要跳过的产品,我需要访问我的数据库以查看该产品是否存在。在

以下是我可以想到的各种方法:

  1. 只需为spider中的每个产品创建一个db请求。这个 好像是个坏主意。在
  2. 在我的项目存储管道中,我已经创建了一个数据库池,如下所示: dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs)而且使用它似乎更有效,所以我不需要不断地创建新的数据库连接。我不知道如何在spider中访问实例化的pipeline类(这可能更像是一个普通的python问题)。
    注:这家伙基本上也在问同样的问题,但并没有真正得到他想要的答案。How to get the pipeline object in Scrapy spider
  3. 也许在开始爬网之前,把所有的产品网址都加载到内存中,这样我就可以在处理产品时对它们进行比较?哪里是个好地方?在
  4. 其他建议?在

更新:这是我与数据库池的管道

class PostgresStorePipeline(object):
    """A pipeline to store the item in a MySQL database.
    This implementation uses Twisted's asynchronous database API.
    """

    def __init__(self, dbpool):
        print "Opening connection pool..."
        dispatcher.connect(self.spider_closed, signals.spider_closed)
        self.dbpool = dbpool

    @classmethod
    def from_settings(cls, settings):
        dbargs = dict(
            host=settings['MYSQL_HOST'],
            database=settings['MYSQL_DBNAME'],
            user=settings['MYSQL_USER'],
            password=settings['MYSQL_PASSWD'],
            #charset='utf8',
            #use_unicode=True,
        )
        dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs)
        return cls(dbpool)

Tags: self数据库管道settingspipeline产品mysqlcp
1条回答
网友
1楼 · 发布于 2024-10-05 12:24:20

我想你的意思是URL,记住对于scrapyitem是一个数据输出,pipeline是处理这些输出项的机制。在

当然,您不需要打开许多连接来执行数据库查询,但是您必须执行必要的查询。这取决于您的数据库中有多少记录只执行一个查询,还是每个URL执行一个查询,您应该测试哪一个更适合您的情况。在

我建议您使用如下内容设置您自己的^{}

from scrapy.dupefilters import RFPDupeFilter

class DBDupeFilter(RFPDupeFilter):

    def __init__(self, *args, **kwargs):
        # self.cursor = .....                       # instantiate your cursor
        super(DBDupeFilter, self).__init__(*args, **kwargs)

    def request_seen(self, request):
        if self.cursor.execute("myquery"):          # if exists
            return True
        else:
            return super(DBDupeFilter, self).request_seen(request)

    def close(self, reason):
        self.cursor.close()                         # close  your cursor
        super(DBDupeFilter, self).close(reason)

更新

这里的问题是DUPEFILTER_CLASS没有在其request_seen对象上提供spider,甚至没有提供构造函数,所以我认为最好的方法是使用一个Downloader Middleware,在这里可以引发一个IgnoreRequest异常。在

  1. 在spider上实例化db连接,可以在spider本身(构造函数)上实现,也可以通过中间件或管道上的信号添加,我们将在中间件上添加:

    from scrapy.exceptions import IgnoreRequest
    
    class DBMiddleware(object):
    
        def __init__(self):
            pass
    
        @classmethod
        def from_crawler(cls, crawler):
            o = cls()
            crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
            return o
    
        def spider_opened(self, spider):
            spider.dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs)
    
        def process_request(self, request, spider):
            if spider.dbpool... # check if request.url inside the database
                raise IgnoreRequest()
    
  2. 现在在您的管道中,删除dbpool的实例化,并在必要时从spider参数中获取它,记住process_item接收项目和spider作为参数,因此您应该能够使用spider.dbpool来检查数据库连接。

  3. 记住activate your middleware

这样,您应该只在spider对象内执行一个db连接实例。在

相关问题 更多 >

    热门问题