爬虫scrapy-redis分布式

一、scrapy和scrapy-redis区别
  1、Scrapy 是一个通用的爬虫框架,但是不支持分布式,
    Scrapy-redis是为了更方便地实现Scrapy分布式爬取,而提供了一些以redis为基础的组件(仅有组件)。
    安装:pip3 install scrapy-redis
  2、Scrapy-redis提供了下面四种组件(components):(四种组件意味着这四个模块都要做相应的修改)
    Scheduler
    Duplication Filter
    Item Pipeline
    Base Spider
  3、scrapy-redis框架:
    1.框架图


    2.如上图所示,scrapy-redis在scrapy的架构上增加了redis,基于redis的特性拓展了如下组件
      a)Scheduler:
        Scrapy改造了python本来的collection.deque(双向队列)形成了自己的Scrapy queue(https://github.com/scrapy/queuelib/blob/master/queuelib/queue.py)),
         但是Scrapy多个spider不能共享待爬取队列Scrapy queue, 即Scrapy本身不支持爬虫分布式。
         scrapy-redis的解决是把这个Scrapy queue换成redis数据库(也是指redis队列),从同一个redis-server存放要爬取的request,便能让多个spider去同一个数据库里读取。
         Scrapy中跟“待爬队列”直接相关的就是调度器Scheduler,它负责对新的request进行入列操作(加入Scrapy queue),取出下一个要爬取的request(从Scrapy queue中取出)等操作。
         它把待爬队列按照优先级建立了一个字典结构,比如:
        {优先级0 : 队列0
        优先级1 : 队列1
        优先级2 : 队列2}
         然后根据request中的优先级,来决定该入哪个队列,出列时则按优先级较小的优先出列。为了管理这个比较高级的队列字典,原来的Scheduler已经无法使用,所以使用Scrapy-redis的scheduler组件。
      b)Duplication Filter
        Scrapy中用集合实现这个request去重功能,Scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合中比对,
         如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。这个核心的判重功能是这样实现的:

def request_seen(self, request):
    # self.request_figerprints就是一个指纹集合  
    fp = self.request_fingerprint(request)

    # 这就是判重的核心操作  
    if fp in self.fingerprints:
        return True
    self.fingerprints.add(fp)
    if self.file:
        self.file.write(fp + os.linesep) 

        在scrapy-redis中去重是由Duplication Filter组件来实现的,它通过redis的set不重复的特性,巧妙的实现了Duplication Filter去重。
         scrapy-redis调度器从引擎接受request,将request的指纹存⼊redis的set检查是否重复,并将不重复的request push写⼊redis的 request queue。
         引擎请求request(Spider发出的)时,调度器从redis的request queue队列里根据优先级pop出request返回给引擎,引擎将此request发给spider处理。

      c)Item Pipeline:
        引擎将(Spider返回的)爬取到的Item给Item Pipeline,scrapy-redis的Item Pipeline将爬取到的 Item 存在redis的items queue。
         修改过Item Pipeline可以很方便的根据key从items queue 提取item,进而实现 items processes集群。
      d)Base Spider
        不在使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url的类。
         当我们生成一个Spider继承RedisSpider时,调用setup_redis函数,这个函数会去连接redis数据库,然后会设置signals(信号):
         一个是当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,并且抛出DontCloseSpider异常。
         一个是当抓到一个item时的signal,会调用item_scraped函数,这个函数会调用schedule_next_request函数,获取下一个request。

二、官方文档

官方站点:https://github.com/rolando/scrapy-redis。scrapy-redis工程的主体还是是redis和scrapy两个库,工程本身实现的东西不是很多,
    这个工程就像胶水一样,把这两个插件粘结了起来。下面我们来看看,scrapy-redis的每一个源代码文件都实现了什么功能,
    最后如何实现分布式的爬虫系统:
    1、connection.py 
        负责根据setting中配置实例化redis连接。被dupefilter和scheduler调用,总之涉及到redis存取的都要使用到这个模块 .       
        #代码见资料
    2、dupefilter.py
        负责执行requst的去重,实现的很有技巧性,使用redis的set数据结构。但是注意scheduler并不使用其中用于在这个模块中实现的dupefilter键做request的调度,
    而是使用queue.py模块中实现的queue。当request不重复时,将其存入到queue中,调度时将其弹出。
        #代码见资料
        
    3、picklecompat.py
        #代码见资料
        这里实现了loads和dumps两个函数,其实就是实现了一个序列化器。因为redis数据库不能存储复杂对象(key部分只能是字符串,value部分只能是字符串,字符串列表,字符串集合和hash),
    所以我们存啥都要先串行化成文本才行。
    4、pipelines.py   
        这是用来实现分布式处理的作用。它将Item存储在redis中以实现分布式处理。由于在这里需要读取配置,所以就用到了from_crawler()函数。
        #代码见资料
        pipelines文件实现了一个item pipieline类,和scrapy的item pipeline是同一个对象,通过从settings中拿到我们配置的REDIS_ITEMS_KEY作为key,把item串行化之后存入redis数据库
    对应的value中(这个value可以看出出是个list,我们的每个item是这个list中的一个结点),这个pipeline把提取出的item存起来,主要是为了方便我们延后处理数据。
    5、queue.py
        该文件实现了几个容器类,可以看这些容器和redis交互频繁,同时使用了我们上边picklecompat中定义的序列化器。这个文件实现的几个容器大体相同,只不过一个是队列,一个是栈,一个是优先级队列,
    这三个容器到时候会被scheduler对象实例化,来实现request的调度。比如我们使用SpiderQueue最为调度队列的类型,到时候request的调度方法就是先进先出,而实用SpiderStack就是先进后出了。
        #代码见资料
    6、scheduler.py
        此扩展是对scrapy中自带的scheduler的替代(在settings的SCHEDULER变量中指出),正是利用此扩展实现crawler的分布式调度。其利用的数据结构来自于queue中实现的数据结构。
    scrapy-redis所实现的两种分布式:爬虫分布式以及item处理分布式就是由模块scheduler和模块pipelines实现。上述其它模块作为为二者辅助的功能模块
        #代码见资料
    7、spider.py   
        设计的这个spider从redis中读取要爬的url,然后执行爬取,若爬取过程中返回更多的url,那么继续进行直至所有的request完成。之后继续从redis中读取url,循环这个过程。
    分析:在这个spider中通过connect signals.spider_idle信号实现对crawler状态的监视。当idle时,返回新的make_requests_from_url(url)给引擎,进而交给调度器调度。
        #代码见资料
    总结:
        最后总结一下scrapy-redis的总体思路:这个工程通过重写scheduler和spider类,实现了调度、spider启动和redis的交互。实现新的dupefilter和queue类,达到了判重和调度容器和redis的交互,
    因为每个主机上的爬虫进程都访问同一个redis数据库,所以调度和判重都统一进行统一管理,达到了分布式爬虫的目的。 当spider被初始化时,同时会初始化一个对应的scheduler对象,
    这个调度器对象通过读取settings,配置好自己的调度容器queue和判重工具dupefilter。每当一个spider产出一个request的时候,scrapy内核会把这个reuqest递交给这个spider对应的scheduler对象进行调度,
    scheduler对象通过访问redis对request进行判重,如果不重复就把他添加进redis中的调度池。当调度条件满足时,scheduler对象就从redis的调度池中取出一个request发送给spider,让他爬取。当spider爬取的所有暂时可用url之后,
    scheduler发现这个spider对应的redis的调度池空了,于是触发信号spider_idle,spider收到这个信号之后,直接连接redis读取strart url池,拿去新的一批url入口,然后再次重复上边的工作。

  

三、scrapy-redis分布式

 

1、分布式策略
    假如有5台电脑,其中一台作为Master端,其余作为Slaver端
    Master端(核心服务器):搭建一个Redis数据库,不负责爬取,只负责url指纹判重、Request的分配,以及数据的存储
    Slaver端(爬虫程序执行端):负责执行爬虫程序,运行过程中提交新的Request给Master
2、流程图
    1.见图1
    2.过程
        首先Slaver端从Master端拿任务(Request、url)进行数据抓取,Slaver抓取数据的同时,产生新任务的Request便提交给 Master 处理;
    Master端只有一个Redis数据库,负责将未处理的Request去重和任务分配,将处理后的Request加入待爬队列,并且存储爬取的数据。
    Scrapy-Redis默认使用的就是这种策略,我们实现起来很简单,因为任务调度等工作Scrapy-Redis都已经帮我们做好了,我们只需要继承RedisSpider、指定redis_key就行了。
        缺点是,Scrapy-Redis调度的任务是Request对象,里面信息量比较大(不仅包含url,还有callback函数、headers等信息),
    可能导致的结果就是会降低爬虫速度、而且会占用Redis大量的存储空间,所以如果要保证效率,那么就需要一定硬件水平。
3、测试Slave端远程连接Master端
    测试中,Master端的IP地址为:192.168.199.108
    1.Master端按指定配置文件启动 redis-server
        非Windows系统:sudo redis-server /etc/redis/redis/conf
        Windows系统:命令提示符(管理员)模式下执行 redis-server C:\Intel\Redis\conf\redis.conf读取默认配置即可。
    2.Master端启动本地redis-cli
    3.slave端启动redis-cli -h 192.168.199.108,-h 参数表示连接到指定主机的redis数据库
    
    #注意
    Slave端无需启动redis-server,Master端启动即可。只要 Slave 端读取到了 Master 端的 Redis 数据库,则表示能够连接成功,可以实施分布式

4、Redis数据库桌面管理工具
    推荐 Redis Desktop Manager。
    下载地址:https://redisdesktop.com/download
    #见图2和图3

 

 

 

 四、scrapy-redis分布式项目

1、源码自带项目说明
    使用scrapy-redis的example来修改
    
    先从github上拿到scrapy-redis的示例,然后将里面的example-project目录移到指定的地址:
    # clone github scrapy-redis源码文件
    git clone https://github.com/rolando/scrapy-redis.git

    # 直接拿官方的项目范例,改名为自己的项目用(针对懒癌患者)
    mv scrapy-redis/example-project ~/scrapyredis-project
    我们clone到的 scrapy-redis 源码中有自带一个example-project项目,
    这个项目包含3个spider,分别是dmoz, myspider_redis,mycrawler_redis。  

2、dmoz (class DmozSpider(CrawlSpider))
        这个爬虫继承的是CrawlSpider,它是用来说明Redis的持续性,当我们第一次运行dmoz爬虫,然后Ctrl + C停掉之后,
    再运行dmoz爬虫,之前的爬取记录是保留在Redis里的。分析起来,其实这就是一个 scrapy-redis 版 CrawlSpider 类,
    需要设置Rule规则,以及callback不能写parse()方法。
    
    执行方式:scrapy crawl dmoz

3、myspider_redis (class MySpider(RedisSpider))
        这个爬虫继承了RedisSpider, 它能够支持分布式的抓取,采用的是basic spider,需要写parse函数。
    其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出来,成为请求的url地址。
        #加代码
    
    #注意:
    RedisSpider类 不需要写allowd_domains和start_urls:

    1.scrapy-redis将从在构造方法__init__()里动态定义爬虫爬取域范围,也可以选择直接写allowd_domains。
    2.必须指定redis_key,即启动爬虫的命令,参考格式:redis_key = 'myspider:start_urls'
    3.根据指定的格式,start_urls将在 Master端的 redis-cli 里 lpush 到 Redis数据库里,RedisSpider 将在数据库里获取start_urls。
    
4、mycrawler_redis (class MyCrawler(RedisCrawlSpider))
        这个RedisCrawlSpider类爬虫继承了RedisCrawlSpider,能够支持分布式的抓取。因为采用的是crawlSpider,所以需要遵守Rule规则,以及callback不能写parse()方法。
    同样也不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出来,成为请求的url地址。



#执行方式:
    1.通过runspider方法执行爬虫的py文件(也可以分次执行多条),爬虫(们)将处于等待准备状态:
        scrapy runspider myspider_redis.py

    2.在Master端的redis-cli输入push指令,参考格式:
        $redis > lpush myspider:start_urls http://www.dmoz.org/

    3.Slaver端爬虫获取到请求,开始爬取。      

#总结
    官方例题提供三种方法:
    
    如果只是用到Redis的去重和保存功能,就选第一种;
    如果要写分布式,则根据情况,选择第二种、第三种;
    通常情况下,会选择用第三种方式编写深度聚焦爬虫。

  

##有缘网项目

存入redis(官方第一种)

 1 #需要进行设置的选项,其他均默认
 2 #############################
 3 
 4 BOT_NAME = 'youyuan'
 5 SPIDER_MODULES = ['youyuan.spiders']
 6 NEWSPIDER_MODULE = 'youyuan.spiders'
 7 #==============================================================================#
 8 
 9 # Crawl responsibly by identifying yourself (and your website) on the user-agent
10 USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
11 
12 # Obey robots.txt rules
13 ROBOTSTXT_OBEY = False
14 #============================================================================================#
15 
16 DEFAULT_REQUEST_HEADERS = {
17    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
18 #   'Accept-Language': 'en',
19 }
20 #==============================================================================#
21 
22 ITEM_PIPELINES = {
23     'youyuan.pipelines.YouyuanPipeline': 300,
24     'scrapy_redis.pipelines.RedisPipeline' : 400,           #对redis的设置。优先级要小于YouyuanPipeline
25 }
26 
27 #==============================================================================#
28 
29 #====================================redis存储开始============================#
30 
31 # 使用了scrapy-redis里的去重组件,不使用scrapy默认的去重
32 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
33 # 使用了scrapy-redis里的调度器组件,不实用scrapy默认的调度器
34 SCHEDULER = "scrapy_redis.scheduler.Scheduler"
35 # 允许暂停,redis请求记录不丢失
36 SCHEDULER_PERSIST = True
37 #延迟爬取时间
38 DOWNLOAD_DELAY = 1
39 
40 #默认的scrapy请求(按优先级顺序)队列形式
41 
42 #按sotred排序顺序出队列
43 #SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
44 #按栈形式,请求先进后出
45 SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"
46 # 使用队列形式,请求先进先出
47 SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
48 
49 #下面的设置,如果存在本机数据库,可以不进行设置。
50 #REDIS_HOST = '10.12.159.130'
51 #REDIS_PORT = 6379
52 
53 #====================================redis存储结束=================================#
有缘网setting.py文件
 1 from scrapy import Field, Item
 2 
 3 class YouyuanItem(Item):
 4     # 用户名
 5     username = Field()
 6     # 年龄
 7     age = Field()
 8     # 头像图片的链接
 9     header_url = Field()
10     # 相册图片的链接
11     images_url = Field()
12     # 内心独白
13     content = Field()
14     # 籍贯
15     place_from = Field()
16     # 学历
17     education = Field()
18     # 兴趣爱好
19     hobby = Field()
20     # 个人主页
21     source_url = Field()
22     # 数据来源网站
23     sourec = Field()
有缘网item.py文件
 1 ##存入当地,保存成json文件
 2 import json
 3 
 4 class YouyuanPipeline(object):
 5     def open_spider(self,spider):
 6         self.fw = open("youyuan.json", "w",encoding="utf-8")
 7 
 8     def process_item(self, item, spider):
 9         content = json.dumps(dict(item), ensure_ascii=False) + "\n"
10         self.fw.write(content)
11         return item
12 
13     def close_spider(self, spider):
14         self.fw.close()
有缘网pipelines.py文件
 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from scrapy.linkextractors import LinkExtractor
 4 from scrapy.spiders import CrawlSpider, Rule
 5 from youyuan.items import YouyuanItem
 6 
 7 import re
 8 
 9 class YySpider(CrawlSpider):
10     name = 'yy'
11     allowed_domains = ['youyuan.com']
12     start_urls = ['http://www.youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0-0/p1/']
13 
14     # 第一级匹配规则:北京市18~25岁女性的每一页链接匹配规则
15     page_links = LinkExtractor(allow = (r"youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0-0/p\d+/"))
16     # 第二级匹配规则:每个女性个人主页的匹配规则
17     profile_links = LinkExtractor(allow = (r"youyuan.com/\d+-profile/"))
18 
19     rules = (
20         Rule(page_links,follow=True),
21         Rule(profile_links, callback = "parse_item",follow=False),
22     )
23 
24     def parse_item(self, response):
25         item = YouyuanItem()
26 
27         item['username'] = self.get_username(response)
28         # 年龄
29         item['age'] = self.get_age(response)
30         # 头像图片的链接
31         item['header_url'] = self.get_header_url(response)
32         # 相册图片的链接
33         item['images_url'] = self.get_images_url(response)
34         # 内心独白
35         item['content'] = self.get_content(response)
36         # 籍贯
37         item['place_from'] = self.get_place_from(response)
38         # 学历
39         item['education'] = self.get_education(response)
40         #  兴趣爱好
41         item['hobby'] = self.get_hobby(response)
42         # 个人主页
43         item['source_url'] = response.url           #每个人的主页不需要再xpath匹配规则,直接response.url获取即可
44         # 数据来源网站
45         item['sourec'] = "youyuan"
46 
47         yield item
48 
49     def get_username(self, response):
50         username = response.xpath("//dl[@class='personal_cen']//div[@class='main']/strong/text()").extract_first()
51         return username.strip()
52 
53 
54     def get_age(self, response):
55         age = response.xpath("//dl[@class='personal_cen']//dd/p/text()").extract()
56         if len(age):
57             age = re.findall(u"\d+岁", age[0])[0]
58         else:
59             age = "NULL"
60         return age.strip()
61 
62     def get_header_url(self, response):
63         header_url = response.xpath("//dl[@class='personal_cen']/dt/img/@src").extract_first()
64         return header_url.strip()
65 
66 
67     def get_images_url(self, response):
68         images_url = response.xpath("//div[@class='ph_show']/ul/li/a/img/@src").extract()
69         if len(images_url):
70             images_url = images_url
71         else:
72             images_url = "NULL"
73         return images_url
74 
75     def get_content(self, response):
76         content = response.xpath("//div[@class='pre_data']/ul/li/p/text()").extract_first()
77         return content.strip()
78 
79     def get_place_from(self, response):
80         place_from = response.xpath("//div[@class='pre_data']/ul/li[2]//ol[1]/li[1]/span/text()").extract_first()
81         return place_from.strip()
82 
83     def get_education(self, response):
84         education = response.xpath("//div[@class='pre_data']/ul/li[3]//ol[2]/li[2]/span/text()").extract_first()
85         return education.strip()
86 
87 
88     def get_hobby(self, response):
89         hobby = response.xpath("//dl[@class='personal_cen']//ol/li/text()").extract()
90         if len(hobby):
91             hobby = ",".join(hobby).replace(" ","")     #可以将所有的爱好(在不同的标签下),拼接成一个完整字符串,
92                                                          #replace的作用是,将 " " (空格) --->  ""(空字符串)
93         else:
94             hobby = "NULL"
95         return hobby.strip()                            #strip去除左右两端的空格
有缘网yy.py文件

 

 

 有缘网项目分布式,需要更改的文件(第二种、第三种)

  1 # -*- coding: utf-8 -*-
  2 import scrapy
  3 from scrapy.linkextractors import LinkExtractor
  4 #from scrapy.spiders import CrawlSpider, Rule
  5 from scrapy.spiders import Rule
  6 from scrapy_redis.spiders import RedisCrawlSpider
  7 from youyuan.items import YouyuanItem
  8 
  9 import re
 10 
 11 #class YySpider(CrawlSpider):
 12 class YySpider(RedisCrawlSpider):
 13     name = 'yy'
 14     #allowed_domains = ['youyuan.com']
 15     #start_urls = ['http://www.youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0-0/p1/']
 16     redis_key = "yyspider:start_urls"
 17 
 18     # 动态域范围获取
 19     def __init__(self, *args, **kwargs):
 20         # Dynamically define the allowed domains list.
 21         domain = kwargs.pop('domain', '')
 22         self.allowed_domains = filter(None, domain.split(','))
 23         super(YySpider, self).__init__(*args, **kwargs)
 24 
 25     # 第一级匹配规则:北京市18~25岁女性的每一页链接匹配规则
 26     page_links = LinkExtractor(allow = (r"youyuan.com/find/beijing/mm18-25/advance-0-0-0-0-0-0-0/p\d+/"))
 27     # 第二级匹配规则:每个女性个人主页的匹配规则
 28     profile_links = LinkExtractor(allow = (r"youyuan.com/\d+-profile/"))
 29 
 30     rules = (
 31         Rule(page_links),
 32         Rule(profile_links, callback = "parse_item"),
 33     )
 34 
 35     def parse_item(self, response):
 36         item = YouyuanItem()
 37 
 38         item['username'] = self.get_username(response)
 39         # 年龄
 40         item['age'] = self.get_age(response)
 41         # 头像图片的链接
 42         item['header_url'] = self.get_header_url(response)
 43         # 相册图片的链接
 44         item['images_url'] = self.get_images_url(response)
 45         # 内心独白
 46         item['content'] = self.get_content(response)
 47         # 籍贯
 48         item['place_from'] = self.get_place_from(response)
 49         # 学历
 50         item['education'] = self.get_education(response)
 51         #  兴趣爱好
 52         item['hobby'] = self.get_hobby(response)
 53         # 个人主页
 54         item['source_url'] = response.url           #每个人的主页不需要再xpath匹配规则,直接response.url获取即可
 55         # 数据来源网站
 56         item['sourec'] = "youyuan"
 57 
 58         yield item
 59 
 60     def get_username(self, response):
 61         username = response.xpath("//dl[@class='personal_cen']//div[@class='main']/strong/text()").extract_first()
 62         return username.strip()
 63 
 64 
 65     def get_age(self, response):
 66         age = response.xpath("//dl[@class='personal_cen']//dd/p/text()").extract()
 67         if len(age):
 68             age = re.findall(u"\d+岁", age[0])[0]
 69         else:
 70             age = "NULL"
 71         return age.strip()
 72 
 73     def get_header_url(self, response):
 74         header_url = response.xpath("//dl[@class='personal_cen']/dt/img/@src").extract_first()
 75         return header_url.strip()
 76 
 77 
 78     def get_images_url(self, response):
 79         images_url = response.xpath("//div[@class='ph_show']/ul/li/a/img/@src").extract()
 80         if len(images_url):
 81             images_url = images_url
 82         else:
 83             images_url = "NULL"
 84         return images_url
 85 
 86     def get_content(self, response):
 87         content = response.xpath("//div[@class='pre_data']/ul/li/p/text()").extract_first()
 88         return content.strip()
 89 
 90     def get_place_from(self, response):
 91         place_from = response.xpath("//div[@class='pre_data']/ul/li[2]//ol[1]/li[1]/span/text()").extract_first()
 92         return place_from.strip()
 93 
 94     def get_education(self, response):
 95         education = response.xpath("//div[@class='pre_data']/ul/li[3]//ol[2]/li[2]/span/text()").extract_first()
 96         return education.strip()
 97 
 98 
 99     def get_hobby(self, response):
100         hobby = response.xpath("//dl[@class='personal_cen']//ol/li/text()").extract()
101         if len(hobby):
102             hobby = ",".join(hobby).replace(" ","")     #可以将所有的爱好(在不同的标签下),拼接成一个完整字符串,
103                                                          #replace的作用是,将 " " (空格) --->  ""(空字符串)
104         else:
105             hobby = "NULL"
106         return hobby.strip()                            #strip去除左右两端的空格
yy.py主文件

 

 更改地方除了主文件的前半部分,还有setting.py

#下面的设置,如果存在本机数据库,可以不进行设置。
#host表示作为主机的地址。其他机器需要和这个主机进行连接
#REDIS_HOST = '10.12.159.130'
#REDIS_PORT = 6379

  

五、将项目存入MySQL

后续更新。。。。。。。。。。。。。。。。。

 

 

 

 

 

 

 

 

 

 

 


posted @ 2018-08-05 23:52  Monomania丶pp  阅读(127)  评论(0)    收藏  举报