Scrapy实战篇(六)之爬取360图片数据和图片

  

  本篇文章我们以360图片为例,介绍scrapy框架的使用以及图片数据的下载。

 

  目标网站:http://images.so.com/z?ch=photography

  思路:分析目标网站为ajax加载方式,通过构造目标url从而请求数据,将图片数据存储在本地,将图片的属性存储在mongodb中。

 

  1、首先定义我们需要抓取的字段

class ImageItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    collection = 'images'  #代表mongodb的的集合名称
    #下面四个字段分别是图片id,链接,标题,缩率图
    id = Field()
    url = Field()
    title = Field()
    thumb = Field()

 

  

  2、构造我们要爬取的url;由于目标网站时ajax加载的,展示的数据在http://images.so.com/zj?ch=photography&sn=30&listtype=new&temp=1中以json的形式存储,不断的下拉页面之后,每次变化的参数只有sn,并且每次以30的增量增加,第一页sn=30,第二页为60,则sn和页码的关系为sn*30,所以我们可以构造出url

 

#定义起始需要爬取的url列表,首先从spider中发送给调度引擎
    def start_requests(self):
        data = {'ch':'photography','listtype':'new','temp':1}
        base_url = 'http://images.so.com/zj?'
        for page in range(1,self.settings.get('MAX_PAGE') + 1):   #MAX_PAGE以参数的形式在settings文件中配置
            data['sn'] = page * 30
            url = base_url + urlencode(data)
            yield Request(url,self.parse)

 

 

  3、编写解析函数,返回的数据是json格式

#解析函数
    def parse(self, response):
        result = json.loads(response.text)   #将JSON文本字符串转为JSON对象
        for image in result.get('list'):
            item = ImageItem()
            item['id'] = image.get('imageid')
            item['url'] = image.get('qhimg_url')
            item['title'] = image.get('group_title')
            item['thumb'] = image.get('qhimg_thumb_url')
            yield item

 

 

  4、编写pipeline文件,将图片属性数据存入mongo,将图片存储到本地

import pymongofrom scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline


#定义了两个个Pipeline,分别为数据存储到mongodb,图片下载到本地
#在settings中定义Pipeline的执行顺序
class MongoPipeline(object):
    def __init__(self,mongo_url,mongo_db):
        self.mongo_url = mongo_url
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls,crawler):
        return cls(
            mongo_url=crawler.settings.get('MONGO_URL'),
            mongo_db=crawler.settings.get('MONGO_DB')
        )

    def open_spider(self,spider):
        self.client = pymongo.MongoClient(self.mongo_url)
        self.db = self.client[self.mongo_db]

    def process_item(self, item, spider):
        self.db[item.collection].insert(dict(item))
        return item

    def close(self,spider):
        self.client.close()

class ImagesPipeline(ImagesPipeline): def file_path(self,request,response=None,info=None): url = request.url file_name = url.split('/')[-1] return file_name def item_completed(self,results,item,info): image_paths=[x['path'] for ok,x in results if ok] if not image_paths: raise DropItem('Image Download Failed') return item def get_media_requests(self,item,info): yield Request(item['url'])

 

第一个为MongoPipeline,通过类方法from_crawler从settings文件中获取mongodb的配置信息,将蜘蛛文件中返回的item存入mongo数据库。

 

第二个为ImagesPipeline,scrapy提供了专门处理下载的Pipeline,包括文件下载和图片下载,下载过程支持异步和多线程,效率极高。

 

首先定义存储文件的路径,需要定义一个IMAGES_STORE变量,在settings文件中添加一行

IMAGES_STORE = './images

 

我们将路径定义在当前路径下的images中,即下载的图片都会存储在这个文件夹中。

 

  内置的ImagesPipeline会默认读取Item对象的image_urls字段,并认为该变量是一个列表,会遍历这个字段,然后取出url进行图片下载。

  但是我们上面定义的模型可以看出,Item对象的图片连接并不是image_url,也不是列表形式的,而是单个url,所以为了实现下载,需要重写ImagePipeline,继承内置的ImagePileline,再次我们重写了三个方法,分别是

  1)get_media_requests():它的第一个参数item就是爬取生成的Item对象,我们将它的url取出来,直接生成Request对象返回,从而加入调度队列,等待被调度,执行下载。

  2)file_path():它的第一个参数request就是当前下载的Request对象,这个方法用来返回保存的文件名称,直接将图片链接的最后一部分当做文件名称即可。

  3)item_completed():它是当单个Item完成下载时的处理方法,因为并不是每张图片都会下载成功,所以需要分析下载结果并剔除下载失败的图片,该方法的第一个参数results就是该item对象的下载结果,它是一个列表的形式,列表的每一个元素都是一个元组,其中包含了下载成功或者失败的信息。

 

  5、在settings中激活pipeline,并配置需要的配置项

ITEM_PIPELINES = {
   'images360.pipelines.ImagesPipeline': 300,
   'images360.pipelines.MongoPipeline': 301,
}

 

 

  6、执行爬虫,获取数据即可。

  scrapy crawl  images

 

  项目完整代码:https://gitee.com/liangxinbin/Scrpay/tree/master/images360

posted on 2019-02-13 22:04  liangxb  阅读(1491)  评论(0编辑  收藏  举报