一、基础知识

Scrapy是基于Twisted的异步处理框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。各模块之间耦合性第,可扩展性强,定制开发几个模块既可以实现一个爬虫。Scrapy框架如图:

包括如下几部分:

  • Engine,引擎。处理整个系统的数据流,整个框架的核心,
  • Item,项目。定义了爬取结果的数据结构,爬取的数据会被赋值成该Item对象。
  • Scheduler,调度器。接受引擎发过来的请求并加入队列,可以想象成一个URL(抓取网页的网址或链接)的优先队列,由它来决定下一个要抓取的网址是什么,同时去除重复的网址。
  • Downloader,下载器。下载网页内容,并将网页内容返回给蜘蛛。(Scrapy下载器是建立在twisted这个高效的异步模型上的)
  • Spiders,蜘蛛。定义了爬取的逻辑和网页的解析规则,主要是干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
  • Item Pipeline,项目管道。负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
  • Downloader Middlewares。位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。
  • Spider Middlewares。介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。

Scrapy运行流程如下:

  1. 引擎从调度器中取出一个链接(URL)用于接下来的抓取
  2. 引擎把URL封装成一个请求(Request)传给下载器
  3. 下载器把资源下载下来,并封装成应答包(Response)
  4. 爬虫解析Response
  5. 解析出实体(Item),则交给实体管道进行进一步的处理
  6. 解析出的是链接(URL),则把URL交给调度器等待抓取

安装:

pip install scrapy

二、网页分析

平时上网看到各种各样的妹子图,有没有想过把它们通通打包下来?以360图片为例,目标网址为:https://image.so.com。切换到美女专栏:

打开谷歌的开发者模式,简单分析。首先我猜想这个网站的图片为减少服务器的负担,一般会采用异步加载方式,也就是后台获得的都是Ajax请求,不出所料,在XHR后缀的请求中,确实看到了我想要的信息。

查看Request URL,发现其中包含一些固定参数:

  • ch:关键词
  • listtpye:new
  • temp:1
  • sn:偏移量,翻页参数,每个页面包含30张图

切换到Preview选项卡:

发现里边的数据返回格式是JSON,进行在线转换:

发现每个图片的详细信息都存放在list节点中。那么我计划提取如下内容:

  • imageid : 图片ID
  • group_title :图片名称
  • qhimg_url : 图片链接地址
  • qhimg_thumb_url : 缩略图链接地址

首先解析JSON,遍历其list字段,取出一个个图片信息,生成Item对象。

三、爬虫设计

爬虫目的:实现图片的打包下载到本地,并将图片的相关信息存入mysql和mongodb数据库

  1. 构造请求并提取信息:

命令行新建一个项目,命令如下:

scrapy startproject images360

进入本地项目目录,新建一个images.py的Spider,命令如下:

scrapy genspider images images.so.com

首先定义一个Item,叫做ImageItem。在这里定义四个字段,包括图片的ID、链接、标题、缩略图。另外还有两个属性collection和table,都定义为images字符串,分别代表MongoDB存储的Collection名称和Mysql存储的表名称。

# -*- coding: utf-8 -*-# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.htmlfrom scrapy import Item, Fieldclass ImageItem(Item):collection = table = 'images'id = Field()    #IDurl = Field()   #链接title = Field()  #标题thumb = Field()  #缩略图

蜘蛛images.py的代码如下:

# -*- coding: utf-8 -*-
from scrapy import Spider, Request
from urllib.parse import urlencode
import jsonfrom images360.items import ImageItemclass ImagesSpider(Spider):name = 'images'allowed_domains = ['images.so.com']start_urls = ['http://images.so.com/']def start_requests(self):data = {'ch': 'beauty', 'listtype': 'new'}base_url = 'https://image.so.com/zj?'for page in range(1, self.settings.get('MAX_PAGE') + 1):data['sn'] = page * 30params = urlencode(data)   #将字典转化为URL的get参数,构造出完整的URLurl = base_url + paramsyield Request(url, self.parse)   #返回完整的Request请求def parse(self, response):result = json.loads(response.text)for image in result.get('list'):    #信息都存放在JSON 的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

2.存储信息

(1)首先是MongoDB:

用一个MongoPipeline将信息保存到MongoDB。这里用到两个变量,MONGO_URI和MONGO_DB,即存储到MongoDB的链接地址和数据库名称。同时在settings.py中做如下配置:

MONGO_URI = 'localhost'
MONGO_DB = 'images360'

这样一个保存到MongoDB的Pipeline就创建好了。最主要的是process_item()方法,直接调用Collection对象的insert()方法即可完成数据的插入,最后返回Item对象。

(2)然后是Mysql:

首先在命令行新建数据库和数据表,这里可以参考我之前写的NO.10文章(其中一定要注意“;”的使用)。

这里同样要实现一个Mysql的Pipeline,因此在settings.py添加几个变量:

MYSQL_HOST = 'localhost'
MYSQL_DATABASE = 'images360'
MYSQL_USER = 'root'
MYSQL_PASSWORD = '8888'
MYSQL_PORT = 3306

这里分别定义了Mysql的地址、数据库名称、端口、用户名和密码。

这里用到的数据插入方法是一个动态构造SQL语句的方法

pipeline.py的代码如下:

# -*- coding: utf-8 -*-# Define your item pipelines here
#完成数据清洗和存储
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.htmlimport pymongo
import pymysql
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipelineclass MongoPipeline(object):def __init__(self, mongo_uri, mongo_db):self.mongo_uri = mongo_uriself.mongo_db = mongo_db#一种依赖注入的方式,通过crawler对象拿到Scrapy的所有核心组件,如全局配置的每个信息,然后创建一个Pipeline实例。#参数cls就是Class,最后返回一个Class实例@classmethoddef 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]#必须要实现的方法,返回item对象和Spider对象def process_item(self, item, spider):name = item.collectionself.db[name].insert(dict(item))return item#关闭数据库链接,spider是被关闭的Spider对象def close_spider(self, spider):self.client.close()class MysqlPipeline():def __init__(self, host, database, user, password, port):self.host = hostself.database = databaseself.user = userself.password = passwordself.port = port@classmethoddef from_crawler(cls, crawler):return cls(host=crawler.settings.get('MYSQL_HOST'),database=crawler.settings.get('MYSQL_DATABASE'),user=crawler.settings.get('MYSQL_USER'),password=crawler.settings.get('MYSQL_PASSWORD'),port=crawler.settings.get('MYSQL_PORT'),)def open_spider(self, spider):self.db = pymysql.connect(self.host, self.user, self.password, self.database, charset='utf8',port=self.port)self.cursor = self.db.cursor()def close_spider(self, spider):self.db.close()def process_item(self, item, spider):print(item['title'])data = dict(item)keys = ', '.join(data.keys())values = ', '.join(['%s'] * len(data))sql = 'insert into %s (%s) values (%s)' % (item.table, keys, values)self.cursor.execute(sql, tuple(data.values()))self.db.commit()return itemclass ImagePipeline(ImagesPipeline):#返回保存的文件名,用split()分割提取最后一部分作为文件名def file_path(self, request, response=None, info=None):url = request.urlfile_name = url.split('/')[-1]  #如http://www.6mm.cc/uploads/allimg/1306/2-13060F12S3.jpg。获取最后一个字符串return file_name#当单个Item完成下载时的处理方法。第一个参数results就是该Item对应的下载结果,是列表形式,列表每一个元素是一个元祖,包含下载成功或失败的信息。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 Downloaded Failed')return item#第一个参数item是爬取生成的Item对象。我们将它的url字段取出来,直接生成Request对象。将Request加入调度队列,等待被下载def get_media_requests(self, item, info):yield Request(item['url'])

中间件middlewares.py的代码如下:

# -*- coding: utf-8 -*-# Define here the models for your spider middleware
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/spider-middleware.htmlfrom scrapy import signalsclass Images360SpiderMiddleware(object):# Not all methods need to be defined. If a method is not defined,# scrapy acts as if the spider middleware does not modify the# passed objects.@classmethoddef from_crawler(cls, crawler):# This method is used by Scrapy to create your spiders.s = cls()crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)return s#应该返回None或者抛出一个异常#若返回None,Scrapy将会继续处理该Response,调用所有其他的Spider Middleware,直到Spider处理该Response#若抛出异常,Scrapy会调用Request的errback()方法def process_spider_input(self, response, spider):# Called for each response that goes through the spider# middleware and into the spider.# Should return None or raise an exception.return None#必须返回包含Request或Item对象的可迭代对象#result是包含Request或Item对象的可迭代对象def process_spider_output(self, response, result, spider):# Called with the results returned from the Spider, after# it has processed the response.# Must return an iterable of Request, dict or Item objects.for i in result:yield i#当Spider Middleware的process_spider_input()方法抛出异常,调用此方法
#必须要么返回None,要么返回一个包含Response或Item对象的可迭代对象
def process_spider_exception(self, response, exception, spider):# Called when a spider or process_spider_input() method# (from other spider middleware) raises an exception.# Should return either None or an iterable of Response, dict# or Item objects.pass#必须返回另一个包含Request对象的可迭代对象def process_start_requests(self, start_requests, spider):# Called with the start requests of the spider, and works# similarly to the process_spider_output() method, except# that it doesn’t have a response associated.# Must return only requests (not items).for r in start_requests:yield rdef spider_opened(self, spider):spider.logger.info('Spider opened: %s' % spider.name)#打印输出

3.运行程序

命令行进入本地项目目录:输入

scrapy crawl images

4. 爬取结果

发现图片都被打包存放在本地images文件夹,同时图片的相关信息都存放在mysql和mongodb数据库,哈哈好开心》》》》

这样就可以美美的欣赏这些图片啦》》》》》

NO.17——应用Scrapy框架实现美女图片的打包下载相关推荐

  1. Scrapy爬取美女图片续集 (原创)

    上一篇咱们讲解了Scrapy的工作机制和如何使用Scrapy爬取美女图片,而今天接着讲解Scrapy爬取美女图片,不过采取了不同的方式和代码实现,对Scrapy的功能进行更深入的运用. 在学习Scra ...

  2. Python爬虫之scrapy框架360全网图片爬取

    Python爬虫之scrapy框架360全网图片爬取 在这里先祝贺大家程序员节快乐,在此我也有一个好消息送给大家,本人已开通了微信公众号,我会把资源放在公众号上,还请大家小手动一动,关注过微信公众号, ...

  3. Scrapy爬取美女图片续集

    上一篇咱们讲解了Scrapy的工作机制和如何使用Scrapy爬取美女图片,而今天接着讲解Scrapy爬取美女图片,不过采取了不同的方式和代码实现,对Scrapy的功能进行更深入的运用. 在学习Scra ...

  4. php 打包下载网络图片,PHP实现图片批量打包下载功能

    上次遇到一个需要打包下载批量图片的问题,找了一下发现这个好方法,记录一下. 首先新建一个zipfile打包类: class zipfile { var $datasec = array (); var ...

  5. scrapy爬取美女图片

    使用scrapy爬取整个网站的图片数据.并且使用 CrawlerProcess 启动. 1 # -*- coding: utf-8 -* 2 import scrapy 3 import reques ...

  6. 17-爬虫之scrapy框架五大核心组件工作流程及下载中间件介绍04

    scrapy的五大核心组件 引擎(Scrapy) 对整个系统的数据流进行处理, 触发事务(框架核心). 调度器(Scheduler) 用来接受引擎发过来的请求. 由过滤器过滤重复的url并将其压入队列 ...

  7. ssm框架验证码图片加载不出_基于SSM框架的文件图片上传/下载功能实现

    前一段时间很多做毕业设计的同学问:如何写图片和文件的上传下载功能,今天正好有时间,所以就做了一个案例,详细的讲解这个功能. 框架结构: 对于很多做过开发的而言,上传功能肯定都用过,而且用到的场景很多, ...

  8. python利用多线程批量下载高清美女图片(350秒下载近3600张1.2个G的照片,地址可变)

    目录 第一章.前言 1.1.实现的效果: 1.2.需要用到的库: 第二章.代码分块讲解 2.1.对象的定义和初始化 2.2.方法1和2获取所有图集链接 2.2.1. 对应网站结构 2.2.2 .相应代 ...

  9. JavaScript前端批量下载图片文件打包下载

    参考:https://blog.csdn.net/qdm13209211861/article/details/126668206 参考代码在获取base64的时候有图片失真的问题.下面的代码已经修复 ...

最新文章

  1. PHP新手上路(六)
  2. 面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来...
  3. JVM内存结构、内存模型 、对象模型那些事
  4. LInux main.cpp 编码问题 导致影响后面的内容
  5. 100个必会的python脚本-100行Python代码实现自动抢火车票(附源码)
  6. CentOS下配置JDK1.6+TOMCAT6
  7. iOS Target-Action模式下内存泄露问题深入探究
  8. securecrt delete键向后删除
  9. 动态网页技术--JSP(7)
  10. 【SPOJ】1043 Can you answer these queries III
  11. 拓端tecdat|R语言实现拟合神经网络预测和结果可视化
  12. selenium-js
  13. 深入浅出设计模式 ------ Prototype(原型模式)之深度克隆
  14. Delphi基础教程第一季
  15. 智慧校园导航软件,实现3D校园室内外定位导航!
  16. matlab之图例legend的数字变量显示
  17. 学习可爱彩色线条PS极简马克笔简笔画:饮品篇
  18. win10锁屏壁纸路径
  19. [前端案例]百行代码实现炫酷时钟
  20. Bypass UAC 提权

热门文章

  1. C51——认识C51单片机
  2. 东微半导在科创板挂牌:业绩增速迅猛,上市次日一度跌破发行价
  3. 爬取人民日报_【爬虫项目】人民日报
  4. Linux: ------安装JDK、Tomcat、MySQL、Nginx、Tomcat负载均衡集群、Nginx负载均衡策略、MSM配置
  5. Jackson科普:为基于抗体的研究选择荧光团
  6. Android 该如何开发一个证件照DIY小程序 这篇来教你
  7. python:readline()和readlines()区别
  8. 明年元旦春节及两个黄金周放假安排公布
  9. Error: no data exchange control with ID xx 错误分析
  10. java timer时间回拨_用89C2051单片机制作的电话回拨器