Scrapy定制图片管道爬取搜狗图片(Ajax接口)

进入页面,发现图片是动态加载的。通过Ajax加载json文件。所以对request header的url进行观察,发现start参数每次加15。所以爬取过程并不难解决,关键是图片的存储
在这里插入图片描述
在这里插入图片描述
爬的过程还是会有坑的
先看items.py,这个没啥

import scrapy

class SougouphotoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    file_name = scrapy.Field()# 获取文件的名字
    picture_link = scrapy.Field()
    image_results = scrapy.Field()
    image_paths = scrapy.Field()
    

sougou.py

# -*- coding: utf-8 -*-
import scrapy
import demjson
from ..items import SougouphotoItem

class SougouSpider(scrapy.Spider):
    name = 'sougou'
    allowed_domains = ['pic.sogou.com']# 不是sougou是sogou。。。我醉了
    start_urls = ['https://pic.sogou.com/pics/channel/getAllRecomPicByTag.jsp?category=壁纸&tag=全部&start=0&len=15']

    def parse(self, response):
        # 此处巨坑
        content = demjson.decode(response.body.decode('gbk'))
        datas = content['all_items']
        for data in datas:
            file_name = data['title']
            picture_link = data['thumbUrl']

            item = SougouphotoItem()
            item['file_name'] = file_name
            item['picture_link'] = [picture_link] # 打死都要记住此处是列表
            yield item
        urls = ['https://pic.sogou.com/pics/channel/getAllRecomPicByTag.jsp?category=壁纸&tag=全部&start={}&len=15'.format(str(i)) for i in range(15,225,15)]
        for url in urls:
            request = scrapy.Request(url,callback=self.parse)
            yield request
            

注意

  • 首先,搜狗的英文是sogou,我被这个害惨了,发现一只只能爬出15张。。后来才缓过神。

  • 在获取json数据后,对json数据进行处理,此处如果用json.loads(response.body)会出现UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xb1 in position,后来经过多种查询和尝试,发现解决办法是用demjson库,需要pip一下,然后decode()方法解析json数据,而且response.body还有decode(‘gbk’)即content = demjson.decode(response.body.decode(‘gbk’))这样才可以正确转换为python对象

  • 要注意一个data里面有很多个url,thumbUrl、pic_url、orgin_url等,并不是每一个都可以请求并获取到相应,很可能会出现404.。。即报错[scrapy.pipelines.files] WARNING: File (code: 404): Error downloading file from <GET…所以最好取多个image的url,那一个行要哪个,这里偷懒了

  • 要注意,item返回的图片的url一定要是列表的形式,不然会出现ValueError: Missing scheme in request url: h

下面是piplines.py

import os
import scrapy
from sougouphoto.settings import IMAGES_STORE as images_store
from scrapy.pipelines.images import ImagesPipeline

headers = {
    'Referer': 'https://pic.sogou.com/pics/recommend?category=%B1%DA%D6%BD&from=category',
    'User-Ageny':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
}

class SougouphotoPipeline(ImagesPipeline):
	# 继承ImagesPipline并重写两个方法
	
    def get_media_requests(self, item, info):
        # image_link = item['picture_link']
        for image_link in item['picture_link']:
        	# 正如用不用框架实现下载图片一样,对图片的url要发起请求
            yield scrapy.Request(image_link,headers=headers)

    def item_completed(self, results, item, info):
        # 可以知道results的结构
        # 提取results里面的路径并改为自己的文件存储路径

        image_path = [x['path'] for ok,x in results if ok]
        item['image_paths'] = image_path
        
        try:#此处对图片进行重命名
            os.rename(images_store + image_path[0], images_store + item['file_name'] + '.jpg')
        except:
            pass
        return item
        

先是重写ImagePiline里面的get_media_request方法,用来对图片url发送请求并获取相应,第二个函数获取对应的results,results长这样

[(True,
  {'checksum': '2b00042f7481c7b056c4b410d28f33cf',
   'path': 'full/7d97e98f8af710c7e7fe703abc8f639e0ee507c4.jpg',
   'url': 'http://www.example.com/images/product1.jpg'}),
 (True,
  {'checksum': 'b9628c4ab9b595f72f280b90c4fd093d',
   'path': 'full/1ca5879492b8fd606df1964ea3c1e2f4520f076f.jpg',
   'url': 'http://www.example.com/images/product2.jpg'}),
 (False,
  Failure(...))]

可以看到是列表里面套元祖再套字典,所以用列表推导式提取里面的path,先是判断第一个元素是否为True,是True的话就提取里面的path固有这一条列表推导式

image_path = [x['path'] for ok,x in results if ok]

关于列表推导式,最左边的那个元素就代表是这个列表里面的元素,然后这个最左边的东西是要经过一个循环得到的,这个循环又要满足某个条件才会进行循环。

在这里的话,意思就是:序列解包,取出第一个元素是True还是False并赋值给ok,如果ok是True,就取出后面的字典并提取出名为‘path’的键作为值,这个值就作为这个列表里面的元素。

后面用os.rename()方法对图片进行重命名,这里的话需要从settings里面导入一下IMAGE_STORE这位兄台。

settings.py

LOG_LEVEL = 'WARNING'
ROBOTSTXT_OBEY = False
IMAGES_STORE = 'D:\\yourphoto/'# 必须要写
DEFAULT_REQUEST_HEADERS = {
   'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
   'Referer': 'https://pic.sogou.com/pics/recommend?category=%B1%DA%D6%BD&from=category',
   'Cookie': 'SUID=9E6888751620940A000000005C3C5D91; SUV=1547459988264723; IPLOC=CN4420; usid=9D9D1C74E609990A000000005C446306; sct=1; CXID=AFE813F02B1F31E306F131BC626E5180; ad=tUxlylllll2tvh@9lllllVeaHuDllllltUO$kyllll9lllllp6xll5@@@@@@@@@@; ld=llllllllll2tvjlQlllllVeU@4clllllKqhDcZllll9llllllklll5@@@@@@@@@@; LSTMV=260%2C204; LCLKINT=2323; JSESSIONID=aaasiP55egOwC6sRlHQJw; tip_show_home_search=20190214; SNUID=F0288185F4F07420E30A9B41F5D7C678; SNUID=5F872E2A5B5FDA8F4D4BB9A15B2B3BDC',
}
ITEM_PIPELINES = {
   # 'scrapy.contrib.pipeline.images.ImagesPipeline': 1,
   'sougouphoto.pipelines.SougouphotoPipeline': 300,
}

然后 scrapy crawl sougou就完事了。。
看一哈结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值