Python爬虫之分布式爬虫

2022-12-26 15:03:09 浏览数 (2)

  • 搭建分布式机群,让其对一组资源进行分布式联合爬取
  • 提升爬取效率
  • 实现分布式:
    • pip install scrapy-redis
  • scrapy-redis 组件的作用:
    • 给原生的scrapy框架提供可以被共享的管道和调度器

分布式爬虫

实现步骤:

  • scrapy startproject firstdemo
  • scrapy genspider -t crawl xxx [www.xxx.com](http://www.xxx.com/)
  • 修改当前爬虫文件
    • 导包 : from scrapy_redis.spiders import RedisCrawlSpider
    • start_urlsallowed_domains进行注释
    • 添加新属性: redis_key = 'sun' 可以被共享的调度器的名称
    • 编写数据解析相关操作
    • 将当前爬虫类的父类修改成RedisCrawlSpider
  • 修改配置文件settings
  • 指定使用可以被共享的管道
    • ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400}
  • 指定调度器
    • 增加一个去重容器类的配置,使用redisset集合来存储请求的指纹数据,从而实现请求去重的持久化 DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
    • 使用scrapy_redis组件 自己的调度器 SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
    • 配置调度器是否要持久化,也就是当爬虫结束,是否要清空Redis中请求队列和去重指纹set(人话:爬虫一般机器宕机了,重启后是否继续爬虫还是从0开始) SCHEDULER_PERSIST = True
  • 指定redis服务器
    • REDIS_HOST = '127.0.0.1'
    • REDIS_PORT = 6379
  • redis相关操作配置
    • linux或mac:
      • redis.conf
    • windows:redis.windows.conf
      • bind 127.0.0.1 删除
      • 关闭保护模式 protected-mode yes 改为 no
    • 结合配置文件开启redis服务
      • redis-server redis.windows.conf
    • 启动客户端
      • redis-cli
  • 执行工程
    • scrapy runspider xxx.py
    • 向调度器队列(redis)中放入一个起始url
      • lpush xxx www.xx.com
    • 查看队列中所有的内容和数量:
      • lrange xx:items 0 -1
      • llen xx:items
  • 最终爬取到的数据存储在了redisproName:items这个数据结构中

代码实现

sun2.py

代码语言:javascript复制
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from sun2Pro.items import Sun2ProItem
class Sun2Spider(RedisCrawlSpider):
    name = 'sun2'
    redis_key = 'sun'


    rules = (
        Rule(LinkExtractor(allow=r'id=2&page=d '), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        li_list = response.xpath('/html/body/div[2]/div[3]/ul[2]/li')
        for li in li_list:
            new_num = li.xpath('./span[1]/text()').extract_first()
            new_title = li.xpath('./span[3]/a/text()').extract_first()
            item = Sun2ProItem()
            item['title'] = new_title
            item['new_num'] = new_num
            yield item

items

代码语言:javascript复制
import scrapy

class Sun2ProItem(scrapy.Item):
    title = scrapy.Field()
    new_num = scrapy.Field()

settings

代码语言:javascript复制
DOWNLOAD_DELAY = 3
# 指定管道
ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 400
}
# 指定调度器
# 增加一个去重容器类的配置,使用redis的set集合来存储请求的指纹数据,从而实现请求去重的持久化
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
# 使用scrapy_redis组件 自己的调度器
SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
# 配置调度器是否要持久化,也就是当爬虫结束,是否要清空Redis中请求队列和去重指纹set(人话:爬虫一般机器宕机了,重启后是否继续爬虫还是从0开始)
SCHEDULER_PERSIST = True
# 指定redis
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379

增量式爬虫

  • 监测网站数据更新情况,只会爬取网站最新出来的数据
  • 核心:监测页面url之前是否请求过
    • 将爬取过的url存储到redisset数据结构中
  • 查看所有的 urls : semebers urls

案例演示

movie.py

代码语言:javascript复制
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis
from moviePro.items import MovieproItem


class MovieSpider(CrawlSpider):
    name = 'movie'

    start_urls = ['http://www.male37.live/index.php/vod/type/id/2/page/2.html']

    rules = (
        # Rule(LinkExtractor(allow=r'/id/3/page/d /.html'), callback='parse_item', follow=True),
        Rule(LinkExtractor(allow=r'id/d /page/d .html'), callback='parse_item', follow=True),
    )
    conn = Redis(host='127.0.0.1', port=6379)

    def parse_item(self, response):
        li_list = response.xpath('/html/body/div[1]/div/div[1]/div/div/div[2]/ul/li')
        for li in li_list:
            detail_url = 'http://www.male37.live'   li.xpath('./div/a/@href').extract_first()
            ex = self.conn.sadd('urls', detail_url)
            if ex == 1:
                print('该url没有被爬取过,可以进行数据爬取!')
                yield scrapy.Request(url=detail_url, callback=self.parse_detail)
            else:
                print('数据还没更新,暂无新数据可爬取!')

    def parse_detail(self, response):
        item = MovieproItem()
        item['name'] = response.xpath(
            '/html/body/div[1]/div/div[1]/div[1]/div/div/div/div[2]/h1/text()').extract_first()
        print(item['name'], '--------------')
        item['desc'] = response.xpath(
            '/html/body/div[1]/div/div[1]/div[1]/div/div/div/div[2]/p[5]/span[2]').extract_first()
        item['desc'] = ''.join(item['desc'])
        yield item

items.py

代码语言:javascript复制
import scrapy


class MovieproItem(scrapy.Item):
    name = scrapy.Field()
    desc = scrapy.Field()

pipelines.py

代码语言:javascript复制
class MovieproPipeline:
    conn = None

    def open_spider(self, spider):
        self.conn = spider.conn

    def process_item(self, item, spider):
        dic = {
            'name': item['name'],
            'desc': item['desc']
        }
        print(dic)
        self.conn.lpush('movieData', dic)
        return item

settings

代码语言:javascript复制
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379

ITEM_PIPELINES = {
   'moviePro.pipelines.MovieproPipeline': 300,
}

0 人点赞