热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Scrapy爬取动态页面下载图片(以抓取360图片为例)

当我们想要抓取一个页面的内容时,要做的第一件事不是写代码,而是分析页面,确定这是一个静态页面还是动态页面。抓取静态页面的方法十分简单,直接解析html源码再进行分析解析即可,如果不太明白,可以参

当我们想要抓取一个页面的内容时,要做的第一件事不是写代码,而是分析页面,确定这是一个静态页面还是动态页面。抓取静态页面的方法十分简单,直接解析html源码再进行分析解析即可,如果不太明白,可以参考我上篇文章Scrapy抓取豆瓣电影信息,这里我主要讲述一下如何抓取动态页面。

抓取动态页面有两种方法:
第一种方法是采用第三方工具,模拟浏览器的行为,从而加载数据。比如:Selenium、PhantomJs。这种方法的优点在于不必考虑动态页面的各种变化多端,但是性能低。

第二种方法是分析页面,找到对应的请求接口,直接获取数据。这种方法的优点在于性能高,但缺点也显而易见,就是获取API接口比较麻烦。

我这里采用第二种方式抓取动态页面。

1.浏览器打开页面 http://image.so.com/z?ch=beauty,查看网页源代码,发现源码中没有图片信息,这是一个动态加载的页面,而且是ajax异步请求动态页面。

2.分析页面,提取API接口,通过F12,审查元素可以找到。

3.打开上面的url,发现传入的是json格式的数据,所以之后我们获取到response响应,要先用json.loads()解析数据。

4.观察API接口,可以发现有几个参数,ch、sn、listtype、temp,通过改变这些参数的值就能获取到不同的内容。

通过分析发现,ch参数代表图片分类,比如beauty就表示美女图片,sn表示图片的编号,比如0就表示1到30之间的图片,30就表示31到60之间的图片。

分析了这些参数,我们就确定了我们需要请求的url地址,此处的url不像静态页面中通过程序自动获取a标签中的href,而是需要我们自动设定,我们可以通过重写start_requests方法指定需要获取的url。

5.编写我们的spider

# -*- coding: utf-8 -*-
from json import loads

import scrapy

from urllib.parse import urlencode

from image360.items import BeautyItem


class ImageSpider(scrapy.Spider):
    name = 'image'
    allowed_domains = ['image.so.com']

    # 重写Spider中的start_requests方法:指定开始url
    def start_requests(self):
        base_url = 'http://image.so.com/zj?'
        param = {'ch': 'beauty', 'listtype': 'new', 'temp': '1'}
        # 可以根据需要爬取不同数量的图片,此处只爬取60张图片
        for page in range(2):
            param['sn'] = page * 30
            full_url = base_url + urlencode(param)
            yield scrapy.Request(url=full_url, callback=self.parse)

    def parse(self, response):
        # 获取到的内容是json数据
        # 用json.loads()解析数据
        # 此处的response没有content
        model_dict = loads(response.text)
        for elem in model_dict['list']:
            item = BeautyItem()
            item['title'] = elem['group_title']
            item['tag'] = elem['tag']
            item['height'] = elem['cover_width']
            item['width'] = elem['cover_height']
            item['url'] = elem['qhimg_url']
            yield item

6.编写item,定义保存的字段


import scrapy


class BeautyItem(scrapy.Item):
    title = scrapy.Field()
    tag = scrapy.Field()
    height = scrapy.Field()
    width = scrapy.Field()
    url = scrapy.Field()

7.编写pipeline,完成数据持久化操作,这里包括下载图片和保存图片信息到mongo中。

Scrapy提供了一个 item pipeline ,来下载属于某个特定项目的图片,比如,当你抓取产品时,也想把它们的图片下载到本地,就可以通过图片管道实现。这在ImagesPipenine类中实现,提供了一个方便并具有额外特性的方法,来下载并本地存储图片。这个类中提供了很多处理图片的方法,想要了解详细内容可以查看官方文档中文版

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

import logging
import pymongo
import scrapy

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

logger = logging.getLogger('SaveImagePipeline')


# 继承ImagesPipenine类,这是图片管道
class SaveImagePipeline(ImagesPipeline):
    """ 下载图片 """
    def get_media_requests(self, item, info):
        # 此方法获取的是requests 所以用yield 不要return
        yield scrapy.Request(url=item['url'])

    def item_completed(self, results, item, info):
        """ 文件下载完成之后,返回一个列表 results 列表中是一个元组,第一个值是布尔值,请求成功会失败,第二个值的下载到的资源 """
        if not results[0][0]:
            # 如果下载失败,就抛出异常,并丢弃这个item
            # 被丢弃的item将不会被之后的pipeline组件所处理
            raise DropItem('下载失败')
        # 打印日志
        logger.debug('下载图片成功')
        return item

    def file_path(self, request, respOnse=None, info=None):
        """ 返回文件名 """
        return request.url.split('/')[-1]


class SaveToMongoPipeline(object):
    """ 保存图片信息到数据库 """
    def __init__(self, mongodb_server, mongodb_port, mongodb_db, mongodb_collection):
        self.mongodb_server = mongodb_server
        self.mongodb_port = mongodb_port
        self.mongodb_db = mongodb_db
        self.mongodb_collection = mongodb_collection

    def open_spider(self, spider):
        # 当spider被开启时,这个方法被调用
        self.cOnnection= pymongo.MongoClient(self.mongodb_server, self.mongodb_port)
        db = self.connection[self.mongodb_db]
        self.collection = db[self.mongodb_collection]

    def close_spider(self, spider):
        # 当spider被关闭时,这个方法被调用。
        self.connection.close()

    # 依赖注入
    @classmethod
    def from_crawler(cls, crawler):
        # cls() 会调用初始化方法
        return cls(crawler.settings.get('MONGODB_SERVER'),
                   crawler.settings.get('MONGODB_PORT'),
                   crawler.settings.get('MONGODB_DB'),
                   crawler.settings.get('MONGODB_COLLECTION'))

    def process_item(self, item, spider):
        post = {'title': item['title'], 'tag': item['tag'],
                'width': item['width'], 'height': item['height'], 'url': item['url']}
        self.collection.insert_one(post)
        return item

8.编写settings,完成配置,此处只把需要配置的内容写了出来。

BOT_NAME = 'image360'

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

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' \
             'Chrome/67.0.3396.79 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 1

# 随机延迟,设定随机延迟,使爬虫更像浏览器的行为
RANDOMIZE_DOWNLOAD_DELAY = True
# 延迟时间
DOWNLOAD_DELAY = 3

# 数据库信息
MONGODB_SERVER = '服务器地址'
MONGODB_PORT = 27017
MONGODB_DB = 'image360'
MONGODB_COLLECTION = 'image'

# 日志
LOG_LEVEL = 'DEBUG'

# 数字越小越先执行
ITEM_PIPELINES = {
    'image360.pipelines.SaveImagePipeline': 300,
    'image360.pipelines.SaveToMongoPipeline': 330,
}

# 配置图片保存地址,会自动创建文件夹
IMAGES_STORE = './resources'

9.启动spider
在启动spider之前,我们还需要安装几个包,pypiwin32、pilllow、pymongo

pip install pypiwin32
pip install pillow
pip install pymongo

安装完成之后就可以启动spider了

scrapy crawl image

10.查看结果:
获取到的图片返回的内容:

保存在指定路径的图片:

一个爬取动态页面并且下载图片的爬虫就完成了,其实写起来很简单,关键是需要分析API接口,重写start_requests方法。


推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • HTML学习02 图像标签的使用和属性
    本文介绍了HTML中图像标签的使用和属性,包括定义图像、定义图像地图、使用源属性和替换文本属性。同时提供了相关实例和注意事项,帮助读者更好地理解和应用图像标签。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
author-avatar
炯炯800
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有