【Python基础】分布式爬虫工具有哪些

2021-02-02 10:10发布

3条回答
给你三个亿
2楼 · 2021-02-25 15:07

一、分布式爬虫架构

在了解分布式爬虫架构之前,首先回顾一下Scrapy的架构,如下图所示。


Scrapy单机爬虫中有一个本地爬取队列Queue,这个队列是利用deque模块实现的。如果新的Request生成就会放到队列里面,随后Request被Scheduler调度。之后,Request交给Downloader执行爬取,简单的调度架构如下图所示。

如果两个Scheduler同时从队列里面取Request,每个Scheduler都有其对应的Downloader,那么在带宽足够、正常爬取且不考虑队列存取压力的情况下,爬取效率会有什么变化?没错,爬取效率会翻倍。

这样,Scheduler可以扩展多个,Downloader也可以扩展多个。而爬取队列Queue必须始终为一个,也就是所谓的共享爬取队列。这样才能保证Scheduer从队列里调度某个Request之后,其他Scheduler不会重复调度此Request,就可以做到多个Schduler同步爬取。这就是分布式爬虫的基本雏形,简单调度架构如下图所示。

我们需要做的就是在多台主机上同时运行爬虫任务协同爬取,而协同爬取的前提就是共享爬取队列。这样各台主机就不需要各自维护爬取队列,而是从共享爬取队列存取Request。但是各台主机还是有各自的Scheduler和Downloader,所以调度和下载功能分别完成。如果不考虑队列存取性能消耗,爬取效率还是会成倍提高。

二、维护爬取队列

那么这个队列用什么来维护?首先需要考虑的就是性能问题。我们自然想到的是基于内存存储的Redis,它支持多种数据结构,例如列表(List)、集合(Set)、有序集合(Sorted Set)等,存取的操作也非常简单。

Redis支持的这几种数据结构存储各有优点。

  • 列表有lpush()lpop()rpush()rpop()方法,我们可以用它来实现先进先出式爬取队列,也可以实现先进后出栈式爬取队列。

  • 集合的元素是无序的且不重复的,这样我们可以非常方便地实现随机排序且不重复的爬取队列。

  • 有序集合带有分数表示,而Scrapy的Request也有优先级的控制,我们可以用它来实现带优先级调度的队列。

我们需要根据具体爬虫的需求来灵活选择不同的队列。

三、如何去重

Scrapy有自动去重,它的去重使用了Python中的集合。这个集合记录了Scrapy中每个Request的指纹,这个指纹实际上就是Request的散列值。我们可以看看Scrapy的源代码,如下所示:


import hashlib
def request_fingerprint(request, include_headers=None):
   if include_headers:
       include_headers = tuple(to_bytes(h.lower())
                                for h in sorted(include_headers))
   cache = _fingerprint_cache.setdefault(request, {})
   if include_headers not in cache:
       fp = hashlib.sha1()
       fp.update(to_bytes(request.method))
       fp.update(to_bytes(canonicalize_url(request.url)))
       fp.update(request.body or b'')
       if include_headers:
           for hdr in include_headers:
               if hdr in request.headers:
                   fp.update(hdr)
                   for v in request.headers.getlist(hdr):
                       fp.update(v)
       cache[include_headers] = fp.hexdigest()
   return cache[include_headers]

request_fingerprint()就是计算Request指纹的方法,其方法内部使用的是hashlib的sha1()方法。计算的字段包括Request的Method、URL、Body、Headers这几部分内容,这里只要有一点不同,那么计算的结果就不同。计算得到的结果是加密后的字符串,也就是指纹。每个Request都有独有的指纹,指纹就是一个字符串,判定字符串是否重复比判定Request对象是否重复容易得多,所以指纹可以作为判定Request是否重复的依据。


那么我们如何判定重复呢?Scrapy是这样实现的,如下所示:


def __init__(self):
   self.fingerprints = set()

def request_seen(self, request):
   fp = self.request_fingerprint(request)
   if fp in self.fingerprints:
       return True
   self.fingerprints.add(fp)

在去重的类RFPDupeFilter中,有一个request_seen()方法,这个方法有一个参数request,它的作用就是检测该Request对象是否重复。这个方法调用request_fingerprint()获取该Request的指纹,检测这个指纹是否存在于fingerprints变量中,而fingerprints是一个集合,集合的元素都是不重复的。如果指纹存在,那么就返回True,说明该Request是重复的,否则这个指纹加入到集合中。如果下次还有相同的Request传递过来,指纹也是相同的,那么这时指纹就已经存在于集合中,Request对象就会直接判定为重复。这样去重的目的就实现了。

Scrapy的去重过程就是,利用集合元素的不重复特性来实现Request的去重。

对于分布式爬虫来说,我们肯定不能再用每个爬虫各自的集合来去重了。因为这样还是每个主机单独维护自己的集合,不能做到共享。多台主机如果生成了相同的Request,只能各自去重,各个主机之间就无法做到去重了。

那么要实现去重,这个指纹集合也需要是共享的,Redis正好有集合的存储数据结构,我们可以利用Redis的集合作为指纹集合,那么这样去重集合也是利用Redis共享的。每台主机新生成Request之后,把该Request的指纹与集合比对,如果指纹已经存在,说明该Request是重复的,否则将Request的指纹加入到这个集合中即可。利用同样的原理不同的存储结构我们也实现了分布式Reqeust的去重。

四、防止中断

在Scrapy中,爬虫运行时的Request队列放在内存中。爬虫运行中断后,这个队列的空间就被释放,此队列就被销毁了。所以一旦爬虫运行中断,爬虫再次运行就相当于全新的爬取过程。

要做到中断后继续爬取,我们可以将队列中的Request保存起来,下次爬取直接读取保存数据即可获取上次爬取的队列。我们在Scrapy中指定一个爬取队列的存储路径即可,这个路径使用JOB_DIR变量来标识,我们可以用如下命令来实现:


scrapy crawl spider -s JOB_DIR=crawls/spider

更加详细的使用方法可以参见官方文档,链接为:https://doc.scrapy.org/en/latest/topics/jobs.html。

在Scrapy中,我们实际是把爬取队列保存到本地,第二次爬取直接读取并恢复队列即可。那么在分布式架构中我们还用担心这个问题吗?不需要。因为爬取队列本身就是用数据库保存的,如果爬虫中断了,数据库中的Request依然是存在的,下次启动就会接着上次中断的地方继续爬取。

所以,当Redis的队列为空时,爬虫会重新爬取;当Redis的队列不为空时,爬虫便会接着上次中断之处继续爬取。

五、架构实现

我们接下来就需要在程序中实现这个架构了。首先实现一个共享的爬取队列,还要实现去重的功能。另外,重写一个Scheduer的实现,使之可以从共享的爬取队列存取Request。

幸运的是,已经有人实现了这些逻辑和架构,并发布成叫Scrapy-Redis的Python包。接下来,我们看看Scrapy-Redis的源码实现,以及它的详细工作原理


有点好奇
3楼 · 2021-08-20 12:00

QuickRecon:具有查找子域名名称、收集电子邮件地址并寻找人际关系等功能。

PyRailgun:简洁、轻量、高效的网页抓取框架。

Scrapy基于 Twisted 的异步处理框架,文档齐全。

Ruya:一个在广度优先方面表现优秀,基于等级抓取的开放源代码的网络爬虫。在英语日语页面的抓取表现良好,它在 GPL 许可下发行,并且完全用 Python 编写。按照 robots.txt 有一个延时的单网域延时爬虫。

PySipder:PySipder 是一个 Python 爬虫程序。演示地址:http://demo.pyspider.org/。使用 Python 编写脚本,分布式架构,提供强大的 API,支持 Python 2&3、支持 JavaScript 页面。强大的 WebUI 和脚本编辑器、任务监控和项目管理和结果查看。后端系统支持:MySQLMongoDBSQLitePostgresql。支持任务优先级、重试、定期抓取等。

征戰撩四汸
4楼 · 2022-06-22 17:57

ava

Arachnid微型爬虫框架,含有一个小型 HTML 解析器。是一个基于Java的web spider框架.它包含一个简单的HTML剖析器可以分析包含HTML内容的输入流.经过实现Arachnid的子类就可以开发一个简单的Web spiders并可以在Web站上的每一个页面被解析以后增长几行代码调用。 Arachnid的下载包中包含两个spider应用程序例子用于演示如何使用该框架。
http://arachnid.sourceforge.net/
GPL

crawlzilla安装简易,拥有中文分词功能。Apache2

Ex-Crawler由守护进程执行,使用数据库存储网页信息。GPLv3

Heritrix一个互联网档案馆级的爬虫,设计的目标是对大型网络的大部份内容的按期存档快照,用 java 编写。严格遵守 robots 文件的排除指示和 META robots 标签。http://crawler.archive.org/LGPL

heyDr轻量级开源多线程垂直检索爬虫框架。GPLv3

ItSucksItSucks是一个java web spider(web机器人,爬虫)开源项目。支持经过下载模板和正则表达式来定义下载规则。提供一个swing GUI操做界面。下载地址:http://itsucks.sourceforge.net/不详

jcrawl轻量、性能优良,能够从网页抓取各类类型的文件。Apache

JSpider在 GPL 许可下发行,高度可配置、可定制、功能强大、容易扩展的网络爬虫引擎。你能够利用它来检查网站的错误(内在的服务器错误等),网站内外部连接检查,分析网站的结构(可建立一个网站地图),下载整个Web站点,你还能够写一个JSpider插件来扩展你所须要的功能。LGPL

Leopdo包括全文和分类垂直搜索,以及分词系统。Apache

MetaSeeker网页抓取、信息提取、数据抽取工具包,操做简单。不详

Playfish经过 XML 配置文件实现高度可定制性与可扩展性。MIT

Spiderman灵活、扩展性强,微内核+插件式架构,经过简单的配置就能够完成数据抓取,无需编写一句代码。Apache

webmagic功能覆盖整个爬虫生命周期,使用 Xpath 和正则表达式进行连接和内容的提取。Apache

Web-Harvest运用 XSLT、XQuery、正则表达式等技术来实现对 Text 或 XML 的操做,具备可视化的界面。Web-Harvest是一个Java开源Web数据抽取工具。它可以收集指定的Web页面并从这些页面中提取有用的数据。
http://web-harvest.sourceforge.net
BSD

WebSPHINX(Miller and Bharat, 1998) 由 java 类库构成,基于文本的搜索引擎。它使用多线程进行网页检索,html 解析,拥有一个图形用户界面用来设置开始的种子 URL 和抽取下载的数据;WebSPHINX 由两部分组成:爬虫工做平台和 WebSPHINX 类包。由两部分组成:爬虫工做平台和WebSPHINX类包。
http://www.cs.cmu.edu/~rcm/websphinx/
Apache

YaCy基于 P2P 网络的免费分布式 Web 搜索引擎(在 GPL 许可下发行)。其核心是分布在数百台计算机上的被称 为YaCy-peer的计算机程序,基于P2P网络构成了YaCy网络,整个网络是一个分散的架构,在其中全部的YaCy-peers都处于对等的地位, 没有统一的中心服务器,每一个YaCy-peer都能独立的进行互联网的爬行抓取、分析及建立索引库,经过P2P网络与其余YaCy-peers进行共享, 而且每一个YaCy-peer又都是一个独立的代理服务器,可以对本机用户使用过的网页进行索引,而且采起多机制来保护用户的隐私,同时用户也经过本机运行 的Web服务器进行查询及返回查询结果。
YaCy搜索引擎主要包括五个部分,除普通搜索引擎所具备的爬行器、索引器、反排序的索引库外,它还包括了一个很是丰富的搜索与管理界面以及用于数据共享的P2P网络。
GPL

Nutch用 java 编写,在 Apache 许可下发行的爬虫。它能够用来链接 Lucene 的全文检索套件。Nutch是Lucene的做者Doug Cutting发起的另外一个开源项目,它是构建于Lucene基础上的完整的Web搜索引擎系统,虽然诞生时间不长,但却以其优良血统及简洁方便的使用方 式而广收欢迎。咱们能够使用Nutch搭建相似Google的完整的搜索引擎系统,进行局域网、互联网的搜索。Apache

Agent Kernel当一个爬虫抓取时,用来进行安排,并发和存储的 java 框架。/

Dine一个多线程的 java 的 http 客户端。它能够在 LGPL 许可下进行二次开发。LGPL




Python

QuickRecon具备查找子域名名称、收集电子邮件地址并寻找人际关系等功能。GPLv3

PyRailgun简洁、轻量、高效的网页抓取框架。MIT

Scrapy基于 Twisted 的异步处理框架,文档齐全。BSD

Ruya一个在广度优先方面表现优秀,基于等级抓取的开放源代码的网络爬虫。在英语和日语页面的抓取表现良好,它在 GPL 许可下发行,而且彻底用 Python 编写。按照 robots.txt 有一个延时的单网域延时爬虫。GPL

PySipderPySipder 是一个 Python 爬虫程序。演示地址:http://demo.pyspider.org/。使用 Python 编写脚本,分布式架构,提供强大的 API,支持 Python 2&3、支持 JavaScript 页面。强大的 WebUI 和脚本编辑器、任务监控和项目管理和结果查看。后端系统支持:MySQL、MongoDB、SQLite、Postgresql。支持任务优先级、重试、按期抓取等。


相关问题推荐

  • 什么是Python列表2020-12-03 10:47
    回答 20

    在python中列表(list)是使用最频繁的数据类型,在其他语言中通常叫做数组。列表由一系列按特定顺序排列的元素组成。你可以创建包含字母表中所有字母、数字0~9或所有家庭成员姓名的列表;也可以将任何东西加入列表中,其中的元素之间可以没有任何关系。...

  • 回答 16

    简单来讲,爬虫就是一个探测机器,它的基本操作就是模拟人的行为去各个网站溜达,点点按钮,查查数据,或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。...

  • 回答 17

    因为Python可以做数据分析  数据挖掘,数据挖掘的话简单来说就是爬虫工程师

  • 回答 13

    1)学习爬虫,可以私人订制一个搜索引擎,并且可以对搜索引擎的数据采集工作原理进行更深层次地理解。有的朋友希望能够深层次地了解搜索引擎的爬虫工作原理,或者希望自己能够开发出一款私人搜索引擎,那么此时,学习爬虫是非常有必要的。简单来说,我们学会了...

  • 回答 4

    大部分数据都是可以爬的,不过有些网站对数据的加密做的非常好,在解析的过程中要消耗很长的时间。

  • 爬虫是什么?2020-08-26 10:11
    回答 10

    抓取数据,进行统计和分析

  • 成都爬虫好找工作吗2020-10-14 10:23
    回答 12

    在成都找网络爬虫工作也是可以的,自己可以先到招聘软件上看看当地招聘的需求量以及薪资待遇水平怎么样,要是能达到自己的预期效果可以在当地工作,要不可以到北上广深找工作,就业机会能更多些。...

  • 回答 9

    两种方式,一种是MySQL自带的命令行窗口,一种是图形用户管理工具,前者类似于一个cmd窗口,日常管理维护数据库不是很方便,后者就是一个图形用户管理软件,种类繁多,使用起来也相对容易一些...

  • 回答 4

    不可以所有编程最起码都得学函数,分支,循环之后才可以编写代码

  • 回答 2

    一台主机  多台从机

  • 回答 7

    代理ip网址http://www.goubanjia.com/http://www.ip181.com/https://www.kuaidaili.com/python 环境安装requests库安装bs4库proxies设置代理服务器地址proxies = {'http':  'http://61.155.164.110:3128'}http://www.goub......

  • 回答 2

    import  requestsimport  jsonfrom bs4 import BeautifulSoupfrom    urllib.request import urlretrieve#构造函数def sk():    #请求头    header={        'user-Agent':'Mozilla/5.0 (Windows NT 10.0; W...

  • 回答 3

    针对字符串中本身含有双引号,我们可以利用单引号进行字符串的定义来解决这个问题。使用单引号作为字符串的界限就不会引起识别异常问题,保证字符串的合理定义

  • 回答 2

    要用unicode编码来替换。

没有解决我的问题,去提问