基於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())

命令行執行

這樣就可以了 

如果有任何疑問請滴滴我

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