写在前面
scrapy作为强大的爬虫框架,当然可以用来抓取图片,本文以英雄联盟全部英雄皮肤为例,记录一下抓取图片并自定义图片保存路径的方法。
创建爬虫
#创建项目
scrapy startproject lolskin
#创建spider
scrapy genspider lolskinspider "lol.qq.com"
配置item
items.py
import scrapy
class LolskinItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#保存英雄名称,如:黑暗之女、狂战士
hero_name = scrapy.Field()
#保存皮肤名称,如:这货不是乌迪尔
skin_name = scrapy.Field()
#保存皮肤图片的下载地址
skin_url = scrapy.Field()
配置spider
lolskinspider.py
import scrapy
#引入item
from lolskin.items import LolskinItem
#爬虫类
class LolskinspiderSpider(scrapy.Spider):
#爬虫名称
name = 'lolskinspider'
#请求允许的域名,需要从game.gtimg.cn获取英雄资料
allowed_domains = ['lol.qq.com','game.gtimg.cn']
def start_requests(self):
#从目标地址获取英雄列表
url = 'https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js'
#将response传递给parse方法
yield scrapy.Request(url = url,callback = self.parse)
def parse(self, response):
#单个英雄的详细信息,花括号需要匹配英雄的heroId
url = 'https://game.gtimg.cn/images/lol/act/img/js/hero/{}.js'
#从response(转换为json格式)中获取全部英雄信息的列表
heros = response.json()['hero']
#遍历全部英雄
for hero in heros:
#获取heroId
hero_id = hero['heroId']
#拼接url,将response传递给get_skins方法
yield scrapy.Request(url = url.format(hero_id),callback = self.get_skins)
def get_skins(self,response):
#从response中读取英雄的皮肤列表
skins = response.json()['skins']
#遍历每一个皮肤
for skin in skins:
#炫彩皮肤的mainImg为空,将炫彩皮肤过滤掉
if skin['mainImg'] != '':
#创建item对象
item = LolskinItem()
#保存hero_name
item['hero_name'] = skin['heroName']
#保存skin_name,去掉特殊字符(K/DA那几个)
item['skin_name'] = skin['name'].replace('/','')
#需要将skin_url保存为列表形式,不然scrapy下载器无法识别
item['skin_url'] = [skin['mainImg']]
#将item传递给管道执行下一步操作
yield item
else:
continue
配置管道
pipelines.py
#重写get_media_requests方法时需要用到的库
from scrapy.http import Request
#操作文件夹
import os
#引入scrapy的图片下载器
from scrapy.pipelines.images import ImagesPipeline
#创建类并继承ImagesPipeline的属性
class ImagePipeline(ImagesPipeline):
#如果不存在文件夹则创建(可能不需要)
if not os.path.exists('英雄联盟'):
os.mkdir('英雄联盟')
# 自定义文件存储路径可以通过重写get_media_requests动态传参数来实现,具体得request设置meta属性
def get_media_requests(self, item, info):
return [Request(x, meta={"hero_name":item["hero_name"],"skin_name": item['skin_name']}) for x in item.get(self.images_urls_field, [])]
# file_path接收传递的request,并返回文件保存路径
def file_path(self, request, response=None, info=None):
#英雄名
hero_name = request.meta['hero_name']
#皮肤名
skin_name = request.meta['skin_name']
#完整路径,类似于:英雄联盟/潮汐海灵/兔宝宝 菲兹.jpg
return '{}/{}.jpg'.format(hero_name,skin_name)
修改settings
#关闭rebot检查
ROBOTSTXT_OBEY = False
#设置下载延迟
DOWNLOAD_DELAY = 0.25
#关闭cookies
COOKIES_ENABLED = False
#执行管道
ITEM_PIPELINES = {
'lolskin.pipelines.ImagePipeline': 300,
}
#t图片根目录(于scrapy项目文件夹同级,也可以写绝对路径)
IMAGES_STORE = '英雄联盟'
#图片url地址,需要跟item中的名字对应
IMAGES_URLS_FIELD = 'skin_url'
#保存路径的"键",如果不修改file_path方法的话会生成哈希乱码作为路径
IMAGES_RESULT_FIELD = 'skin_name'
爬虫执行
scrapy crawl lolskinspider
写在后面
对scrapy的使用又多了一点了解!加油!