接上篇《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实战项目的多页数据下载的内容就全部介绍完毕。下一篇我们来讲解电影天堂网站的多页面下载,继续巩固一下多页面下载技术。