scrapy 如何在多个模块里共用一个数据库连接池 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
a65420321a
V2EX    Python

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

  •  
  •   a65420321a 2020 年 7 月 8 日 3077 次点击
    这是一个创建于 2028 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有个 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 复用同一个链接吗?
    搜了一圈,各种出错,没有实际进展
    12 条回复    2020-07-13 09:54:38 +08:00
    zdnyp
        1
    zdnyp  
       2020 年 7 月 8 日
    写一个 pipeline 的基类,在 open_spider 的时候连接,close_spider 的时候关闭
    a65420321a
        2
    a65420321a  
    OP
       2020 年 7 月 8 日
    @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 里面要怎么调用这个 elf.conn 呢?
    996635
        3
    996635  
       2020 年 7 月 8 日
    建议楼主看一下 scrapy 自带的几个 extensions 例子, 可能会有一些灵感. 印象中 scrapy 准备的几个钩子可以做这个事情.
    另外,如果想全局复用连接池, 要考虑线程安全的问题.
    spider 之间传递上下文靠 meta.
    pipeline 里可以获取 spider 的对象.
    a65420321a
        4
    a65420321a  
    OP
       2020 年 7 月 8 日
    @996635

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

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

    话说,为啥我搜出来的都是说在 pipeline 下的 open_spider 里创建数据库链接,这样的话别的地方通过什么方式调用呢?
    Kobayashi
        5
    Kobayashi  
       2020 年 7 月 9 日 via Android
    @zdnyp 搭车问一下。我目前也是基类,每个 pipeline 绑定一个 Redis connection 。不过不太明白 itempipeline 工作原理,itempipeline 支持并行还是并发,pipeline 上单一 Redis 连接后用吗,要必要开连接池?

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

    scrapy 文档里 architecture 解释的太简单了。
    Kobayashi
        7
    Kobayashi  
       2020 年 7 月 9 日
    我的思路是

    1. 每个 Pipeline 一个 redis 连接。由于不明白 pipeline 工作原理(并发?并行?),不确定要不要开连接池。
    2. pipeline 上没有 redis 连接。直接绑在 Spider 上, Pipeline.process(self,item,spider) 可以访问到 spider 上的 redis 连接。这个恐怕需要连接池,大小不知道设置多少合适。
    a65420321a
        8
    a65420321a  
    OP
       2020 年 7 月 9 日
    @Kobayashi
    我之前一直在纠结,怎么在 spider 里面直接调用 pipeline 的 redis 链接,没有相通,最后我是在 spider 里面声明了 redis 连接池,在 pipeline 和 middleware 通过 spider 参数直接调用 redis 链接
    现在看下来,在 pipeline 的 open_spider 中声明 redis 链接,在 spider 里面把需要筛选的东西处理成不同的 item,通过 pipeline 的 process_item 调用 redis 链接。。
    我没理解错吧?
    可是,如果这样的话,我需要在 middleware 里使用代理,也要用到 redis,这又要怎么搞。。。
    Kobayashi
        9
    Kobayashi  
       2020 年 7 月 9 日
    @a65420321a 按照我定义 RedisPipeline 类的方法再定义一个 ProxyPipeline 基类。自己创建的 MyPipeline 同时继承这 2 个类即可。我自己使用方式是在 Pipeline 中同时使用 redis 和 database 连接。
    a65420321a
        10
    a65420321a  
    OP
       2020 年 7 月 10 日
    @Kobayashi
    。。。pipeline 里面可以给 request 加代理吗?
    Kobayashi
        11
    Kobayashi  
       2020 年 7 月 11 日 via Android
    @a65420321a pipeline 只能拿到 Item,也就是你从结果中拿到的数据。加代理要在请求被 downloader 处理前,自定义 downloader middleware 即可。

    兄弟,翻翻教程和文档好吗?教程的话推荐《 Python 3 爬虫开发实战》的最后几张 scrapy 讲解,介绍了 scrapy 架构。重要的是带了很多可以生产直接使用的实例。之后读完文档就可以随意用了。
    a65420321a
        12
    a65420321a  
    OP
       2020 年 7 月 13 日
    @Kobayashi
    看过的~你们说 pipeline 让我以为 middleware 可以调 pipeline 来着。。。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3197 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 12:44 PVG 20:44 LAX 04:44 JFK 07:44
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86