分布式爬虫实践(附带源码地址)

  • 分布式爬虫优点:
    1. 可以充分利用多台机器的带宽
    2. 可以充分利用多台机器的ip地址(同一个局域网内用的还是一个,分布式没有用)
    3. 多台机器做,爬取效率更高
  • 分布式爬虫需要解决的问题
    1. 分布式爬虫是好几台机器在同时运行,如何保证不同的机器爬取页面的时候不会出现重复爬取的问题
    2. 同样,分布式爬虫在不同的机器上运行,如何把数据爬完后保证保存在同一个老地方

scrapy-redis是一个组件不是框架,可以集成到scrapy框架中,使得爬虫可以进行分布式。可以充分的利用资源

pip install scrapy-redis

编写scraoy-redis分布式爬虫:
只要在基础的scrapy项目中修改以下三点就可以(基础的scrpay项目可以运行再修改为最佳)

  1. 将scrapy.Spider变成scrapy_redis.spider.RedisSpider;或者是从scrapy.CrawlSpider变成scrapy_redis.spider.RedisCrawlSpider
  2. 将爬虫的start_urls删掉增加一个redis_key="XXX"这个是为了以后指明从redis上的key读取url
  3. 在setting文件配置项中添加如下配置
#确保再爬取过程中去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#确保request存储到redis
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#数据不消失(暂停 重启)
SCHEDULER_PERSIST = True
ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 400,#数据存储在redis的pipeline中共享一个存储
}
REDIS_HOST=''
REDIS_PORT=''
  1. 启动爬虫分为两个步骤
    1. scrapy crawl spider 让爬虫就绪
    2. 在redis中输入lpush XXX urls让爬虫从这个url开始爬取(xxx 为上方第二个步骤redis_key urls为开始爬取的url地址)

以下是利用分布式爬取房天下的租房信息:
item.py文件:

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class FangtianxiaItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    province=scrapy.Field()
    city=scrapy.Field()
    name=scrapy.Field()
    price=scrapy.Field()
    rooms=scrapy.Field()
    area=scrapy.Field()
    address=scrapy.Field()
    sale=scrapy.Field()
    origin_url=scrapy.Field()
class ESFItem(scrapy.Item):
    province = scrapy.Field()
    city = scrapy.Field()
    name = scrapy.Field()
    price = scrapy.Field()
    rooms = scrapy.Field()
    floor=scrapy.Field()
    toward=scrapy.Field()
    area = scrapy.Field()
    address = scrapy.Field()
    year=scrapy.Field()
    unity=scrapy.Field()
    origin_url = scrapy.Field()

spider.py文件(一部分修改成分布式的具体代码)

mport scrapy
import re
from fangtianxia.items import FangtianxiaItem,ESFItem
from scrapy_redis.spiders import RedisSpider#导入scrapy-redis包
class SfwSpider(RedisSpider):#修改继承的类
    name = 'sfw'
    allowed_domains = ['fang.com']
    #start_urls = ['https://www.fang.com/SoufunFamily.html']
    #修改起始url地址
    redis_key = "fang:start_urls"#从这里读取url 随遗取即可
    def parse(self, response):
        trs=response.xpath("//div[@class='outCont']//tr")
        province=None
        for tr in trs:
            tds=tr.xpath(".//td[not(@class)]")
            province_td=tds[0]
            province_text=province_td.xpath(".//text()").get()
            province_text=re.sub(r"\s","",province_text)
            if province_text:
                province=province_text
            if province=='其它':
                #如果爬取的是海外城市则不进行爬取
                continue
            city_td=tds[1]
            city_links=city_td.xpath(".//a")
            for city_link in city_links:
                city=city_link.xpath(".//text()").get()
                city_url=city_link.xpath('.//@href').get()
                module=city_url.split('.')
                one = module[0]
                mid = module[1]
                last = module[2]
                newhouse_url=one + '.newhouse.' + mid + '.' + last + 'house/s/'
                esf_url=one+'.esf.'+mid+'.'+last
                if 'bj' in one:
                    newhouse_url='https://newhouse.fang.com/house/s/'
                    esf_url='https://esf.fang.com/'
                yield scrapy.Request(url=newhouse_url,callback=self.parse_newhouse,meta={'info':(province,city)})
                yield scrapy.Request(url=esf_url,callback=self.parse_esf,meta={'info':(province,city)},dont_filter=True)
    def parse_newhouse(self,response):
    	pass
    def parse_esf(self,response):
		pass

setting.py文件(针对scrapy-redis自u改的代码)

#确保再爬取过程中去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#确保request存储到redis
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#使用队列的形式
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
#数据不消失(暂停 重启)
SCHEDULER_PERSIST = True
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"

ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 400,
    #也可自加一些pipelines文件
}
#redis的ip地址和端口
REDIS_HOST='XXXXX'
REDIS_PORT='xxx'
LOG_LEVEL = 'DEBUG'

完整代码已分享与github上请自行浏览fork

你可能感兴趣的:(scrapy)