说起写爬虫,大多数第一时间想到的就是python了。python语法简洁明了,加上及其丰富好用的库,用它来写爬虫有天然的优势。

之前学python的时候也用requests+lxml写过几个爬虫玩,但是都就爬取一些内容就没继续下去了,都没做成一个项目,中间python也荒废了好久。最近要学kafka,就打算爬点数据来实践实践。于是就学起scrapy来,总的来说,scrapy还是很容易上手的,也比较简单,花了几天的时间学习加实践,也渐渐的掌握了这个爬虫框架。所以打算写个博客做个总结,以免之后又太久没用忘记了。

scrapy架构原理

scrapy架构图

[图片上传失败...(image-21611e-1532663400039)]

scrapy引擎向spider获取起始Request集合,也就是spider中定义的start_urls。如果spider重写了start_requests()方法,那么这个方法返回的Request集合就是起始Request。

scrapy引擎将拿到的Request发给调度中心开始调度。

scrapy引擎向调度中心请求获取下一个要爬取的Request。

scrapy引擎拿到Request后,然后将Request发给下载器。这个过程经过一系列在settings.py中配置的下载中间件,所有在settings.py中配置的下载中间件会依次对Request进行处理。——对应DownloaderMiddleware#process_request()方法

下载器根据Request拉取响应的内容,比如Request的url是http://www.baidu.com,下载器就会拉取对应的网页内容下来并封装成Response对象。

下载器将Response发送给scrapy引擎。这个过程也会经过一系列在settings.py中配置的下载中间件,这些下载中间件会依次对Response进行处理。——对应DownloaderMiddleware#process_response()方法

scrapy引擎拿到Response后将Response发给spider,交给对应的spider函数处理。这里默认方法是parse(),这个回调方法构造Request的时候指定。引擎发送Response的过程会经过一系列在settings.py中配置的spider中间件,这些spider中间件会依次对Response进行一些处理。——对应SpiderMiddleware#process_spider_input()

spider处理完Response后会返回一个result,这个result是一个包含 Request 或 Item 对象的可迭代对象(iterable)。然后将result发给scrapy引擎,这个过程也会经过一系列在settings.py中配置的spider中间件,这些spider中间件会依次对这个result进行一些处理。——对应SpiderMiddleware#process_spider_output()

scrapy引擎拿到这个result后,会将其中的Item发送给Item Pipeline处理,这些item就会被一系列我们在settings.py中配置的pipeline处理。同时,scrapy也会将result中的Request发给调度中间准备调度。

继续重复第2步的步骤,直到所有的Request全部处理完后程序退出。

在scrapy 0.15版本后,spider中间件新增了一个方法,用于处理第一步中spider发送给引擎的Request,也就是SpiderMiddleware#process_start_requests(start_requests, spider)

scrapy的组件介绍

一、Spider

Spider组件主要用来生成要爬取的url,解析返回的内容,然后生成新的url继续交给scrapy去爬取,或者生成item交给pipeline处理。

编写scrapy爬虫应用时,我们大多数精力应该都是放在spider的编写上面。

通过定义start_urls参数或者重写start_requests()方法来给scrapy引擎提供起始的拉取url。

之后,scrapy引擎拿到url后去获取对应url网页中的内容后就会回调spider中的parse()方法,我们可以重写parse()方法来解析scrapy引擎返回回来的内容。

在parse()方法中,我们可以返回一个可迭代的对象,可以理解为是一个list,因为list也是一个可迭代对象,这个list里面可以放Request对象或者Item对象。

scrapy拿到list后,会遍历整个容器,然后把Request再放进调度等会去获取内容,对于Item对象,scrapy引擎就把这个item对象发到pipeline去处理。在pipeline有用户自己编写的一套处理逻辑,可以选择的将item存到文件或者数据库中。

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

import scrapy

class TestSpider(scrapy.Spider):

name = "kongtrio"

# 定义爬取的域名,如果返回的url所属的域名不在这个列表里面,scrapy就不会去爬取内容

allowed_domains = ["bbs.hupu.com"]

# 定义起始的url

start_urls = (

'http://bbs.hupu.com/bxj/',

)

# 如果重写了这个方法,scrapy引擎取到的起始url就是这个方法返回的内容了

# 这样start_urls就不会生效了

def start_requests(self):

for i in range(1, 10):

yield scrapy.Request('http://bbs.hupu.com/bxj-' + str(i))

def parse(self, response):

# scrapy拉取到url的内容后,会封装成Response对象,然后回调这个parse()方法

# 我们可以对这个response进行解析,然后根据策略返回响应的内容

# scrapy 自带了xpath的方式解析内容,xpath教程可以看这篇 https://blog.csdn.net/u013332124/article/details/80621638

title_href = response.xpath(".//a[@class='title']/@href").extract_first()

title = response.xpath(".//a[@class='title']/text()").extract_first()

# 返回一个request对象和一个item对象,request对象放的是标题的url,后面scrapy会继续读取这个url然后交给parse继续解析

return [scrapy.Request(content_url, self.post_content_parse, dont_filter=True),{"title":title}]

二、pipeline

这也是我们需要关心的组件。前面spider返回的item会经过scrapy引擎的调度发向pipeline。

pipeline的组件做的事情很简单,就是拿到item,然后具体的操作用户自己实现。

class HupuSpiderPipeline(object):

def process_item(self, item, spider):

if not item["title"]:

# 如果这个pipeline抛出DropItem异常,那么这个item就不会传给后面的pipeline了

raise DropItem("invalid item")

title = item["title"]

print(title)

# return后 会把这个item继续传给后面的pipeline

return item

上面这个pipeline做的事情很简单,就是从item中获取title,然后打印出来。

我们可以写多个pipeline,分别做不同业务的事情。但是要注意的是,在process_item()方法中,必须将item返回,不然后面的pipeline就不会被调起来处理item了。或者抛出DropItem异常也会中断item的传递。

编写好pipeline之后还要记得在settings.py里面配置,这样pipeline才会真正被scrapy引擎知道,并开始工作。

# 后面的数字表示pipeline的次序

ITEM_PIPELINES = {

'hupu_spider.pipelines.HupuSpiderPipeline': 300,

# 'hupu_spider.pipelines.HupuImgDownloadPipeline': 400,

}

编写完pipeline和spider,我们其实就基本实现了一个简单的scrapy爬虫应用了。挺大一部分场景也只要我们编写pipeline和spider就可以了。当然,其他的组件也需要了解一下,以面对丰富多样的需求变动。

三、下载中间件

下载中间件主要是用于在scrapy引擎发送Request到下载器和下载器返回Response给scrapy引擎的过程中。

scrapy引擎发送Request到下载器

scrapy引擎发送Request到下载器的过程中,会经过一个个的下载中间件,这些中间件会对Request进行处理,可以将处理后的Request再发送给下一个中间件,也可以中断Request的处理,甚至可以不需要经过下载器就直接生成Response然后返回给scrapy引擎,具体的策略由代码实现来决定。在所有的中间件都处理过后,下载器拿到Request就会开始下载内容然后返回Response了。

下载器返回Response给scrapy引擎

下载器通过Request拉取到数据后,就会封装成Response返回给scrapy引擎,在这个过程中,也会经过这些下载中间件的处理。下载中间件可以生成Request重新交给scrapy引擎处理,也可以对Response进行一些处理后交给下一个下载中间件,最后抵达scrapy引擎。

下载中间件的定义和使用

我们需要写一个类来继承DownloaderMiddleware,并在settings.py中配置编写好的这个下载中间件。

DOWNLOADER_MIDDLEWARES = {

'myproject.middlewares.CustomDownloaderMiddleware': 543,

'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,

}

后面的数字表示该下载中间件的顺序,数字越小越接近scrapy引擎

如果要禁用内置的一些下载中间件,可以将数字设置为None

编写下载中间件需要关注的几个方法:

process_request(request, spider): 这个方法接收scrapy传过来的Request对象,我们可以在这个方法里面对这个Request进行一些处理,然后根据返回的对象做一些操作:

返回None,通知下一个下载中间件继续对这个Request进行处理

返回Response对象,直接生成Response发给scrapy引擎,这样Request就不会交给下载器去下载内容了。注意,生成的Response还是会经过一个个下载中间件处理

返回Request对象,直接把新的Request返回给scrapy引擎重新调度,但是后面的下载中间件就不会再执行了

如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用

process_response(request, response, spider):这个方法接收下载器或者其他下载中间件发送过来的Response,同时还包括对应的Request对象,并在方法内对response进行一些处理,然后根据返回的对象类型做一些操作:

如果返回一个Request对象,下载中间件的执行就会被停止,并且会把这个Request对象交给scrapy引擎重新调度。

如果返回一个Response对象,就会通知下一个下载中间件继续对这个response进行处理

如果其抛出一个 IgnoreRequest 异常,则调用request的errback(Request.errback)

总结

理解了scrapy的整个结构后,下载中间件的功能还是比较好理解的。官方目前也内置了很多实用的下载中间件,所以在大多数场景下,也不用我们手动去编写下载中间件。不过复杂的场景还是用的上的,多学一点也没有坏处。

四、Spider中间件

Spider中间件主要用于scrapy引擎和spider之间的数据处理。包括spider发送Request和Item给scrapy引擎以及scrapy引擎发送Response给spider。

1. spider发送Request和Item给scrapy引擎

spider返回Request和Item给scrapy引擎过程中,会经过一个个spider中间件对result进行处理。spider中间件可以拿到spider返回的result和请求返回的response,这个result是Request和Item的迭代对象。spider中间件进行一些处理之后返回一个result。然后下一个spider中间件继续拿到result处理。

2.scrapy引擎发送Response给spider

scrapy引擎发送Response给spider的过程中,会经过一个个spider中间件对Response进行处理。处理之后spider中间件可以返回None或者抛出一个异常。返回None的话就会继续调用下一个spider中间件继续处理response,抛出异常的话就不会往下执行了。

spider中间件的定义和使用

我们需要写一个类来继承SpiderMiddleware,并在settings.py中配置编写好的这个下载中间件。

SPIDER_MIDDLEWARES = {

'myproject.middlewares.CustomSpiderMiddleware': 543,

'scrapy.contrib.spidermiddleware.offsite.OffsiteMiddleware': None,

}

后面的数字表示该下载中间件的顺序,数字越小越接近scrapy引擎

如果要禁用内置的一些下载中间件,可以将数字设置为None

编写spider中间件需要关注的几个方法:

process_spider_input(response, spider):

接收scrapy引擎传过来的response,用户可以在方法内处理该response。根据返回类型的不同会有不同的表现行为:

如果其返回 None ,Scrapy将会继续处理该response,调用所有其他的中间件直到spider处理该response

如果其跑出一个异常(exception),Scrapy将不会调用任何其他中间件的 process_spider_input() 方法,并调用request的errback。errback的输出将会以另一个方向被重新输入到中间件链中,使用 process_spider_output() 方法来处理,当其抛出异常时则带调用 process_spider_exception() 。

process_spider_output(response, result, spider):

当Spider处理response返回result时,该方法被调用。

必须返回返回包含 Request 或 Item 对象的可迭代对象。

process_spider_exception(response, exception, spider):

当spider或(其他spider中间件的) process_spider_input() 抛出异常时, 该方法被调用

如果其返回 None ,Scrapy将继续处理该异常,调用中间件链中的其他中间件的 process_spider_exception() 方法,直到所有中间件都被调用,该异常到达引擎(异常将被记录并被忽略)

如果其返回一个可迭代对象,则中间件链的 process_spider_output() 方法被调用, 其他的 process_spider_exception() 将不会被调用

process_start_requests(start_requests, spider):

0.15 新版功能

该方法以spider 启动的request为参数被调用,执行的过程类似于 process_spider_output() ,只不过其没有相关联的response并且必须返回request(不是item)。

其接受一个可迭代的对象(start_requests 参数)且必须返回另一个包含 Request 对象的可迭代对象

总结

目前scrapy也内置了很多spider中间件,可以满足大多数场景。虽然平常时候我们可能不会有写spider中间件的时候,但是还是有必要了解的。

五、总结

scrapy的架构原理以及相关组件介绍差不多到这里就结束了。熟悉Python的话,scrapy学起来还是很快的。有空写写爬虫也是挺有意思的,大家有空可以学一学。

最后,有对爬虫或者java技术感兴趣的欢迎联系我一起交流~本人邮箱在下方

python scrapy框架 简书_python爬虫框架——Scrapy架构原理介绍相关推荐

  1. python爬虫框架实例项目_python爬虫框架scrapy实例详解

    生成项目 scrapy提供一个工具来生成项目,生成的项目中预置了一些文件,用户需要在这些文件中添加自己的代码. 打开命令行,执行:scrapy start tutorial/ scrapy.cfg t ...

  2. python爬虫框架scrapy实例详解_python爬虫框架scrapy实例详解

    生成项目 scrapy提供一个工具来生成项目,生成的项目中预置了一些文件,用户需要在这些文件中添加自己的代码. 打开命令行,执行:scrapy startproject tutorial,生成的项目类 ...

  3. python scrapy框架 简书_python scrapy 实战简书网站

    1:创建项目 2:创建爬虫 3:编写start.py文件用于运行爬虫程序# -*- coding:utf-8 -*- #作者: baikai #创建时间: 2018/12/14 14:09 #文件: ...

  4. python中scrapy加请求头_Python爬虫之scrapy框架随机请求头中间件的设置

    方法一,定义一个存放请求头的列表,并从中随机获取请求头: 获取请求头的网址http://www.useragentstring.com/pages/useragentstring.php?name=A ...

  5. python模拟登录爬虫 简书_python爬虫入门之模拟登陆新浪微博

    很多网页浏览都需要首先登陆,比如说新浪微博.当然,这里有一个小技巧,用手机3G版登陆.电脑版会有各种加密,动态加载什么的.我们就耍一下小流氓,柿子拣软的捏么. 浏览器保持登陆是利用我们登陆时收到的co ...

  6. python 串口助手 简书_python用pyserial读取串口问题解决

    object is not callable Error: 'bool' object is not callable 没有返回值 正确代码: ser = serial.Serial('COM7', ...

  7. 小甲鱼python课后题简书_Python练习题100道

    1.有四个数字:1,2,3,4,能组成多少个互不相同且无重复数字的三位数?各是多少? 方法一:遍历所有可能,把重复的剃掉. total=0 for i in range(1,5): for j in ...

  8. python学习笔记简书_Python学习笔记

    本人在廖雪峰的python教程学习python,在此记录一些笔记,记一些重要的东西,以便查询及复习. 输入与输出 用print()在括号中加上字符串,就可以向屏幕上输出指定的文字. print()会依 ...

  9. python excel 饼图 简书_Python可视化29_matplotlib-饼图(pie)

    本文详细介绍python 使用matplotlib.pyplot.pie绘制饼图(pie) 本文快速预览 更多好文,欢迎随缘关注@ image image 目录 默认参数 修改配色 饼图某部分突出or ...

最新文章

  1. ptrace原理与性能对比
  2. K8S 最佳实践-映射外部服务 Endpoints / ExternalName
  3. mysql change命令_Mysql 操作基本命令大全
  4. Ext JS 3.2.0发布(转)
  5. 【GoLang】golang 最佳实践汇总
  6. Jmeter报文体包含过大附件导致请求报文发送失败的解决办法
  7. 比较算盘和计算机的优点,UPD4526BC 二进制与十进制相比较的优点
  8. 怎么用python画天气图_Python气象绘图教程(十五)—Cartopy_5
  9. 最好用的论文数据搜索网站,搜索容易让写论文变轻松!
  10. Unity酱~ 卡通渲染技术分析(一)
  11. 星岚技术 Win10 x64 纯净版 V2021.5【带驱动包】
  12. 大禹电子:超声波水下通讯设备测试结论
  13. chrome图片下载插件
  14. 分享基于白鹭Egret联合Matchvs开发的足球游戏(附Demo源码)
  15. 冒泡算法java代码实现
  16. 保利紫山开启湛江城市墅居新纪元
  17. 数值分析 python_数值分析实验之矩阵特征值(Python代码)
  18. 正版服务器,MC原版服务器搭建教程
  19. 计算机学院混合式局域网 组网方案设计
  20. Java服务器验证登录系统

热门文章

  1. Python基本语法,python入门到精通
  2. 程序员想趁头发还在找个女友,标准:是女的就行
  3. python处理列表中字典_Python 列表、元组、字典及集合操作详解
  4. python图像处理大全
  5. 细菌基因组基本概念(一)
  6. JMG | 基因PRKG2的变异导致骨骼表型异常
  7. 人类为什么没有尾巴?这个跳跃基因抹去了人类的尾巴,并带来了额外风险
  8. 你可能也看过这个生物学家转行后创造的价值 120 亿美元的动画
  9. 【PMP学习笔记】:三、项目经理角色
  10. Keil | 使用Register Windows测量函数的执行时间