使用scrapy_redis分布式爬虫爬取壁纸网站

230 阅读2分钟

@概述

  • 对于比较庞大的爬虫项目,可以考虑分工在多台服务器上进行分布式爬取
  • master端安装redis内存数据库,实现高速写入和转存(必须要转存,否则断电或程序崩溃,则数据将不复存在)
  • slave端爬虫程序运行起来后,会监听master端发送的指令并开始爬取,数据在scrapy_redis框架作用下,会源源不断地存储到master端redis数据库
  • master端redis的安装以及slave端scrapy_redis的安装请参考《分布式爬虫环境配置》
  • 除了环境配置以外,代码与scrapy基本是一致的
  • 代码很好理解,难点主要在于环境的配置和调试

@环境的安装

@项目代码

# 数据模型类
class MscrapyredisItem(scrapy.Item):
    crawled = scrapy.Field()
    spider = scrapy.Field()
    url = scrapy.Field()

    # 定义一下打印样式
    def __str__(self) -> str:
        return "MscrapyredisItem{crawled:%s,spider:%s,url:%s}"%(self.get("crawled"),self.get("spider"),self["url"])

  • 爬虫类
# 必须继承于RedisCrawlSpider,RedisSpider二者之一
# 其功能是在scrapy框架的Spider和CrawlSpider基础上增加了分布式功能
class BizhiSpider(RedisCrawlSpider):

    # 爬虫名称
    name = 'bizhi'

    # 在redis-cli中:lpush bizhi_key http://desk.zol.com.cn/
    # start_urls = ['http://desk.zol.com.cn/']
    redis_key = 'bizhi_key'

    # 允许爬取的子链接
    bizhi_link = LinkExtractor(allow=r'/bizhi/.*html$')

    # 深度爬取合规子链接,交由download_img方法处理
    rules = (
        Rule(bizhi_link, callback='download_img', follow=True),
    )

    # 处理页面
    def download_img(self, response):

        item = MscrapyredisItem()

        # 提取图片下载链接
        img_url = response.xpath("//img[@id='bigImg']/@src").extract()[0]
        item['url'] = img_url
        print(img_url)

        yield item

  • 设置类核心代码
# 指定使用scrapy-redis的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 指定使用scrapy-redis的去重
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'

# 在redis中保持scrapy-redis用到的各个队列,从而允许暂停和暂停后恢复,也就是不清理redis queues
SCHEDULER_PERSIST = True

# 指定redis数据库的连接参数
# REDIS_PASS是我自己加上的redis连接密码(默认不做)
REDIS_HOST = '192.168.187.133'
REDIS_PORT = 6379
#REDIS_PASS = 'redisP@ssw0rd'

# LOG等级
LOG_LEVEL = 'DEBUG'

# 覆盖默认请求头,可以自己编写Downloader Middlewares设置代理和UserAgent
DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8',
    'Connection': 'keep-alive',
    'Accept-Encoding': 'gzip, deflate, sdch'
}

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# Disable cookies (enabled by default)
COOKIES_ENABLED = False

# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
   # 'mScrapyRedis.middlewares.MscrapyredisDownloaderMiddleware': 543,
    'mScrapyRedis.middlewares.HeadersProxyMiddleware': 543,
}

# 通过配置RedisPipeline将item写入key为 spider.name : items 的redis的list中,供后面的分布式处理item
# 这个已经由 scrapy-redis 实现,不需要我们写代码
ITEM_PIPELINES = {
    'mScrapyRedis.pipelines.MscrapyredisPipeline': 300,
    'scrapy_redis.pipelines.RedisPipeline': 400
}

  • 下载中间件
# 为请求添加随机请求头
class HeadersProxyMiddleware(object):

    # 对请求进行预处理
    def process_request(self, request, spider):
        # print("\n" * 5, "ProxyMiddleware process_request")

        # 随机选择USER_AGENTS
        # 设置 request 对象的头部信息
        user_agent = random.choice(USER_AGENTS)
        # request.headers.setdefault("User-Agent", user_agent)
        request.headers["User-Agent"] = user_agent
  • 数据处理类
class MscrapyredisPipeline(object):

    def process_item(self, item, spider):

        #utcnow() 是获取UTC时间
        item["crawled"] = datetime.utcnow()

        # 爬虫名
        item["spider"] = spider.name

        print("\n"*5,item,"returned!!!")
        return item

@运行程序:

  • master端redis服务器跑起:redis-server /etc/redis/redis.conf
  • slave端爬虫程序跑起待命:scrapy crawl bizhi
  • master端打开redis客户端:redis-cli
  • master端通过redis-cli发送开始启动命令:push bizhi_key desk.zol.com.cn/