爬取360图片

这次我们爬取的网址是
http://image.so.com/z?ch=photography
随着滚轮下滑,图片一个个加载出来,所以我们推测这是Ajax形式
我们在开发工具里选中XHR
观察请求
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可知这个url的sn参数是以30倍数增长,我们可以利用这个特性进行url的构造
其次我们图片的具体信息都在list里面
下面我们先新建scrapy项目
在你想创建项目的路径里打开powershell

scrapy startproject images360
cd images360
scrapy genspider images images.so.com

我们先在settings.py设置一些变量

# 爬取最大页数
MAX_PAGE = 5

BOT_NAME = 'images360'

SPIDER_MODULES = ['images360.spiders']
NEWSPIDER_MODULE = 'images360.spiders'

MONGN_URI = 'localhost'
MONGO_DB = 'images360'

IMAGES_STORE = 'D:\pythonProject\Spiderr\Chapter13\images360\images360\images'
ROBOTSTXT_OBEY = False

我们使用MongoDb来存储,所以进行一下设置,然后IMAGES_STORE是我们图片下载存放的路径
ROBOTSTXT_OBEY需设置为False,默认设置为True,会导致无法爬取

初始化我们的容器,items.py

from scrapy import Item, Field

class ImageItem(Item):
    collection = table = 'images'
    id = Field()
    url = Field()
    title = Field()
    thumb = Field()

然后在images.py写入相关代码

# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request, Spider
from urllib.parse import urlencode
import json
from images360.items import ImageItem

class ImagesSpider(scrapy.Spider):
    name = 'images'
    allowed_domains = ['images.so.com']
    start_urls = ['http://images.so.com/']

    def start_requests(self):
        data = {'ch':'photography', 'listtype':'new'}
        # http://images.so.com/zj?ch=photography&sn=30&listtype=new&temp=1
        base_url = 'http://images.so.com/zj?'
        for page in range(1, self.settings.get('MAX_PAGE')+1):
            data['sn'] = 30 * page
            params = urlencode(data)
            url = base_url+params
            yield Request(url, self.parse)

    def parse(self, response):
        # self.logger.debug(response.text)
        result = json.loads(response.text)
        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

这里的两个方法实现了url的构造和解析
url构造完后返回给Request队列等待调度
pase完后记得将Item设置为生成器

最后是实现数据处理,我这里写了两个类,一个是存放到Mongodb里,另一个是使用scrapy的组件实现图片下载

import pymongo

class MongoPipeline(object):
    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

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


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

    def process_item(self, item, spider):
        name = 'images'
        self.db[name].insert(dict(item))
        return item

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

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

class ImagePipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        yield Request(item['url'])

    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

image_paths这里是列表推导式的写法
相当于

for ok, x in results:
    if ok:
        print(x['path'])

results是我们下载结果的一个列表,里面的元素是元组,包含下载信息,我们通过判断字段是否为True来得知下载是否成功
如果返回时False我们raise 一个DropItem错误
最后在settings里添加一个字段表面Pipelines的优先级

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

参考:崔庆才《python3网络爬虫实战》

猜你喜欢

转载自blog.csdn.net/weixin_44106928/article/details/90176526