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.运行程序,执行爬取
完成后的images文件夹如下:
完整项目地址: https://github.com/webscrapingproject/Scrapy-AKC