使用scrapy抓取图片


写在前面

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的使用又多了一点了解!加油!