对于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())
命令行执行
这样就可以了
如果有任何疑问请滴滴我