增量式与分布式爬虫

分布式爬虫

redis安装

  • 用户自定义目录,也就是你想安装的位置,新建一个文件夹,注意你的路径里不要有中文
  • 将redis-x64-3.2.100.zip压缩包 解压到你当前新建的文件夹里
  • 将解压的文件的路径复制 并 配置到环境变量中
  • 右击此电脑点击属性找到高级设置,然后点环境变量—系统变量—双击path—新建–粘贴路径即可

分布式

  • 分布式爬虫

    • 多台服务器机群,共同爬取数据
    • 适用于数据量较大
    • 提高了成本
  • 原生scrapy 不能实现分布式,要通过scrapy-redis

    • scrapy-redis提供了共享的调度器
    • scrapy-redis提供了共享的管道
  • 使用scrapy实现分布式的思路

    • 为原生的scrapy框架提供共享的管道和调度器
    • pip install scrapy-redis
  • 配置及创建项目

    • 创建工程

      • scrapy startproject projectname
    • 爬虫文件

      • scrapy genspider -t crawl spidername www.baidu.com
    • 修改爬虫文件

      • 导包:from scrapy_redis.spiders import RedisCrawlSpider
      • 将当前爬虫类的父类进行修改RedisCrawlSpider
      • allowed_demains,start_urls 注释掉,添加一个新属性redis_key=“qn”(调度器队列的名称)
      • 指定redis_key = ‘xxx’,即共享调度器队列名字
      • lpush xxx url
      • 数据解析:将解析的数据封装到item中然后向管道提交
    • 配置文件的编写

      • 指定管道

      • ITEM_PIPELINES = {
           'scrapy_redis.pipelines.RedisPipeline': 400,
        }
        
      • 指定调度器

        # 增加了一个去重容器类的配置,作用使用redis的set集合来存储请求的指纹数据,从而实现请求去重的持久化
        DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
        # 使用scrapy-redis组件自己的调度器
        SCHEDULER = "scrapy_redis.scheduler.Scheduler"
        # 配置调度器是否要持久化,也就是当爬虫结束了,要不要清空redis中请求队列和去重指纹的set,如果是True,就表示要持久化存储,就不清空数据,否则清空数据
        SCHEDULER_PERSIST = True
        
        
      • 指定具体的redis

        REDIS_HOST = 'redis服务器的ip地址'
        REDIS_PORT = 6379
        
      • 修改redis配置并指定配置启动

        • bind 127.0.0.1
        • protected-mode no

        • 开启redis服务(携带redis的配置文件:redis-server ./redis.window.conf)和客户端(redis-cli)

      • 启动程序:scrapy runspider xxx.py(需要进入spider文件夹)

      • 向调度器队列中扔入一个起始的url(redis的客户端):lpush xxx www.xxx.com (xxx表示的就是redis_key的值)

增量式与分布式爬虫_第1张图片

代码演示

  • 爬虫文件中

     import scrapy
     from scrapy.linkextractors import LinkExtractor
     from scrapy.spiders import CrawlSpider, Rule
     
     from scrapy_redis.spiders import RedisCrawlSpider
     from fbsspider.items import FbsspiderItem
     
     class SunaskSpider(RedisCrawlSpider):
         # 爬虫名虽然运行时不再使用,但是不能删(******)
         name = 'sunask'
         # allowed_domains = ['baidu.com']
         # start_urls = ['http://baidu.com/']
         # 共享调度器
         redis_key = 'sch'
         # http: // wz.sun0769.com / index.php / question / questionType?type = 4 & page = 30
         link = LinkExtractor(allow=r'http://wz.sun0769.com.*?page=\d+')
         rules = (
             Rule(link, callback='parse_item', follow=True),
         )
     
         def parse_item(self, response):
             title_list = response.xpath('//a[@class="news14"]/@title').extract()
             for title in title_list:
                 yield FbsspiderItem(title=title)
    
    
  • settings配置 就用上面笔记的复制粘贴就好了

"""
共享管道
"""
ITEM_PIPELINES = {
   # 'fbsspider.pipelines.FbsspiderPipeline': 300,
    'scrapy_redis.pipelines.RedisPipeline': 400,
}


# 增加了一个去重容器类的配置,作用使用redis的set集合来存储请求的指纹数据,从而实现请求去重的持久化
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 配置调度器是否要持久化,也就是当爬虫结束了,要不要清空redis中请求队列和去重指纹的set,如果是True,就表示要持久化存储,就不清空数据,否则清空数据
SCHEDULER_PERSIST = True

# 配置redis数据库
REDIS_HOST = '192.168.43.29'
REDIS_PORT = 6379
  • scrapy runspider sunask.py 启动服务时需要注意一下操作,完成一下操作服务 才会执行 爬取流程
    增量式与分布式爬虫_第2张图片
    增量式与分布式爬虫_第3张图片
    增量式与分布式爬虫_第4张图片

小插曲

  • 框架开启多线程在settings中 打开这个即可
    增量式与分布式爬虫_第5张图片

增量式爬虫

  • 基于url

  • 测试,提供一个思路增量式与分布式爬虫_第6张图片增量式与分布式爬虫_第7张图片

代码演示

  • 爬虫文件中
import scrapy
from redis import Redis
from ..items import MovieItem
conn = Redis('localhost',6379)

class MvSpider(scrapy.Spider):
    name = 'mv'
    # allowed_domains = ['baidu.com']
    start_urls = ['https://www.4567tv.tv/index.php?m=vod-list-id-5-pg-1-order--by-score-class--year--letter--area--lang-.html']

    def parse(self, response):
        link_list = response.xpath('//a[@class="stui-vodlist__thumb lazyload"]/@href').extract()
        for link in link_list:
            # sadd返回结果是1和0,1代表成功,0代表失败
            ret = conn.sadd('link',link)
            if ret == 1:
                print('数据没爬过')
                yield scrapy.Request(url='https://www.4567tv.tv'+link,callback=self.detail_parse)
            else:
                print('数据爬过了')

    def detail_parse(self,response):
        title = response.xpath('//h1[@class="title"]/text()').extract_first()
        typ = response.xpath('//p[@class="data"][1]/a[1]/text()').extract_first()
        localtion = response.xpath('//p[@class="data"][1]/a[2]/text()').extract_first()
        pro = response.xpath('//span[@class="detail-sketch"]/text()').extract_first()
        yield MovieItem(title=title,typ=typ,localtion=localtion,pro=pro)

  • item文件中
import scrapy


class MovieItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    typ = scrapy.Field()
    pro = scrapy.Field()
    localtion = scrapy.Field()
  • 管道中
import pymongo
class MoviePipeline(object):
    conn = pymongo.MongoClient()
    db = conn.movies
    table = db.mv
    def process_item(self, item, spider):
        self.table.insert_one(dict(item))
        return item
  • settings中将管道打开,ua打开,robots协议改为false即可

基于数据指纹

-爬虫文件中

import scrapy
import hashlib
from redis import Redis
from ..items import JokesItem

conn = Redis('localhost',6379)

class JkSpider(scrapy.Spider):
    name = 'jk'
    # allowed_domains = ['baidu.com']
    start_urls = ['http://xiaohua.zol.com.cn/lengxiaohua/']

    def parse(self, response):
        li_list = response.xpath('//ul[@class="article-list"]/li')
        for li in li_list:
            title = li.xpath('./span[2]/a/text()').extract_first()
            content = ''.join(li.xpath('./div[2]//text()').extract())
            # print('title:',title)
            # print('content:',content)
            data = title + content
            fp = hashlib.md5(data.encode('utf-8')).hexdigest()
            ret = conn.sadd('fp',fp)
            if ret:
                print('没爬过')
                yield  JokesItem(title=title,content=content)
            else:
                print('爬过了')
  • 管道中
import pymongo
class JokesPipeline(object):
    conn = pymongo.MongoClient()
    db = conn.jjj
    table = db.kkk
    def process_item(self, item, spider):
        self.table.insert_one(dict(item))
        return item

  • items中
import scrapy


class JokesItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    content = scrapy.Field()

你可能感兴趣的:(爬虫)