基于scrapy 的360图片爬取 item中图片存储多个链接并下载

对于scrapy我还是没有感觉到他的强大 怪我太菜 仍然感觉requests好用

本片基于360图片的爬取 并对深度的爬取 不爬取封面 太lower了

直接进入正题 首先明确360的图片为动态加载 所以毫无疑问你需要访问xhr 由于本人喜欢二次元所以选择了cosplay

 下面两个图片为动态加载的第二页于 第三页 这里可以很清楚的看见其js文件 且无传递值 所以基本无反爬 url的规则行极高

其第一页的url为https://image.so.com/zj?ch=beauty&t1=598&sn=0&listtype=new&temp=1 很明显的可以看出他的url规律

url="https://image.so.com/zj?ch=beauty&t1=598&sn={}0&listtype=new&temp=1" {}中的数字即为对应的页数从0开始3为步长

接着分析其内容。其文本格式也不怎么复杂,在list中存储图片的信息请注意cover_imgurl qhimg_thumb_url qhimg_url均为封面图片 只是大小不同不必在意  如果大家只下载其封面的话就不用看了,我想爬的是其所有照片,下面这个网站

 

而这个网站的链接并不存在于上面那个json文件中 在下图

 

这个网站不是异步加载 url简单但最后的参数才是关键这个参数只能从下图获取

而这个东西还是异步加载 还需分析

其url构成简单也无多余的东西 只有一个id未确认 而id是从最开始的json中提取出来的所以与不是很难 接下来就是找取对于一个cosplay的网页当中其照片的规律

这个很简单不做过多的说明

接下来进入代码部分本文采用的是scrapy的 说明均在代码中展示首先是项目结构

 

一、items.py

# -*- coding: utf-8 -*-
# Define here the models for your scraped items
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class Pictures360Item(scrapy.Item):
    group_title=scrapy.Field()#标题名    
    id=scrapy.Field()#图片id
    group_pageurl=scrapy.Field()#mycoser网的网址
    worker=scrapy.Field()#拍摄这一组图片的工作人员
    image_urls=scrapy.Field()#这一组图片的url链接 因为谁家拍图拍一张啊

二、

settings.py

BOT_NAME = 'pictures360'

SPIDER_MODULES = ['pictures360.spiders']
NEWSPIDER_MODULE = 'pictures360.spiders'#上面三项均为系统自动定义的值

IMAGES_STORE="./images"#图片存储的位置 若是没有 自动创建 但必不可少

ROBOTSTXT_OBEY = False#robot协议 改成False 使其不遵守robot协议
FEED_EXPORT_ENCODING = 'utf-8'#必须加上 这是显示中文
ITEM_PIPELINES = {
    'pictures360.pipelines.ImagesPipeline': 330,
    'pictures360.pipelines.Pictures360Pipeline': 361,
}#通道函数的执行顺序排列 后面为参数优先级 数越小越先执行 先对图片进行下载 把下载失败的剔除掉 然后再进行文件的写入
#IMAGES_URLS_FIELD="image_urls" 这行代码好像没啥用 在前期搜集资料时好像用到了
SPIDER_MIDDLEWARES = {
   'pictures360.middlewares.Pictures360SpiderMiddleware': 543,
}#这行代码也没啥用 因为没有对middlewares重新定义

三、pictures.py

# -*- coding: utf-8 -*-
import scrapy
import json
from pictures360.items import Pictures360Item
from urllib.parse import urljoin

class PicturesSpider(scrapy.Spider):
    name = 'pictures'
    allowed_domains = ['image.so.com']
    def start_requests(self):#对要爬取的页面进行重新定义 由于是一个规则的url链接所以重新定义                          此函数
        Max=2
        for i in range(Max):
            url="https://image.so.com/zj?ch=beauty&t1=598&sn={}0&listtype=new&temp=1"
            yield scrapy.Request(url.format(i*3),callback=self.parse,dont_filter=True)通过yield进行迭代处理 说白了就是循环处理 而每次处理在上一次的后面 这里请注意callback函数为回调函数 start_requests函数时一个url列表,将每一个url都交给parse函数处理dont_filter默认值为Flase是默认去重 而在迭代爬取中 不更改为Ture会使爬虫框架刚执行就结束

    def parse(self, response):
        lists=json.loads(response.text)#由于链接返回值为json格式 所以转为json
        for everyone in lists["list"]:#对各种数据的提取
            item=Pictures360Item()#实例化items
            item["group_title"]=everyone["group_title"]
            item["id"]=everyone["id"]
            id=everyone["id"]
            url="https://image.so.com/zvj?ch=beauty&t1=598&id={}".format(id)#对url的重新定义
            yield scrapy.Request(url,meta={"key":item},callback=self.middle_page,dont_filter=True)#这里于上面的基本相同 重点在于meta参数 参数的目的在于传递item 由于定义的items的值并不是都在一个网页中 所以要向下传递 而 meta参数是以字典的形式传递的 key值随意 value值为实例化items的值

    def middle_page(self,response):#本函数基本同上 只是对网页的进一步提取
        item=response.meta["key"]#先将item接收
        item["group_pageurl"]=json.loads(response.text)["group_pageurl"]
        url=json.loads(response.text)["group_pageurl"]
        yield  scrapy.Request(url,meta={"key":item},callback=self.finally_page,dont_filter=True)

    def finally_page(self,response):#对最终静态网页的处理
        item=response.meta["key"]
        url="http://www.mycoser.com/"
        lasturls=[]
        item["worker"]=response.css(".text a::text").extract()

        for lasturl in response.css('.center img::attr("layer-src")').extract():
            lasturls.append(urljoin(url,lasturl))#urljoin是网页url的拼接
        item["image_urls"] = lasturls
        yield item#返回item

四、pipelines.py

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline

class Pictures360Pipeline(object):#此函数为项目初始化给的 
    def __init__(self):#初始化一下保存路径
        self.file=open("360.json","w",encoding="utf-8")

    def process_item(self, item, spider):#文件的保存
        content=json.dumps(dict(item),ensure_ascii=False)+"\n"
        self.file.write(content)
        return item

    def close_spider(self,spider):#关闭文件
        self.file.close()

class ImagesPipeline(ImagesPipeline):#由于要保存图片 但是scrapy内置的函数于要求不符所以重写 
    def file_path(self,request,response=None,info=None):#设置保存路径
        url=request.url#提取url链接 这里可以深挖一下 是不是可以提取别的参数
        file_name=url.split("/")[-1]
        return file_name

    def item_completed(self,results,item,info):#对不能下载的图片链接进行剔除 results 与 item info 在下图给出
        image_paths=[x["path"] for ok,x in results if ok] 
        if not image_paths: #根据是否拥有存储地址来判断是否要抛出异常 
            raise DropItem("failed")
        return item

    def get_media_requests(self,item,info): #这里很重要 因为要下载的url为列表 所以要循环后进行迭代
        for i in item["image_urls"]:
            yield Request(i)

 

五、begin.py

from scrapy import cmdline
cmdline.execute("scrapy crawl pictures".split())

命令行执行

这样就可以了 

如果有任何疑问请滴滴我

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章