scrapy多模块复用同一个数据库链接

工作中遇到的一个问题

为方便去重,爬虫起始链接及爬虫结果数据都存放在redis中。

代理是爬虫小组共用的,同样存在redis里面。

爬虫过程中,由于深度抓取会产生很多新的链接,这部分链接也需要放在redis起始链接中。


上述总计4种数据,存放于同一个redis库下属3个不同的key中:

爬虫起始链接 and 深度抓取新生链接 ——> tasks_key

代理 ——> proxy_key

爬虫结果数据 ——> item_key


这就导致了,在scrapy项目代码中,我需要在spider.py、pipilines.py、middleware.py这三个不同的模块中使用同一个数据库


最初代码,在三个模块下自定义类的__init__方法中声明redis链接,分别在parse(),process_item(),process_request()中调用各自的redis链接。。。这三份代码除了self.REDIS_KEY不同,其余部分一!模!一!样!


つ﹏⊂虽然代码运行起来是没问题的,可这写法蠢的不行,实在接受不了,改!

然后,google尝试了一下午,可能是我搜索关键词用的太挫~愣是没找到解决方案。。。。。

google告诉我需要在pipeline中定义open_spider方法和close_spider方法用于建立/关闭数据库链接。可是,此时的self是一个pipeline实例,我要怎么在middleware中通过pipeline实例调用数据库链接啊~臣妾不知道哇,也没搜到结果哇。


啥也不说了,自己试!

一、通过spider参数调用

1.爬虫文件

# spider.py

import scrapy,redis

from baiduSpider.items import BaiduItem              # 项目名叫baiduSpider,自定义item叫baiduItem

from baiduSpider.settings import TASKS_KEY    # settings中定义的三个redis键,spider中使用的叫TASKS_KEY


class MySpider(scrpy.Spider):

        name = 'baidu'

        allowed_domains = ['www.baidu.com']

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

                self.redis_host = redis_host

                self.redis_port = redis_port

                self.redis_db = redis_db

                self.pool = redis.ConnectionPool(host=self.redis_host, 

                                                    port=self.redis_port, 

                                                    db=self.redis_db) 

                self.conn = redis.StrictRedis(connection_pool=self.pool) 

        @classmethod

        def from_crawler(cls, crawler):

                 return cls( redis_host=crawler.settings.get('PROXY_REDIS_HOST'),                                     redis_port=crawler.settings.get('PROXY_REDIS_PORT'),                                     redis_db=crawler.settings.get('PROXY_REDIS_DB') ) 


        def start_requests(self): 

                   url = self.conn.blpop(TASKS_KEY, 600)

                   yield scrapy.Request(url, callback=slef.parse)

        def parse(self, response):

                    item = BaiduItem

                    yield item

                    nextPages = response.xpath('').extrace()

                    for nextPage in nextPages:                 

                            self.conn.rpush(TASKS_KEY, nextPage)

通过类方法from_crawler从settings.py中获取redis相关参数,在__init__中创建redis连接池self.pool及redis连接self.conn

start_requests方法直接调用self.conn从redis取数据,parse方法也可以直接调用self.conn往redis存数据

2.中间件

# middlewares.py

from zhipin.settings import PROXY_KEY

class RandomProxyMiddleware:

        def process_request(self, request, spider):

                proxy = spider.conn.blpop(PROXY_KEY, 600)

                if proxy!=None:

                        proxy = proxy[1]

                        spider.conn.rpush(PROXY_KEY, proxy)

                        proxy = json.loads(proxy.decode('utf-8'))

                        request.meta['proxy'] = "https://%s" % proxy

process_request方法有spider参数,这里的spider就是上面定义的MySpider,通过spider.conn可直接调用MySpider下的self.conn

3.项目管道

# pipelines.py

import json,redis 

from .settings import ITEM_KEY

class MyItemPipeline:

        def process_item(self, item, spider):

                data = dict(item)

                spider.conn.rpush(ITEM_KEY, json.dumps(data))

                return item

同上,还是通过spider参数调用

二、交给pipeline处理

此时,又过了一天,通过spider类声明redis链接,在其他模块中通过spider参数调用redis链接稳定运行了一天。

我又开始回头继续琢磨google出来的pipeline声明redis链接给其他模块使用,终于,琢磨通了.......

我并不是必须在spider中处理那些深度抓取新生的链接,我完全可以再写一个HrefItem

spider将不同的数据处理成不同的item(HrefItem和DataItem),scrapy会将这些item交给定义好的不同的pipeline处理

由于需要多个pipeline,这些pipeline都需要用到redis链接

这需要自定义一个RedisPipeline基类,在open_spider中建立redis链接

然后再定义其他pipeline,继承自RedisPipeline,各自重写process_item方法对不同的item做处理

这样,spider通过不同的pipeline中连接redis对item(HrefItem和DataItem)做相应处理存入不同的key(ITEM_KEY和TASKS_KEY)

ps:此方法还有一个问题没想通,middleware中的redis要怎么处理?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343