【Python从入门到进阶】50、当当网Scrapy项目实战(三)

时间:2024-03-11 11:44:31

接上篇《49、当当网Scrapy项目实战(二)
上一篇我们讲解了的Spider与item之间的关系,以及如何使用item,以及使用pipelines管道进行数据下载的操作,本篇我们来讲解Scrapy的多页面下载如何实现。

一、多页面下载原理分析

1、多页面数据下载主要思路

我们之前编写的爬虫,主要是针对当当网书籍详情首页的列表数据进行下载,也只能下载第一页已经加载好的列表数据:

如果我们想要下载该种书籍的多页数据(例如1到100页)的数据,这就涉及到爬虫的多页面下载逻辑了。

我们现在可以思考一下,我们下载从第1页到第100页的书籍详情列表数据,数据结构和取数逻辑是否是一样的?答案是一样的。
所以我们在爬虫文件中编写的数据列表数据获取逻辑是核心程序,是不需要修改的,我们只需要把每一页的新内容传输给它,它进行数据转换清洗,变成数据结构对象,最后存储到文件中去即可。如同下图:

我们要做的事情,就是在爬虫中parse函数执行第1页请求完毕后,再使用parse函数执行第2页、第3页等等的请求即可。

2、如何获取多个页面的数据

我们如何来获取第2页及之后的数据呢?首先我们进入图书列表页,分别点击后面的第2页、第3页,并记录一下浏览器上面的地址:

我们分别看一下第1页、第2页、第3页的网址:

聪明的童鞋应该可以看出区别了吧,没错,从第1页之后,每页页面在“cp01”前会有一个“pgx-”,而其中的“x”就是当前的页码数。所以我们要获取某一页的数据,就只需要修改“pg”后面的数字为几,即可拿到相关页面的数据了。

二、多页面下载程序编写

1、指定相关路径

此时我们在爬虫文件中,就需要指定起始页面是什么,然后后续的迭代页面是什么,代码如下:

class DangSpider(scrapy.Spider):
    name = "dang"
    # 如果为多页下载,必须将allowed_domains的范围调整为主域名
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["http://category.dangdang.com/cp01.22.01.00.00.00.html"]

    base_url = 'http://category.dangdang.com/pg'
    end_url = '-cp01.22.01.00.00.00.html'
    page = 1
    
    #......下面代码省略......

其中的base_url是迭代页面的主地址信息,end_url是页码获取后拼接的静态页面固定地址,page是下一次要抓取的页面的页码数。

2、编写多页面下载判定与执行逻辑

然后我们在之前parse函数结束中的for循环结束后,编写一个页面判断的逻辑(注意是在for循环的外面,parse函数的里面):

if self.page < 100:  # 判断当前页面是否在100页以内
    self.page = self.page + 1  # 获取下一个页码
    # 根据获取的页码,拼接下一个需要爬取的页面url地址
    url = self.base_url + str(self.page) + self.end_url
    # 回调爬虫的parse函数,用新的url继续进行数据爬取
    # scrapy.Request就是scrapy的get请求
    # 其中的url是请求地址,callback是需要执行的爬虫的函数,注意不需要加圆括号
    yield scrapy.Request(url=url,callback=self.parse)
3、测试效果

这是我们删除原来抓取的book.json中的所有数据,清理下载的书籍图片,然后通过“scrapy crawl dang”命令执行我们的dang.py爬虫:

程序执行后,可以看到爬虫在逐页爬取相关数据:

等待爬虫执行完毕(这里我爬了101页,是因为上面小于100写成小于等于了):

我们可以看到json文件又被写满了:

其中最后一个数据,和当前网站的第100页的数据基本吻合:

查看一下图片,发现也是全部下载下来了(1页60条数据,100页共6000张封面,我们下载了5700多张),说明1到100页的数据已经基本全部抓取过来了:

4、完整代码

下面是刚刚上面优化完毕后的Scrapy爬虫逻辑的完整代码:

import scrapy

from scrapy_dangdang_01.items import ScrapyDangdang01Item

class DangSpider(scrapy.Spider):
    name = "dang"
    # 如果为多页下载,必须将allowed_domains的范围调整为主域名
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["http://category.dangdang.com/cp01.22.01.00.00.00.html"]

    base_url = 'http://category.dangdang.com/pg'
    end_url = '-cp01.22.01.00.00.00.html'
    page = 1

    def parse(self, response):
        # 获取所有的图书列表对象
        li_list = response.xpath('//ul[@id="component_59"]/li')

        # 遍历li列表,获取每一个li元素的几个值
        for li in li_list:
            # 书籍图片
            src = li.xpath('.//img/@data-original').extract_first()
            # 第一张图片没有@data-original属性,所以会获取到控制,此时需要获取src属性值
            if src:
                src = src
            else:
                src = li.xpath('.//img/@src').extract_first()
            # 书籍名称
            title = li.xpath('.//img/@alt').extract_first()
            # 书籍作者
            search_book_author = li.xpath('./p[@class="search_book_author"]//span[1]//a[1]/@title').extract_first()
            # 书籍价格
            price = li.xpath('./p[@class="price"]//span[@class="search_now_price"]/text()').extract_first()
            # 书籍简介
            detail = li.xpath('./p[@class="detail"]/text()').extract_first()
            # print("======================")
            # print("【图片地址】", src)
            # print("【书籍标题】", title)
            # print("【书籍作者】", search_book_author)
            # print("【书籍价格】", price)
            # print("【书籍简介】", detail)

            # 将数据封装到item对象中
            book = ScrapyDangdang01Item(src=src, title=title, search_book_author=search_book_author, price=price, detail=detail)

            # 获取一个book对象,就将该对象交给pipelines
            yield book

        if self.page < 100:  # 判断当前页面是否在100页以内
            self.page = self.page + 1  # 获取下一个页码
            # 根据获取的页码,拼接下一个需要爬取的页面url地址
            url = self.base_url + str(self.page) + self.end_url
            # 回调爬虫的parse函数,用新的url继续进行数据爬取
            # scrapy.Request就是scrapy的get请求
            # 其中的url是请求地址,callback是需要执行的爬虫的函数,注意不需要加圆括号
            yield scrapy.Request(url=url,callback=self.parse)

至此,关于Scrapy实战项目的多页数据下载的内容就全部介绍完毕。下一篇我们来讲解电影天堂网站的多页面下载,继续巩固一下多页面下载技术。