Contents

[Python爬虫系列]3— scrapy采集AKC网站犬类图片

Scrapy是一个比较成熟的爬虫框架,可以用来进行大规模爬虫。好久没用过啦,也想再回顾一下。本项目使用Scrapy下载AKC(AMERICAN KENNEL CLUB,美国养犬俱乐部)网站上的所有犬类图片,想自己制作一个每天定时发布微博的素材。

20200624更新

1.安装Scrapy,新建项目

1
2
3
4
5
6
# 下载图片需要
pip install pillow
pip install Scrapy
scrapy startproject akc
cd akc
scrapy genspider images www.akc.org/dog-breeds

2. 构造请求

注意到起始页面有一个选择框,保存了所有犬类的名字以及二级页面的地址



于是构造请求:

1
2
3
4
5
6
    def parse(self, response):
        # 去除第一个无意义选项
        options=response.css('.custom-select__select > option::attr(value)').extract()[1:]
        names=response.css('.custom-select__select > option::text').extract()[1:]
        for i in range(len(options)):
            yield scrapy.Request(options[i] + 'pictures/', callback = self.parse_detail, meta = {'name': names[i]})

3.提取信息

定义一个item(在item.py),定义了四个字段,包括图片的url,名称,保存文件夹名称以及保存的文件名称

1
2
3
4
5
6
7
from scrapy import Item, Field
class ImageItem(Item):
    collection ='images'
    id = Field()
    url = Field()
    title = Field()
    image_name=Field()

然后在spider中改写parse_detail函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    def parse_detail(self,response):
        # 图片名称
        alt=response.css('.image-grid__item >.media-wrap > img::attr(alt)').extract()
        url=response.css('.image-grid__item >.media-wrap > img::attr(data-src)').extract()
        for i in range(len(alt)):
            item = ImageItem()
            item['id'] = alt[i].strip().replace('.','')
            item['url'] = re.sub('-[0-9x]*.jpg','.jpg',url[i]) # 替换成更大的图片地址
            item['title'] = response.meta['name'] # 保存的文件夹名
            item['image_name'] = item['title'] + '/' + item['id'] + '.jpg' # 保存的文件名(包括路径)
            yield item

4.图片存储

定义Imagepipeline:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import os
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline



class ImagePipeline(ImagesPipeline):
    #返回保存的文件名
    def file_path(self, request, response=None, info=None):
        folder='images'+'/'+request.meta['title']
        if not os.path.exists(folder):
            os.mkdir(folder)
        ## 在setting的IMAGES_STORE的sub directory
        image_path = request.meta['image_name']  # 路径 文件夹名字
        return image_path

    def item_completed(self, results, item, info):
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem('Image Downloaded Failed')
        return item

    # 处理item对象,传递图片名称以及保存地址等信息,执行下载
    def get_media_requests(self, item, info):
        yield Request(item['url'], meta={'title': item['title'],'image_name':item['image_name'] })

class FengniaoPipeline(object):
    def process_item(self, item, spider):
        return item

settinhgs.py中设置

1
2
3
4
IMAGES_STORE = './images'
ITEM_PIPELINES = {
    'akc.pipelines.ImagePipeline': 300
}

5.运行程序,执行爬取

1
scrapy crawl images

完成后的images文件夹如下:

完整项目地址: https://github.com/webscrapingproject/Scrapy-AKC