跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • scrapy 如何在多个模块里共用一个数据库连接池
未分類
19 7 月 2020

scrapy 如何在多个模块里共用一个数据库连接池

scrapy 如何在多个模块里共用一个数据库连接池

資深大佬 : a65420321a 18

有个 scrapy 项目
整体流程大概是:
spider.start_requests 从 redis 的 tasks_keys 里获取 url
middleware.proxyMiddleware.process_request 从 redis 的 proxy_keys 里获取代理
spider.parse 解析出 item,需深度抓取的 url,深度抓取 url 放入 redis 的 tasks_keys 里
pipelines.MyItem 把解析出的 item 存入 redis 的 item_keys 里面
。。。。

总结来说,有 4 个地方需要用到同一个 redis 数据库,区别只在 key
目前的写法是,
middleware.proxyMiddleware 里面__init__声明了 redis.ConnectionPool 连接池,以及 redis.StrictRedis 连接
在 pipelines.MyItem 和 spider 继承的类__init__里面全部粘贴复制了一遍。。。

一模一样的代码写了三个地方

虽然程序可以正常跑,但是,这方法越看越觉得傻
有什么方法可以只声明一个 redis 链接,然后在 spider 、middleware 、pipeline 复用同一个链接吗?
搜了一圈,各种出错,没有实际进展

大佬有話說 (11)

  • 資深大佬 : zdnyp

    写一个 pipeline 的基类,在 open_spider 的时候连接,close_spider 的时候关闭

  • 主 資深大佬 : a65420321a

    @zdnyp

    from .settings import ITEM_KEY
    import json, redis

    class RedisPipeline:

    def __init__(self, redis_host, redis_port, redis_db):
    self.redis_host = redis_host
    self.redis_port = redis_port
    self.redis_db = redis_db

    @classmethod
    def from_crawler(cls, crawler):
    return cls(
    redis_host=crawler.settings.get(‘REDIS_HOST’),
    redis_port=crawler.settings.get(‘REDIS_PORT’),
    redis_db=crawler.settings.get(‘REDIS_DB’)
    )

    def open_spider(self, spider):
    self.pool = redis.ConnectionPool(host=self.redis_host,
    port=self.redis_port,
    db=self.redis_db)
    self.conn = redis.StrictRedis(connection_pool=self.pool)
    print(‘#### pipelines.open_spider’)

    def close_spider(self, spider):
    pass

    def process_item(self, item, spider):
    self.conn.rpush(ITEM_KEY, json.dumps(item))
    return item

    这样没错吧?
    我没搞懂的是,在 middleware 和 spider 里面要怎么调用这个 self.conn 呢?

  • 資深大佬 : 996635

    建议主看一下 scrapy 自带的几个 extensions 例子, 可能会有一些灵感. 印象中 scrapy 准备的几个钩子可以做这个事情.
    另外,如果想全局复用连接池, 要考虑线程安全的问题.
    spider 之间传递上下文靠 meta.
    pipeline 里可以获取 spider 的对象.

  • 主 資深大佬 : a65420321a

    @996635

    额,你说的钩子指的是哪些?

    数据库链接搞定了
    在 spider 下__init__构建了 self.pool 和 self.conn
    然后在 pipeline 里通过 process_item 中的 spider 参数调用 spider.conn 可以复用数据库链接
    middleware 同样是通过 process_request 的 spider 参数

    话说,为啥我搜出来的都是说在 pipeline 下的 open_spider 里创建数据库链接,这样的话别的地方通过什么方式调用呢?

  • 資深大佬 : Kobayashi

    @zdnyp 搭车问一下。我目前也是基类,每个 pipeline 绑定一个 Redis connection 。不过不太明白 itempipeline 工作原理,itempipeline 支持并行还是并发,pipeline 上单一 Redis 连接后用吗,要必要开连接池?

    另外实际上 Redis 连接也能绑在 spider 上。spider 应该只有一个实例,异步的话是不是需要 redis 连接池? Redis 连接到底跟着谁比较好。

    scrapy 文档里 architecture 解释的太简单了。

  • 資深大佬 : Kobayashi

    @a65420321a 接着。https://gist.github.com/laggardkernel/0489ac1ef6ee74839ef545c7d72e085e

  • 資深大佬 : Kobayashi

    我的思路是

    1. 每个 Pipeline 一个 redis 连接。由于不明白 pipeline 工作原理(并发?并行?),不确定要不要开连接池。
    2. pipeline 上没有 redis 连接。直接绑在 Spider 上, Pipeline.process(self,item,spider) 可以访问到 spider 上的 redis 连接。这个恐怕需要连接池,大小不知道设置多少合适。

  • 主 資深大佬 : a65420321a

    @Kobayashi
    我之前一直在纠结,怎么在 spider 里面直接调用 pipeline 的 redis 链接,没有相通,最后我是在 spider 里面声明了 redis 连接池,在 pipeline 和 middleware 通过 spider 参数直接调用 redis 链接
    现在看下来,在 pipeline 的 open_spider 中声明 redis 链接,在 spider 里面把需要筛选的东西处理成不同的 item,通过 pipeline 的 process_item 调用 redis 链接。。
    我没理解错吧?
    可是,如果这样的话,我需要在 middleware 里使用代理,也要用到 redis,这又要怎么搞。。。

  • 資深大佬 : Kobayashi

    @a65420321a 按照我定义 RedisPipeline 类的方法再定义一个 ProxyPipeline 基类。自己创建的 MyPipeline 同时继承这 2 个类即可。我自己使用方式是在 Pipeline 中同时使用 redis 和 database 连接。

  • 主 資深大佬 : a65420321a

    @Kobayashi
    。。。pipeline 里面可以给 request 加代理吗?

  • 資深大佬 : Kobayashi

    @a65420321a pipeline 只能拿到 Item,也就是你从结果中拿到的数据。加代理要在请求被 downloader 处理前,自定义 downloader middleware 即可。

    兄弟,翻翻教程和文档好吗?教程的话推荐《 Python 3 爬虫开发实战》的最后几张 scrapy 讲解,介绍了 scrapy 架构。重要的是带了很多可以生产直接使用的实例。之后读完文档就可以随意用了。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具