爬虫实战篇---使用Scrapy框架进行汽车之家宝马图片下载爬虫

(1)、前言

Scrapy框架为文件和图片的下载专门提供了两个Item Pipeline 它们分别是:

FilePipeline

ImagesPipeline

(2)、使用Scrapy内置的下载方法的好处

1、可以有效避免重复下载

2、方便指定下载路径

3、方便格式转换,例如可以有效的将图片转换为png 或jpg

4、方便生成缩略图

5、方便调整图片大小

6、异步下载,高效率

(3)、较为传统的Scrapy框架图片下载方式

1、创建项目:scrapy startproject baoma---cd baoma --创建爬虫scrapy genspider spider car.autohome.com.cn

2、使用pycharm打开项目

改写settings.py

不遵守robots协议

设置请求头

开启pipelines.py

改写spider.py

 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from ..items import BaomaItem
 4 
 5 class SpiderSpider(scrapy.Spider):
 6     name = 'spider'
 7     allowed_domains = ['car.autohome.com.cn']
 8     start_urls = ['https://car.autohome.com.cn/pic/series/65.html']
 9 
10     def parse(self, response):
11         #SelecorList类型
12         uiboxs = response.xpath('//div[@class = "uibox"]')[1:] #第一个我们不需要
13         for uibox in uiboxs:
14             catagory = uibox.xpath('.//div[@class = "uibox-title"]/a/text()').get()
15             urls = uibox.xpath('.//ul/li/a/img/@src').getall()
16             #遍历列表,并将列表中的某一项执行函数操作,再将函数的返回值以列表的形式返回
17             #map()
18             # for url in urls:
19             #     # url = 'https:' + url
20             #     # print(url)
21             #     #方法二:
22             #     url = response.urljoin(url)
23             #     print(url)
24                 #方法三:
25                 #将列表中的每一项进行遍历传递给lambda表达式,并执行函数中的代码,再以返回值以列表形式进行返回,结果是map对象,接着使用list转换为列表
26             urls = list(map(lambda url:response.urljoin(url),urls))
27             item = BaomaItem(catagory = catagory,urls = urls)
28             yield item

改写pipelines.py

 1 # -*- coding: utf-8 -*-
 2 
 3 # Define your item pipelines here
 4 #
 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
 7 import os
 8 from urllib import request
 9 
10 class BaomaPipeline(object):
11     def __init__(self):
12         self.path = os.path.join(os.path.dirname(__file__), 'images') #os.path.dirname()获取当前文件的路径,os.path.join()获取当前目录并拼接成新目录
13         if not os.path.exists(self.path):  # 判断路径是否存在
14             os.mkdir(self.path)
15 
16     def process_item(self, item, spider):
17         #分类存储
18         catagory = item['catagory']
19         urls = item['urls']
20 
21         catagory_path = os.path.join(self.path,catagory)
22         if  not os.path.exists(catagory_path): #如果没有该路径即创建一个
23             os.mkdir(catagory_path)
24 
25         for url in urls:
26             image_name = url.split('_')[-1] #以_进行切割并取最后一个单元
27             request.urlretrieve(url,os.path.join(catagory_path,image_name))
28 
29 
30         return item

新建测试py(main.py)

1 #author: "xian"
2 #date: 2018/6/14
3 from scrapy import cmdline
4 cmdline.execute('scrapy crawl spider'.split())

运行结果:(我们成功获取了以catagory分类并以图片地址_后的参数作为图片名的图片)

Scrapy框架提供了两个中间件1、下载文件的Files pipeline 和下载图片的Image pipeline

下载文件的Files pipeline

使用步骤:

1、定义好一个item,然后定义两个属性file_urls 和 files . file_urls是用来存储需要下载的文件的url链接,列表类型

2、当文件下载完成后,会把文件下载的相关信息存储到item的files属性中。例如:下载路径,下载url 和文件的效验码

3、再配置文件settings.py中配置FILES_STORE,指定文件下载路径

4、启动pipeline,在ITEM_PIPELINES中设置scrapy.pipelines.files.FilesPipeline :1

下载图片的Images Pipeline

使用步骤:

1、定义好一个item,然后定义两个属性image_urls 和 images. image_urls是用来存储需要下载的文件的url链接,列表类型

2、当文件下载完成后,会把文件下载的相关信息存储到item的images属性中。例如:下载路径,下载url 和文件的效验码

3、再配置文件settings.py中配置FILES_STORE,指定文件下载路径

4、启动pipeline,在ITEM_PIPELINES中设置scrapy.pipelines.images.ImagesPipeline :1

(4)、使用Images_pipeline进行图片下载(还是以汽车之家图片为例)

改写settings.py

开启自己定义的中间件

改写pipelines,py

 1 # -*- coding: utf-8 -*-
 2 
 3 # Define your item pipelines here
 4 #
 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
 7 import os
 8 from urllib import request
 9 from scrapy.pipelines.images import ImagesPipeline
10 import settings
11 
12 class BaomaPipeline(object):
13     def __init__(self):
14         self.path = os.path.join(os.path.dirname(__file__), 'images') #os.path.dirname()获取当前文件的路径,os.path.join()获取当前目录并拼接成新目录
15         if not os.path.exists(self.path):  # 判断路径是否存在
16             os.mkdir(self.path)
17 
18     def process_item(self, item, spider):
19         #分类存储
20         catagory = item['catagory']
21         urls = item['urls']
22 
23         catagory_path = os.path.join(self.path,catagory)
24         if  not os.path.exists(catagory_path): #如果没有该路径即创建一个
25             os.mkdir(catagory_path)
26 
27         for url in urls:
28             image_name = url.split('_')[-1] #以_进行切割并取最后一个单元
29             request.urlretrieve(url,os.path.join(catagory_path,image_name))
30 
31 
32         return item
33 
34 
35 class BMWImagesPipeline(ImagesPipeline):  # 继承ImagesPipeline
36     # 该方法在发送下载请求前调用,本身就是发送下载请求的
37     def get_media_requests(self, item, info):
38         request_objects = super(BMWImagesPipeline, self).get_media_requests(item, info)  # super()直接调用父类对象
39         for request_object in request_objects:
40             request_object.item = item
41         return request_objects
42 
43     def file_path(self, request, response=None, info=None):
44         path = super(BMWImagesPipeline, self).file_path(request, response, info)
45         # 该方法是在图片将要被存储时调用,用于获取图片存储的路径
46         catagory = request.item.get('catagory')
47         images_stores = settings.IMAGES_STORE #拿到IMAGES_STORE
48         catagory_path = os.path.join(images_stores,catagory)
49         if not os.path.exists(catagory_path): #判断文件名是否存在,如果不存在创建文件
50             os.mkdir(catagory_path)
51         image_name = path.replace('full/','')
52         image_path = os.path.join(catagory_path,image_name)
53         return image_path

运行结果展示:

通过对比我们可以直观感受到下载速度明显提高。

下面我们对图片进行优化,获取高清图片

通过分析缩略图和高清图的url,我们发现缩略图只是多了t_罢了

缩略图地址:https://car3.autoimg.cn/cardfs/product/g24/M08/2F/9E/t_autohomecar__wKgHIVpogfqAIlTbAAUzcUgKoGY701.jpg

高清图地址:https://car3.autoimg.cn/cardfs/product/g24/M08/2F/9E/autohomecar__wKgHIVpogfqAIlTbAAUzcUgKoGY701.jpg

(5)、下面我们获取所有的高清图片

传统思路如下:找到更多获取接口的url,进入详情页--找分页接口(显然这种情况会大大提高我们的工作量,下面我们使用Scrapy框架中的CrawlSpider进行爬取,因为CrawlSpider只要指定响应的规则,爬虫会自动进行爬取,省事省力!)

我们首先分析下url的规律:

https://car.autohome.com.cn/pic/series/65-1.html(更多的第一页url)

https://car.autohome.com.cn/pic/series/65-1-p2.html(更多的第二页url)

改写spider.py

 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from scrapy.spiders import CrawlSpider ,Rule#导入CrawlSpider模块 需改写原来的def parse(self,response)方法
 4 from scrapy.linkextractor import LinkExtractor #导入链接提取模块
 5 from ..items import BaomaItem
 6 
 7 
 8 class SpiderSpider(CrawlSpider):
 9     name = 'spider'
10     allowed_domains = ['car.autohome.com.cn']
11     start_urls = ['https://car.autohome.com.cn/pic/series/65.html']
12 
13     rules = {
14         Rule(LinkExtractor(allow=r'https://car.autohome.com.cn/pic/series/65.+'),callback= 'parse_page',follow=True),
15 
16     } #如需要进行页面解释则使用callback回调函数 因为有下一页,所以我们需要跟进,这里使用follow令其为True
17 
18 
19     def parse_page(self, response): #页面解析函数
20         catagory = response.xpath('//div[@class = "uibox"]/div/text()').get()
21         srcs = response.xpath('//div[contains(@class,"uibox-con")]/ul/li//img/@src').getall()
22         srcs = list(map(lambda x:x.replace('t_',''),srcs)) #map(函数,参数二),将参数二中的每个都进行函数计算并返回一个列表
23         # urls = {}
24         # for src in srcs:
25         #     url = response.url.join(src)
26         #     urls.append(url)
27         srcs = list(map(lambda x:response.urljoin(x),srcs))
28         yield BaomaItem(catagory=catagory,image_urls = srcs)

运行结果(展示):(我们成功获取了高清图片到本地)

猜你喜欢

转载自www.cnblogs.com/518894-lu/p/9181448.html