>

手把手教你写网络爬虫,遍布式爬虫

- 编辑:www.bifa688.com -

手把手教你写网络爬虫,遍布式爬虫

摘要:从零开始写爬虫,初学者的速成指南!

 

背景

部门(东方IC、图虫)业务驱动,需要搜集大量图片资源,做数据分析,以及正版图片维权。前期主要用node做爬虫(业务比较简单,对node比较熟悉)。随着业务需求的变化,大规模爬虫遇到各种问题。python爬虫具有先天优势,社区资源比较齐全,各种框架也完美支持。爬虫性能也得到极大提升。本次分享从基础知识入手,涉及python 的两大爬虫框架pyspider、scrapy,并基于scrapy、scrapy-redis 做了分布式爬虫的介绍(直接粘贴的ppt截图)会涉及 redis、mongodb等相关知识。

对于反防盗链(自动登录、自动注册... 以及常见策略)、代理、爬虫快照、对象资源入TOS 未做过多介绍。这个双月我们正在做爬虫平台的可视化,可配置化,流程化。

 

手把手教你写网络爬虫(2)

一、前沿

封面:

作者:拓海

1.1 爬虫是什么?

网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本。

图片 1

摘要:从零开始写爬虫,初学者的速成指南!

1.2 为什么是Python?

简单易学:简单到没有学习过任何编程语言的人稍微看下资料就能编写出爬虫 解释型编程语言:编写完后可以直接执行,无须编译

代码重用性高:可以直接把包含某个功能的模块带入其它程序中使用

跨平台性:几乎所有的python程序都可以不加修改的运行在不同的操作系统

 

封面:

二、基础知识

介绍

 图片 2

2.1 Robots协议

Robots 协议也被称作爬虫协议、机器人协议,它的全名叫做网络爬虫排除标准(Robots Exclusion Protocol),用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取。它通常是一个叫做 robots.txt 的文本文件,放在网站的根目录下。

当搜索爬虫访问一个站点时,它首先会检查下这个站点根目录下是否存在 robots.txt 文件,如果存在,搜索爬虫会根据其中定义的爬取范围来爬取。如果没有找到这个文件,那么搜索爬虫便会访问所有可直接访问的页面。

大家好!回顾上一期,我们在介绍了爬虫的基本概念之后,就利用各种工具横冲直撞的完成了一个小爬虫,目的就是猛、糙、快,方便初学者上手,建立信心。对于有一定基础的读者,请不要着急,以后我们会学习主流的开源框架,打造出一个强大专业的爬虫系统!不过在此之前,要继续打好基础,本期我们先介绍爬虫的种类,然后选取最典型的通用网络爬虫,为其设计一个迷你框架。有了自己对框架的思考后,再学习复杂的开源框架就有头绪了。

 

2.2 URL 的含义

概念:

URL(协议(服务方式) IP地址(包括端口号) 具体地址),即统一资源定位符,也就是我们说的网址,统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。爬虫爬取数据时必须要有一个目标的URL才可以获取数据,因此,它是爬虫获取数据的基本依据。

相关:

URI = Universal Resource Identifier 统一资源标志符

URL = Universal Resource Locator 统一资源定位符

URN = Universal Resource Name 统一资源名称

图片 3

image

今天我们会把更多的时间用在思考上,而不是一根筋的coding。用80%的时间思考,20%的时间敲键盘,这样更有利于进步。

介绍

大家好!回顾上一期,我们在介绍了爬虫的基本概念之后,就利用各种工具横冲直撞的完成了一个小爬虫,目的就是猛、糙、快,方便初学者上手,建立信心。对于有一定基础的读者,请不要着急,以后我们会学习主流的开源框架,打造出一个强大专业的爬虫系统!不过在此之前,要继续打好基础,本期我们先介绍爬虫的种类,然后选取最典型的通用网络爬虫,为其设计一个迷你框架。有了自己对框架的思考后,再学习复杂的开源框架就有头绪了。

今天我们会把更多的时间用在思考上,而不是一根筋的coding。用80%的时间思考,20%的时间敲键盘,这样更有利于进步。

 图片 4

 

2.3 浏览网页的过程

在用户浏览网页的过程中,我们可能会看到许多好看的图片,比如 http://image.baidu.com/ ,我们会看到几张的图片以及百度搜索框,这个过程其实就是用户输入网址之后,经过 DNS 服务器,找到服务器主机,向服务器发出一个请求,服务器经过解析之后,发送给用户的浏览器 HTML、JS、CSS 等文件,浏览器解析出来,用户便可以看到形形色色的图片了,其实就是一次http请求的过程

 

语言&环境

语言:带足弹药,继续用Python开路!

 图片 5

 

 

threading:threading库可以在单独的线程中执行任何的在Python中可以调用的对象。Python 2.x中的thread模块已被废弃,用户可以使用threading模块代替。在Python 3中不能再使用thread模块。为了兼容性,Python 3将thread重命名为_thread。

 

queue:queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

 

re:Python 自1.5版本起增加了re模块,它提供Perl风格的正则表达式模式。re模块使 Python语言拥有全部的正则表达式功能。

 

argparse:Python用于解析命令行参数和选项的标准模块,用于代替已经过时的optparse模块。argparse模块的作用是用于解析命令行参数。

 

configparser:读取配置文件的模块。

 

2.4 代理基本原理

2.4.1基本原理

在本机和服务器之间搭建了一个桥,此时本机不是直接向 Web 服务器发起请求,而是向代理服务器发出请求,这个过程 Web 服务器识别出的真实的 IP 就不再是我们本机的 IP 了,就成功实现了 IP 伪装,这就是代理的基本原理

2.4.2代理的作用

1、突破自身 IP 访问限制,访问一些平时不能访问的站点

2、访问一些单位或团体内部资源

3、隐藏真实 IP

2.4.3爬虫代理

在爬取过程中可能遇到同一个 IP 访问过于频繁的问题,网站就会让我们输入验证码或登录或者直接封锁 IP,这样会给爬取带来极大的不便。让服务器误以为是代理服务器的在请求自己。这样在爬取过程中通过不断更换代理,就不会被封锁,可以达到很好的爬取效果

2.4.4代理分类

FTP 代理服务器、主要用于访问 FTP 服务器

HTTP 代理服务器,主要用于访问网页

SSL/TLS 代理,主要用于访问加密网站

2.4.5常见代理设置

免费代理

付费代理

图片 6

image

图片 7

爬虫的种类

 图片 8

 

网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:通用网络爬虫(General Purpose Web Crawler)、聚焦网络爬虫(Focused Web Crawler)、增量式网络爬虫(Incremental Web Crawler)、深层网络爬虫(Deep Web Crawler)。实际的网络爬虫系统通常是几种爬虫技术相结合实现的。

 

通用网络爬虫

通用网络爬虫又称全网爬虫(Scalable Web Crawler),爬取对象从一些种子 URL 扩充到整个 Web。主要为门户站点搜索引擎和大型 Web 服务提供商采集数据。

通用网络爬虫的结构大致可以分为页面爬取模块 、页面分析模块、链接过滤模块、页面存储模块、URL 队列、初始 URL 集合几个部分。为提高工作效率,通用网络爬虫会采取一定的爬取策略。 常用的爬取策略有:深度优先策略、广度优先策略。

1) 深度优先策略(DFS):其基本方法是按照深度由低到高的顺序,依次访问下一级网页链接,直到不能再深入为止。

2) 广度优先策略(BFS):此策略按照网页内容目录层次深浅来爬取页面,处于较浅目录层次的页面首先被爬取。 当同一层次中的页面爬取完毕后,爬虫再深入下一层继续爬取。

 

聚焦网络爬虫

聚焦网络爬虫(Focused Crawler),又称主题网络爬虫(Topical Crawler),是指选择性地爬取那些与预先定义好的主题相关页面的网络爬虫。 和通用网络爬虫相比,聚焦爬虫只需要爬取与主题相关的页面,极大地节省了硬件和网络资源,保存的页面也由于数量少而更新快,还可以很好地满足一些特定人群对特定领域信息的需求。我们之前爬的歌单就属于这一种。

 

增量式网络爬虫

增量式网络爬虫(Incremental Web Crawler)是 指 对 已 下 载 网 页 采 取 增 量式更新和只爬取新产生的或者已经发生变化网页的爬虫,它能够在一定程度上保证所爬取的页面是尽可能新的页面。 和周期性爬取和刷新页面的网络爬虫相比,增量式爬虫只会在需要的时候爬取新产生或发生更新的页面 ,并不重新下载没有发生变化的页面,可有效减少数据下载量,及时更新已爬取的网页,减小时间和空间上的耗费,但是增加了爬取算法的复杂度和实现难度。现在比较火的舆情爬虫一般都是增量式网络爬虫。

 

深网爬虫

Web 页面按存在方式可以分为表层网页(Surface Web)和深层网页(Deep Web,也称 Invisible Web Pages 或 Hidden Web)。 表层网页是指传统搜索引擎可以索引的页面,以超链接可以到达的静态网页为主构成的 Web 页面。Deep Web 是那些大部分内容不能通过静态链接获取的、隐藏在搜索表单后的,只有用户提交一些关键词才能获得的 Web 页面。例如那些用户注册后内容才可见的网页就属于 Deep Web。

 

三、爬虫入门

图片 9

image

 

一个迷你框架

下面以比较典型的通用爬虫为例,分析其工程要点,设计并实现一个迷你框架。架构图如下:

图片 10 

代码结构:

 图片 11

 

config_load.py    配置文件加载

crawl_thread.py    爬取线程

mini_spider.py    主线程

spider.conf    配置文件

url_table.py    url队列、url表

urls.txt    种子url集合

webpage_parse.py    网页分析

webpage_save.py    网页存储

 

看看配置文件里有什么内容:

spider.conf

 图片 12

 

Step 1. 采用BFS还是DFS?

理论上,这两个算法都能够在大致相同的时间里爬取整个互联网上的内容。但显然各个网站最重要的网页应该是它的首页。在极端情况下,如果只能下载非常有限的网页,那么应该下载的所有网站的首页,如果把爬虫再扩大些,应该爬取从首页直接链接的网页,因为这些网页是网站设计者自己认为相当重要的网页。在这个前提下,显然BFS明显优于DFS。事实上在搜索引擎的爬虫里,主要采用的就是BFS。我们的框架采取这种策略。

抓取深度可以通过配置文件中的max_depth设置,只要没到达指定深度,程序就会不停的将解析出的url放入队列中:

mini_spider.py

 图片 13

 

Step 2. 初始URL集合、URL队列

我们来看看通用爬虫如何下载整个互联网。假设从一家门户网站的首页出发,先下载这个网页(深度=0),然后通过分析这个网页,可以找到页面里的所有超链接,也就等于知道了这家门户网站首页所直接连接的全部网页,诸如京东理财、京东白条,京东众筹等(深度=1)。接下来访问、下载并分析京东理财等网页,又能找到其他相连的网页(深度=2)。让计算机不停的做下去,就能下载整个网站。

在这个过程中,我们需要一个“初始URL集合”保存门户的首页,还需要一个“URL队列”保存分析网页得到的超链接。

mini_spider.py

 图片 14

 

url_table.py

图片 15

 

Step 3. 记录哪些网页已经下载过的小本本——URL表。

在互联网上,一个网页可能被多个网页中的超链接所指向。这样在遍历互联网这张图的时候,这个网页可能被多次访问到。为了防止一个网页被下载和解析多次,需要一个URL表记录哪些网页已经下载过。再遇到这个网页的时候,我们就可以跳过它。

crawl_thread.py

 图片 16

 

Step 4. 多个抓取线程

为了提升爬虫性能,需要多个抓取线程,从URL队列获取链接进行处理。多线程并没什么毛病,但Python的多线程可能会引起很多人的质疑,这源于Python设计之初的考虑:GIL。GIL的全称是Global Interpreter Lock(全局解释器锁),某个线程想要执行,必须先拿到GIL,并且在一个Python进程中,GIL只有一个。结果就是Python里一个进程永远只能同时执行一个线程,这就是为什么在多核CPU上,Python的多线程效率并不高。那么我们为什么还要用Python多线程呢?

CPU密集型代码(各种循环处理、编解码等等),在这种情况下,由于计算工作多,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换当然是需要消耗资源的),Python下的多线程对CPU密集型代码并不友好。

IO密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。Python的多线程对IO密集型代码比较友好。

所以,对于IO密集的爬虫程序,使用Python多线程是没问题的。

crawl_thread.py

 图片 17

 

Step 5. 页面分析模块

从网页中解析出URLs或者其他有用的数据。这个是上期重点介绍的,可以参考之前的代码。

 

Step 6. 页面存储模块

保存页面的模块,目前将文件保存为文件,以后可以扩展出多种存储方式,如mysql,mongodb,hbase等等。

webpage_save.py

 图片 18

 

写到这里,整个框架已经清晰的呈现在大家眼前了,千万不要小看它,不管多么复杂的框架都是在这些基本要素上扩展出来的。

 

3.1 常用爬虫lib

请求库:requests、selenium(自动化测试工具) ChromeDrive(chrome 驱动器)、PhantomJS(无界面浏览器)

解析库: LXML(html、xml、Xpath方式)、BeautifulSoup(html、xml)、PyQuery(支持css选择器)、Tesserocr(光学字符识别,验证码)

数据库: mongo、mysql、redis

存储库: pymysql、pymongo、redispy、RedisDump(Redis 数据导入导出的工具)

web库: Flask(轻量级的 Web 服务程序)、Django

其它工具: Charles(网络抓包工具)

语言&环境

下一步

基础知识的学习暂时告一段落,希望能够帮助大家打下一定的基础。下期开始为大家介绍强大成熟的爬虫框架Scrapy,它提供了很多强大的特性来使得爬取更为简单高效,更多精彩,敬请期待!

 

3.2 一个入门栗子

图片 19

image

图片 20

image

语言:带足弹药,继续用Python开路!

3.3 复杂一点的栗子

问题:“防盗链”

防盗链,服务器会识别 headers 中的 referer 是不是它自己,如果不是,有的服务器不会响应,所以我们还可以在 headers 中加入 referer等信息

反“防盗链”

1、完全模拟浏览器的工作

2、构造cookie信息

3、设置header信息

4、Proxy 代理设置

其它策略

Timeout设置

 

3.4 动态渲染页面抓取

Splash 是一个 JavaScript 渲染服务,是一个带有 HTTP API 的轻量级浏览器,同时它对接了 Python 中的 Twisted 和 QT 库,利用它我们同样可以实现动态渲染页面的抓取。

异步方式处理多个网页渲染过程

获取渲染后的页面的源代码或截图

通过关闭图片渲染或者使用 Adblock 规则来加快页面渲染速度

可执行特定的 JavaScript 脚本

可通过 Lua 脚本来控制页面渲染过程

获取渲染的详细过程并通过 HAR(HTTP Archive)格式呈现

图片 21

3.5 爬虫完整流程

图片 22

image

 

四、爬虫框架

threading:threading库可以在单独的线程中执行任何的在Python中可以调用的对象。Python 2.x中的thread模块已被废弃,用户可以使用threading模块代替。在Python 3中不能再使用thread模块。为了兼容性,Python 3将thread重命名为_thread。

4.1 PySpider简介

一个国人编写的强大的网络爬虫系统并带有强大的WebUI。采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项目管理器以及结果查看器

图片 23

image

queue:queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

4.2 PySpider特性

1、python 脚本控制,可以用任何你喜欢的html解析包(内置 pyquery)

2、WEB 界面编写调试脚本,起停脚本,监控执行状态,查看活动历史,获取结果产出

3、数据存储支持MySQL, MongoDB, Redis, SQLite, Elasticsearch; PostgreSQL 及 SQLAlchemy

4、队列服务支持RabbitMQ, Beanstalk, Redis 和 Kombu

5、支持抓取 JavaScript 的页面

6、组件可替换,支持单机/分布式部署,支持 Docker 部署

7、强大的调度控制,支持超时重爬及优先级设置

8、支持python2&3

图片 24

image

图片 25

image

图片 26

image

re:Python 自1.5版本起增加了re模块,它提供Perl风格的正则表达式模式。re模块使 Python语言拥有全部的正则表达式功能。

4.3 Scrapy简介

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

图片 27

image

argparse:Python用于解析命令行参数和选项的标准模块,用于代替已经过时的optparse模块。argparse模块的作用是用于解析命令行参数。

4.4 Scrapy运行流程

1、调度器(Scheduler)从待下载链接中取出一个链接(URL)

2、调度器启动采集模块Spiders模块

3、采集模块把URL传给下载器(Downloader),下载器把资源下载下来

4、提取目标数据,抽取出目标对象(Item),则交给实体管道(item pipeline)进行进一步的处理;比如存入数据库、文本

5、若是解析出的是链接(URL),则把URL插入到待爬取队列当中

configparser:读取配置文件的模块。

五、scrapy框架

爬虫的种类

5.1 Scrapy基本使用

创建项目:scrapy startproject tutorial

创建spider:scrapy genspider quotes quotes.toscrapy.com

运行项目:scrapy crawl dmoz

交互调试:scrapy shell quotes.toscrape.com

保存数据(多种格式):scrapy crawl quotes -o quoqes.json

图片 28

image

 

5.2 scrapy全局指令

startproject:创建项目

genspider:创建爬虫

settings:获取Scrapy的设定

runspider:在未创建项目的情况下,运行一个编写在Python文件中的spider

shell:以给定的URL(如果给出)或者空(没有给出URL)启动Scrapy shell

fetch:使用Scrapy下载器(downloader)下载给定的URL,并将获取到的内容送到标准输出

view:在浏览器中打开给定的URL,并以Scrapy spider获取到的形式展现

Version:输出Scrapy版本

图片 29

5.3 scrapy项目指令

crawl:使用spider进行爬取

check:检查项目是否有错

list: 列出当前项目中所有可用的spider,每行输出一个spider

edit:仅仅是提供一个快捷方式。开发者可以自由选择其他工具或者IDE来编写调试spiderparse

parse:获取给定的URL并使用相应的spider分析处理

bench:运行benchmark测试

 

5.4 scrapy选择器

BeautifulSoup 是在程序员间非常流行的网页分析库,它基于HTML代码的结构来构造一个Python对象, 对不良标记的处理也非常合理,但它有一个缺点:慢。

lxml 是一个基于 ElementTree (不是Python标准库的一部分)的python化的XML解析库(也可以解析HTML)。

Scrapy提取数据有自己的一套机制。它们被称作选择器(seletors),因为他们通过特定的 XPath 或者 CSS 表达式来“选择” HTML文件中的某个部分。

XPath 是一门用来在XML文件中选择节点的语言,也可以用在HTML上。

CSS 是一门将HTML文档样式化的语言。选择器由它定义,并与特定的HTML元素的样式相关连。

Scrapy选择器构建于 lxml 库之上,这意味着它们在速度和解析准确性上非常相似。

图片 30

image

网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:通用网络爬虫(General Purpose Web Crawler)、聚焦网络爬虫(Focused Web Crawler)、增量式网络爬虫(Incremental Web Crawler)、深层网络爬虫(Deep Web Crawler)。实际的网络爬虫系统通常是几种爬虫技术相结合实现的。

5.5 spiders

Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。

以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。

spider中初始的request是通过调用 startrequests() 来获取的。 startrequests() 读取 start_urls 中的URL, 并以 parse 为回调函数生成 Request 。

在回调函数内分析返回的(网页)内容,返回 Item 对象、dict、 Request 或者一个包括三者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。

在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。

最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。

属性

name: 定义spider名字的字符串(string)

allowed_domains: 包含了 spider 允许爬取的域名(domain)列表(list)

start_urls: URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取

custom_settings: 该设置是一个dict.当启动spider时,该设置将会覆盖项目级的设置. 由于设置必须在初始化(instantiation)前被更新,所以该属性 必须定义为class属性

crawler: 该属性在初始化class后,由类方法 from_crawler() 设置, 并且链接了本spider实例对应的 Crawler 对象

settings: crawler 的配置管理器,扩展(extensions)和中间件(middlewares)使用它用来访问 Scrapy 的配置

logger: self.logger.info('日志:%s', response.status)

方法

from_crawler: 如果存在,则调用此类方法以从 Crawler 创建 pipeline 实例。它必须返回一个新的pipeline实例。 Crawler 对象提供对所有 Scrapy 核心组件(如settings 和 signals)的访问; 它是 pipeline 访问它们并将其功能挂钩到Scrapy中的一种方法

start_requests: 该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request

make_requests_from_url: 该方法接受一个URL并返回用于爬取的 Request 对象

parse: 当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法

log: 使用 scrapy.log.msg() 方法记录(log)message

closed: 当spider关闭时,该函数被调用

通用网络爬虫

5.6 Item Pipeline

当 Item 在 Spider 中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。

以下是item pipeline的一些典型应用:

1、清理HTML数据

2、验证爬取的数据(检查item包含某些字段)

3、查重(并丢弃)

4、将爬取结果保存到数据库中

方法

process_item(self, item, spider): 每个item pipeline组件都需要调用该方法,这个方法必须返回一个具有数据的dict,或是 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。

open_spider: 当spider被开启时,这个方法被调用。

close_spider: 当spider被关闭时,这个方法被调用

from_crawler: 获取setting 配置信息

例子:数据持久化到mongo

图片 31

image

通用网络爬虫又称全网爬虫(Scalable Web Crawler),爬取对象从一些种子 URL 扩充到整个 Web。主要为门户站点搜索引擎和大型 Web 服务提供商采集数据。

5.7 Downloader Middleware

下载器中间件是介于 Scrapy 的 request/response 处理的钩子框架。 是用于全局修改Scrapy request 和 response 的一个轻量、底层的系统。

激活

要激活下载器中间件组件,将其加入到DOWNLOADER_MIDDLEWARES 设置中。 该设置是一个字典(dict),键为中间件类的路径,值为其中间件的顺序(order)。

方法

1、process_request(request, spider): 当每个request通过下载中间件时,该方法被调用

2、processresponse(request, response, spider): processrequest() 必须返回以下之一: 返回一个 Response 对象、 返回一个 Request 对象或raise一个 IgnoreRequest 异常。如果其返回一个 Response (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理。

3、processexception(request, exception, spider): 当下载处理器(download handler)或 processrequest() (下载中间件)抛出异常(包括 IgnoreRequest 异常)时, Scrapy调用 process_exception()

例子:添加代理

图片 32

image

通用网络爬虫的结构大致可以分为页面爬取模块 、页面分析模块、链接过滤模块、页面存储模块、URL 队列、初始 URL 集合几个部分。为提高工作效率,通用网络爬虫会采取一定的爬取策略。 常用的爬取策略有:深度优先策略、广度优先策略。

六、scrapy 搭建项目

1) 深度优先策略(DFS):其基本方法是按照深度由低到高的顺序,依次访问下一级网页链接,直到不能再深入为止。

6.1 爬虫思路

图片 33

image

2) 广度优先策略(BFS):此策略按照网页内容目录层次深浅来爬取页面,处于较浅目录层次的页面首先被爬取。 当同一层次中的页面爬取完毕后,爬虫再深入下一层继续爬取。

6.2 实际项目分析

图片 34

image

起始页

图片 35

image

项目结构

图片 36

image

聚焦网络爬虫

七、分布式爬虫

聚焦网络爬虫(Focused Crawler),又称主题网络爬虫(Topical Crawler),是指选择性地爬取那些与预先定义好的主题相关页面的网络爬虫。 和通用网络爬虫相比,聚焦爬虫只需要爬取与主题相关的页面,极大地节省了硬件和网络资源,保存的页面也由于数量少而更新快,还可以很好地满足一些特定人群对特定领域信息的需求。我们之前爬的歌单就属于这一种。

7.1 单主机爬虫架构

本机维护一个爬虫队列,scheduler 进行调度

Q:多台主机协作的关键是什么?

A:共享爬虫队列

图片 37

image

单主机爬虫架构

图片 38

image

增量式网络爬虫

7.2 分布式爬虫架构

图片 39

image

分布式爬虫架构

图片 40

image

增量式网络爬虫(Incremental Web Crawler)是 指 对 已 下 载 网 页 采 取 增 量式更新和只爬取新产生的或者已经发生变化网页的爬虫,它能够在一定程度上保证所爬取的页面是尽可能新的页面。 和周期性爬取和刷新页面的网络爬虫相比,增量式爬虫只会在需要的时候爬取新产生或发生更新的页面 ,并不重新下载没有发生变化的页面,可有效减少数据下载量,及时更新已爬取的网页,减小时间和空间上的耗费,但是增加了爬取算法的复杂度和实现难度。现在比较火的舆情爬虫一般都是增量式网络爬虫。

7.3 问题

Q1:队列怎么选?

A1: Redis队列

Redis 非关系型数据库,key-value形式存储,结构灵活

是内存中的数据结构存储系统,处理速度快,性能好

提供队列、集合等多种存储结构,方便队列维护

Q2:怎么去重?

A2:Redis集合

Redis 提供集合数据结构,在redis集合中存储每个request的指纹

在向redis集合中存储request指纹的时候,先验证指纹是否存在?

[如果存在]:则不添加request到队列

[不存在]:则将request加入队列,并将指纹加入集合

Q3:怎样防止中断?

A3:启动判断

在每台从机 scrapy 启动时 都会首先判断当前 redis reqeust队列是否为空

[不为空]:从队列中取得下一个 request ,进行执行爬虫

[空]:重新开始爬取,第一台从机执行爬取向队列中添加request

Q4:怎样实现该架构?

A4:Scrapy-Redis

scrapy是Python的一个非常好用的爬虫框架,功能非常强大,但是当我们要爬取的页面非常多的时候,单个主机的处理能力就不能满足我们的需求了(无论是处理速度还是网络请求的并发数),这时候分布式爬虫的优势就显现出来,人多力量大。而scrapy-Redis就是结合了分布式数据库redis,重写了scrapy一些比较关键的代码(scrapy的调度器、队列等组件),将scrapy变成一个可以在多个主机上同时运行的分布式爬虫。

github地址: https://github.com/rmax/scrapy-redis

深网爬虫

7.4 源码解读

阅读源码前:需要了解 scrapy 的运行原理,否则并没什么用。

scrapy-redis 工程的主体还是 redis 和 scrapy 两个库,将两个库的核心功能结合,实现分布式。

图片 41

image

1 connection.py

负责根据setting中配置实例化redis连接。被dupefilter和scheduler调用,总之涉及到redis存取的都要使用到这个模块

图片 42

image

2 dupefilter.py

通过继承 BaseDupeFilter 重写他的方法,实现了基于redis的 request 判重。scrapy-redis使用 redis的一个 set 中插入 fingerprint(不同spider的key不同)

spider名字 DupeFilter的key就是为了在不同主机上的不同爬虫实例,只要属于同一种spider,就会访问到同一个set,而这个set就是他们的url判重池 。

DupeFilter 判重会在 scheduler 类中用到,每一个request在进入调度之前都要进行判重,如果重复就不需要参加调度,直接舍弃就好了

图片 43

image

3 picklecompat.py

loads 和 dumps 两个函数,其实就是实现了一个 serializer,因为 redis 数据库不能存储复杂对象(value部分只能是字符串,字符串列表,字符串集合和hash,key部分只能是字符串),所以存储前需要先序列化成文本才行

这个 serializer 主要用于 scheduler 存 reuqest 对象。

为什么不用json格式?(item pipeline 的串行化默认用的就是 json)

图片 44

image

4 pipelines.py

pipeline 文件实现了一个 item pipieline 类,和 scrapy 的 item pipeline 是同一个对象,从settings中获取我们配置的REDISITEMSKEY作为key,把item串行化之后存入redis数据库对应的value中(这个value是list,我们的每个item是这个list中的一个结点),这个pipeline把提取出的item存起来,主要是为了方便我们延后处理数据。

图片 45

image

5 queue.py

这里实现了三种方式的 Queue

SpiderQueue(队列):先进先出

SpiderStack(栈):先进后出

SpiderPriorityQueue(优先级队列)

这些容器类都会作为scheduler调度request的容器,scheduler在每个主机上都会实例化一个,并且和spider一一对应,所以分布式运行时会有一个spider的多个实例和一个scheduler的多个实例存在于不同的主机上,但是,因为scheduler都是用相同的容器,而这些容器都连接同一个redis服务器,又都使用spider名加queue来作为key读写数据,所以不同主机上的不同爬虫实例公用一个request调度池,实现了分布式爬虫之间的统一调度。

图片 46

image

6 scheduler.py

重写了scheduler类,代替scrapy.core.scheduler 的原有调度器,对原有调度器的逻辑没有很大的改变,主要是使用了redis作为数据存储的媒介,以达到各个爬虫之间的统一调度。scheduler负责调度各个spider的request请求,scheduler初始化时,通过settings文件读取queue和dupefilters的类型,配置queue和dupefilters使用的key。每当一个request要被调度时,enqueuerequest被调用,scheduler使用dupefilters来判断这个url是否重复,如果不重复,就添加到queue的容器中(可以在settings中配置)。当调度完成时,nextrequest被调用,scheduler就通过queue容器的接口,取出一个request,把他发送给相应的spider,让spider进行爬取工作。

图片 47

python学习交流群:125240963

7 spider.py

设计的这个spider从redis中读取要爬的url,然后执行爬取,若爬取过程中返回更多的url,那么继续进行直至所有的request完成。之后继续从redis中读取url,循环这个过程。

分析:在这个spider中通过connect signals.spideridle信号实现对crawler状态的监视。当idle时,返回新的makerequestsfromurl(url)给引擎,进而交给调度器调度。

图片 48

转载:

Web 页面按存在方式可以分为表层网页(Surface Web)和深层网页(Deep Web,也称 Invisible Web Pages 或 Hidden Web)。 表层网页是指传统搜索引擎可以索引的页面,以超链接可以到达的静态网页为主构成的 Web 页面。Deep Web 是那些大部分内容不能通过静态链接获取的、隐藏在搜索表单后的,只有用户提交一些关键词才能获得的 Web 页面。例如那些用户注册后内容才可见的网页就属于 Deep Web。

一个迷你框架

下面以比较典型的通用爬虫为例,分析其工程要点,设计并实现一个迷你框架。架构图如下:

 

图片 49

 

代码结构:

 

图片 50

 

config_load.py 配置文件加载

crawl_thread.py 爬取线程

mini_spider.py 主线程

spider.conf 配置文件

url_table.py url队列、url表

urls.txt 种子url集合

webpage_parse.py 网页分析

webpage_save.py 网页存储

看看配置文件里有什么内容:

spider.conf

 

图片 51

 

Step 1.采用BFS还是DFS?

理论上,这两个算法都能够在大致相同的时间里爬取整个互联网上的内容。但显然各个网站最重要的网页应该是它的首页。在极端情况下,如果只能下载非常有限的网页,那么应该下载的所有网站的首页,如果把爬虫再扩大些,应该爬取从首页直接链接的网页,因为这些网页是网站设计者自己认为相当重要的网页。在这个前提下,显然BFS明显优于DFS。事实上在搜索引擎的爬虫里,主要采用的就是BFS。我们的框架采取这种策略。

抓取深度可以通过配置文件中的max_depth设置,只要没到达指定深度,程序就会不停的将解析出的url放入队列中:

Step 2.初始URL集合、URL队列

我们来看看通用爬虫如何下载整个互联网。假设从一家门户网站的首页出发,先下载这个网页(深度=0),然后通过分析这个网页,可以找到页面里的所有超链接,也就等于知道了这家门户网站首页所直接连接的全部网页,诸如京东理财、京东白条,京东众筹等(深度=1)。接下来访问、下载并分析京东理财等网页,又能找到其他相连的网页(深度=2)。让计算机不停的做下去,就能下载整个网站。

在这个过程中,我们需要一个“初始URL集合”保存门户的首页,还需要一个“URL队列”保存分析网页得到的超链接。

mini_spider.py

url_table.py

 

图片 52

 

Step 3.记录哪些网页已经下载过的小本本——URL表。

在互联网上,一个网页可能被多个网页中的超链接所指向。这样在遍历互联网这张图的时候,这个网页可能被多次访问到。为了防止一个网页被下载和解析多次,需要一个URL表记录哪些网页已经下载过。再遇到这个网页的时候,我们就可以跳过它。

crawl_thread.py

 

图片 53

 

Step 4.多个抓取线程

为了提升爬虫性能,需要多个抓取线程,从URL队列获取链接进行处理。多线程并没什么毛病,但Python的多线程可能会引起很多人的质疑,这源于Python设计之初的考虑:GIL。GIL的全称是Global Interpreter Lock(全局解释器锁),某个线程想要执行,必须先拿到GIL,并且在一个Python进程中,GIL只有一个。结果就是Python里一个进程永远只能同时执行一个线程,这就是为什么在多核CPU上,Python的多线程效率并不高。那么我们为什么还要用Python多线程呢?

CPU密集型代码(各种循环处理、编解码等等),在这种情况下,由于计算工作多,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换当然是需要消耗资源的),Python下的多线程对CPU密集型代码并不友好。

IO密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。Python的多线程对IO密集型代码比较友好。

所以,对于IO密集的爬虫程序,使用Python多线程是没问题的。

crawl_thread.py

 

图片 54

 

Step 5.页面分析模块

从网页中解析出URLs或者其他有用的数据。这个是上期重点介绍的,可以参考之前的代码。

Step 6.页面存储模块

保存页面的模块,目前将文件保存为文件,以后可以扩展出多种存储方式,如mysql,mongodb,hbase等等。

webpage_save.py

 

图片 55

 

写到这里,整个框架已经清晰的呈现在大家眼前了,千万不要小看它,不管多么复杂的框架都是在这些基本要素上扩展出来的。

下一步

基础知识的学习暂时告一段落,希望能够帮助大家打下一定的基础。下期开始为大家介绍强大成熟的爬虫框架Scrapy,它提供了很多强大的特性来使得爬取更为简单高效,更多精彩,敬请期待!

获取视频资料,转发此文 点击喜欢,然后进作者创建qun:814468827 找群文件:网易云音乐视频教程 源码

本文由必发88手机版发布,转载请注明来源:手把手教你写网络爬虫,遍布式爬虫