scrapy_redis通过RedisSpider类实现分布式爬虫-当当图书分布式爬虫演示

鳄鱼君

发表文章数:642

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Python » scrapy_redis通过RedisSpider类实现分布式爬虫-当当图书分布式爬虫演示

RedisSpider类

下面的代码,是官网的演示代码:

# -*- coding: utf-8 -*-
from scrapy_redis.spiders import RedisSpider

class MySpider(RedisSpider):#继承RedisSpider
    name = 'myspider_redis' #爬虫的名字
    redis_key = 'myspider:start_urls'#指定reids中start_urls的键
    #------>启动的时候只需要往对应的键中存入url地址,不同服务器的爬虫就会来取该url
    #------>所以启动爬虫的命令分为两个步骤:
    #  1.scrapy crawl myspider_redis(或者scrapy runspider myspider_redis)让爬虫就绪
    #  2.在redis中输入lupsh myspider:start:urls "http://XXXX" 让爬虫从这个url开始爬取

    allowed_domains = ['jd.com']  #手动指定allow_domain
    start_urls = ['http://jd.com/']
    # def __init__(self,*args,**kwargs): #动态的设置allow_domain,一般不需要,直接手动指定即可
    #     domain=kwargs.pop('domain','')
    #     self.allowed_domains=filter(None,domain.split(','))
    #     super(MySpider,self).__init__(*args,**kwargs)
    #
    def parse(self, response):
        pass

具体的解释已经注释掉了,其实非常简单。在普通的scrapy_redis爬虫中存在start_urls变量,那么我们要实现分布式,多台机器同时抓取,在每个机器上的代码都是一样的,也就是说都会存在start_urls,如果所有的机器都开始抓取,那么都会从start_urls开始抓取,显然非常的浪费资源。代码中没有了start_urls,换成redis的键,代码运行,爬虫会等待,等待reids对应的键中出现URL地址,那么我们只要在redis对应的键中插入url地址,那么所有的机器都会开始抓取了。

那么具体的效果看当当图书演示。

当当图书实战演示

下面我们通过一个例子来说明使用方法。当当图书,跟苏宁图书,京东图书都是一样的类型,只不过实现的效果不一样。

抓取当当图书的部分信息,跟京东图书一样。首先我们创建一个项目,然后生成一个爬虫:

scrapy startproject dangdang
cd dangdang
scrapy genspider dangbook book.dangdang.com

我们通过图片可以可以看到我们想要提取的内容,需要注意的是是否在源码中真存在你确定的那个标签。

scrapy_redis通过RedisSpider类实现分布式爬虫-当当图书分布式爬虫演示

我们在查看源代码的时候发现,网站所有的内容都在源码中,分类页面、图书列表页、图书详情页,我们都可以提取到相应的标签内容,只是需要注意标签是否存在,比较简单,代码参考:

# -*- coding: utf-8 -*-
import scrapy
import urllib.parse
from copy import deepcopy
from scrapy_redis.spiders import RedisSpider
class DangbookSpider(RedisSpider):
    name = 'dangbook'
    allowed_domains = ['dangdang.com']
    redis_key = 'dangdangbook'
    def parse(self, response):
            #大分类分组
            div_list=response.xpath('//div[@class="level_one "]')
            for div in div_list:
                item = {}
                item['b_cate']=div.xpath('./dl/dt/a/text()|./dl/dt/text()').extract()
                #提取的大分类为列表,存在换行符,需要处理
                item['b_cate']=[i.strip() for i in item['b_cate'] if len(i.strip())>0]
                #中间分类
                dl_list=div.xpath('./div//dl[@class="inner_dl"]')
                for dl in dl_list:
                    #中间分类有的标签没有,所以用| 取两个,也存在换行符
                    item['m_cate']=dl.xpath('./dt//text()|./dt/a/text()').extract()
                    item['m_cate'] = [i.strip() for i in item['m_cate'] if len(i.strip()) > 0]
                    #小分类
                    dt_list=dl.xpath('./dd/a')
                    for dt in dt_list:
                        item['s_cate']=dt.xpath('./text()').extract_first()
                        #小分类的地址
                        item['s_href']=dt.xpath('./@href').extract_first()
                        yield scrapy.Request(
                            item['s_href'],callback=self.parse_book_list,
                            meta={'item':deepcopy(item)}
                        )#多个for循环公用一个item字典,在传递的时候需要deepcopy
    def parse_book_list(self,response):
        item=response.meta['item']
        ul_list=response.xpath('//ul[@class="bigimg"]/li')
        for ul in ul_list:
            #i图书图片不在src属性,而是在data-original属性,在源文件可能没有,使用的是懒加载技术
            item['book_img']=ul.xpath('./a/img/@data-original').extract_first()
            item['book_name']=ul.xpath('./p[@class="name"]/a/text()').extract_first()
            item['book_href']=ul.xpath('./p[@class="name"]/a/@href').extract_first()
            item['book_price']=ul.xpath('./p[@class="price"]/span[1]/text()').extract_first()
            item['book_shop']=ul.xpath('./p[@class="search_shangjia"]/a/text()').extract_first()
            item['book_data']=ul.xpath('./p[@class="search_book_author"]/span[2]/text()').extract_first()
            item['book_comments']=ul.xpath('./p[@class="search_star_line"]/a/text()').extract_first()
            print(item)
        #图书列表页翻页
        next_url=response.xpath('//li[@class="next"]/a/@href').extract_first()
        if next_url is not None:
            yield scrapy.Request(
                urllib.parse.urljoin(response.url,next_url),
                callback=self.parse_book_list,
                meta={'item':item}
            )

然后我们修改settings文件内容如下:

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


BOT_NAME = 'dangdang'

SPIDER_MODULES = ['dangdang.spiders']
NEWSPIDER_MODULE = 'dangdang.spiders'
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'

LOG_LEVEL='DEBUG'

ROBOTSTXT_OBEY = False

ITEM_PIPELINES = {
   'dangdang.pipelines.DangdangPipeline': 300,
   'scrapy_redis.pipelines.RedisPipeline':400,
}
#指定哪个去重方法结合request对象去重
DUPEFILTER_CLASS='scrapy_redis.dupefilter.RFPDupeFilter'
#指定scheduler队列
SCHEDULER='scrapy_redis.scheduler.Scheduler'
#队列中的内容是否持久保存,为False的时候,关闭redis的同时会清空redis数据
SCHEDULER_PERSIST=True
REDIS_URL='redis://127.0.0.1:6379'

运行代码,爬虫处于等待状态,等待redis对应的键中出现url地址,那么我们开启redis数据库,在客户端向我们设置的redis_key键中插入url地址:

lpush dangdangbook http://book.dangdang.com/

之后爬虫开始运行,那么该如何多台机器同时抓取呢?首先你需要有多台机器才行,我们修改reids_url为本机的ip地址:

REDIS_URL='redis://本机ip:6379'

然后把对应的爬虫代码上传到各自的服务器上,就可以了,具体不再演示了,没有多台机器。

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《scrapy_redis通过RedisSpider类实现分布式爬虫-当当图书分布式爬虫演示》 发布于2020-03-21

分享到:
赞(3) 赏杯咖啡

评论 抢沙发

9 + 2 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册