当前位置: 首页 > 后端技术 > Python

上万站点、日数据过亿的大型爬虫是如何实现的?

时间:2023-03-26 15:35:28 Python

分布式爬虫、智能解析、消息队列、去重调度等技术点,是我们身边比几大搜索引擎接触最频繁、规模最大的爬虫。但是搜索引擎的爬取方式和我们爬虫工程师的爬取方式有很大的不同,没有太大的参考价值。今天要讲的是舆论方向的爬虫(架构及关键技术原理),主要涉及:网页文本智能提取;分布式爬虫;爬虫DATA/URL去重;部署爬虫;分布式爬虫调度;自动渲染技术;消息队列在爬虫领域的应用;多种形式的反爬虫;继续阅读并准备好在本文末尾角逐奖品!1、网页文本智能提取舆情其实就是舆情的情况。要把握舆论,必须要有足够的内容信息。除了一些大型的内容/社交平台(比如微博)开放了商业接口外,其他的都需要依靠爬虫来采集。因此,舆论方向的爬虫工程师需要面对上千个不同内容和结构的站点。我们用一张图来表示他们面临的问题:是的,他们的收集器必须能够适应成千上万个站点的结构,并从不同样式的HTML文本中提取主要内容——标题、正文、发布时间和作者。如果是你,你会用什么样的设计来满足业务需求?曾经想象过这样一个问题,在技术群里看到有朋友问过类似的问题,但是很难得到满意的回答。有人说:使用分类的方法,将相似的内容归为一类,然后为一类内容配置抽取规则;使用正则化提取指定标签中的内容;利用深度学习、NLP语义分析找出有意义的地方提取内容;利用计算机视觉让人点击,然后根据页面的相似度进行分类提取(其实就是自动化版的分类法);使用算法计算文本的密度,然后提取;总之,各种idea层出不穷,但最终还是没有听到实际应用的消息。目前大部分公司都采用手动配置XPATH规则的方式。采集时,通过URL匹配相应的提取规则,然后调用规则实现多站爬取。这种方法很有效,在企业中也长期使用,比较稳定,但缺点也很明显——费时费力,成本高!偶然有一天,看到微信技术群里有人(优秀的Python工程师青楠)发布了一个文本自动抽取的算法库GeneralNewsExtractor(以下简称GNE)。本库参考了武汉邮电学院洪宏辉、丁世涛、黄傲、郭志远等人的论文—《基于文本及符号密度的网页正文提取方法》,并基于该论文用Python代码实现,即GNE.它的原理是提取网页DOM中的文本和其中的标点符号,根据文本中标点符号的密度,利用算法从一个句子延伸为一段文字和一篇文章。GNE能有效剔除除文字以外的广告、推荐栏、介绍栏等“噪音”内容,准确识别网页文字,识别率高达99%(测试选用的内容为国内文章主流门户/媒体平台)。GNE的具体算法细节和源码分析请参考《Python3 网络爬虫宝典》的第五章。有了它,基本可以解决90%以上的舆情方向爬虫分析需求,剩下的10%可以根据抽取规则进行调整或完全定制,解放了一大波XPATH工程师。2、爬虫DATA/URL去重舆情业务一定要密切关注网站是否有新内容发布。要求是越快越好,但由于各种硬件和软件限制,通常要求在30分钟或15分钟内监控新内容。内容。要监控目标网站的内容变化,我们可以选择的更好的方式是轮询。不断访问网页,判断是否有“新内容”,有则进行爬取,无“新内容”则不爬取。那么问题来了,应用程序如何知道哪些内容是“新”的,哪些内容是“旧”的?拆解问题,“新内容”就是没有被抓取的内容。这时候我们就需要用一些东西来记录这篇文章是否被爬取过,每次有文章要爬取的时候进行比较。这是这个问题的解决方案。那靠什么来比较呢?我们都知道文章的url几乎都是一样的,不会重复,所以我们可以选择文章的url作为判断的依据,也就是把抓取到的url像列表一样存放在一个容器中。判断要抓取的URL是否已经存储在容器中,如果是,则表示已经抓取到,直接丢弃,进入下一个URL的判断过程。整体逻辑如下图:这就是爬虫领域的“去重”。其实去重大致可以分为内容(DATA)去重和链接(URL)去重。这里我们只是顺着舆论的方向说一下去重要求。如果是电商方向的去重,那么URL不能作为判断依据,因为电商爬虫(比如比价软件)的目的主要是判断价格变化。这时候判断变化的依据应该是商品的关键信息(比如价格、折扣),也就是DATA去重。去重原理了解了,那么用什么作为存储去重基础的容器呢?MySQL?雷迪斯?数据库?记忆?其实大部分工程师选择Redis作为存储去重基础的容器,但实际上MySQL、MongoDB、内存都可以作为容器。至于他们为什么选择Redis,它比其他数据存储好在哪里?你可以阅读《Python3 网络爬虫宝典》的第3章。3、分布式爬虫,不管是舆情方向的爬虫,还是电商方向的爬虫,都要承担非常大的爬取量。少则每天百万条数据,多则每天数十亿条数据。以往大家熟知的单机爬虫,无论是性能还是资源,都无法满足需求。1个不够,那就10个,100个!这就是分布式爬虫出现的背景。众所周知,分布式系统和单机系统面临的问题是有区别的。除了相同的业务目标,分布式系统还需要考虑多个个体之间的协作,特别是资源的共享和竞争。当只有1个爬虫应用时,只有1个读取待爬队列,只有1个存储数据,只有1个判断url是否重复。但是,当有几十个或上百个爬虫应用时,需要区分先后顺序,避免出现多个爬虫应用访问同一个URL的情况(因为这不仅浪费时间,也浪费资源)。而且,当只有一个爬虫应用的时候,你只需要在一台电脑(服务器)上运行,但是突然有那么多爬虫应用,它们应该如何部署在不同的电脑上呢?手动一张一张上传,然后一张一张开始?资源问题首先来说说资源共享和竞争。为了解决待爬取的URL队列和已经爬取的队列的共享,队列(也就是上面说的存放URL的容器)必须放在公共(多爬虫应用)访问,比如服务器上部署了Redis。这时,一个新的情况出现了。随着数据量的增加,需要存储的URL越来越多,可能会出现存储空间需求过大导致成本增加的问题。因为Redis是用内存来存储数据的,它存储的URL越多,需要的内存就越大,而内存在硬件设备中是比较昂贵的硬件,所以我们不得不考虑这个问题。幸运的是,一个叫布卢姆的人发明了一种算法——布隆过滤器(Bloomfilter),它使用哈希图来标记一个对象(这里是一个URL)是否存在,这样就可以大大降低内存的占用率。根据1亿个长度为32个字符的URL的MD5值计算,使用BloomFilter前后差距约为30倍。BloomFilter的算法原理和代码实现的解读请参考《Python3 网络爬虫宝典》的第三章。部署问题一个一个上传文件,手动一次又一次跑爬虫,真的很累。你可以向你的运维同事寻求技术支持,也可以探索这些可以减少你工作量的自动化部署方式。目前业界比较知名的持续集成和部署是GitLab的GitLabRunner和GitHubAction,也可以借助K8S容器化来实现。但是它们只能帮你部署和启动,爬虫应用的一些管理功能是不能指望的。那么,今天要给大家介绍的是另一种实现方式——使用Crawlab。Crawlab是由国外知名公司的工程师开发的分布式爬虫管理平台。它不仅支持用Python编写的爬虫,还兼容大多数编程语言和应用程序。通过Crawlab,我们可以将爬虫应用分发到不同的电脑(服务器),可以在可视化界面设置定时任务,查看爬虫应用在平台上的状态,环境依赖等信息。具体如下图所示:面对这样一个实用的平台工具,作为工程师的我们不禁要问:它是如何将文件分发到不同的电脑上的?它是如何实现不同计算机(多节点)之间的通信的?它是如何实现多语言兼容的?...其中,我们比较关心的多节点通信是借助Redis实现的,文件的去中心化同步是借助MongoDB实现的。更多详细信息可以在《Python3 网络爬虫宝典》的第6章找到。除了这类平台,Python爬虫工程师还经常接触到Scrapy框架和相关的衍生库。Scrapy团队官方开发了一个名为Scrapyd的库,专门用于部署Scrapy框架开发的爬虫应用。在部署Scrapy应用时,我们通常只需要执行一行命令就可以将爬虫程序部署到服务器上。想知道背后的逻辑吗:程序是以什么形式上传到服务器的?程序如何在服务器上运行?为什么我可以看到每个任务的开始时间和结束时间?中途取消任务执行的功能是如何实现的?它的版本控制是如何实现的?如果不是Scrapy框架编写的Python应用,是否可以实现像上面几点的监控和操作呢?实际上,Scrapy应用程序会被打包成后缀为“.egg”的压缩包,以HTTP的形式上传到服务器。服务器程序需要执行该程序时,先将其复制到操作系统的临时文件夹中,执行时将其导入到当前Python环境中,执行完毕后删除该文件。至于它的执行时间和中断操作,其实是用了Python的进程接口。详情请参考《Python3 网络爬虫宝典》第6章。4、自动渲染技术为了达到炫酷的效果,或者为了节省带宽上的静态资源,很多网站都使用JavaScript来优化页面内容。Python程序本身无法解释JavaScript和HTML代码,因此无法获取我们在浏览器中“看到”的内容,但实际上并不是“真实的”,因为这些内容都是浏览器渲染出来的,只存在在浏览器中,HTML文档中的文本,JavaScript文件中的代码,图片、视频以及那些特效都没有出现在代码中,我们看到的一切都是浏览器的功劳。由于Python获取不到浏览器渲染的内容,所以当我们像往常一样编写代码爬取上面的数据时,会发现获取到的数据和看到的不一样,任务就会失败。这时候就需要用到自动渲染技术了。事实上,像Chrome和FireFox这样的浏览器已经开放了接口,允许其他编程语言按照协议规范来操作浏览器。基于这种技术背景,一些团队开发了像Selenium和Puppeteer这样的工具,然后我们就可以使用Python(其他语言)代码来操作浏览器了。让浏览器帮我们完成用户名密码输入、登录按钮点击、文字图片渲染、验证码滑动等操作,从而打破Python与浏览器本身的差异壁垒,回归本源在浏览器的帮助下呈现内容后的Python程序。然后得到和我们在网页上看到的一样的内容。除了浏览器,APP也有类似情况。具体操作做法和案例详见《Python3 网络爬虫宝典》第二章。5、在之前描述消息队列在爬虫领域的应用中,我们并没有提到爬虫的细节。假设这样一个正常的爬取场景:爬虫首先访问网站的文章列表页,然后根据列表页的URL进入详情页进行爬取。这里需要注意的是,文章详情页数必须是列表页数的N倍。如果列表显示20条内容,则多出20倍。如果我们需要爬取很多网站,那么就会用到分布式爬虫。如果分布式爬虫只是复制一个爬虫程序的N份来运行,那么就会出现资源分配不均衡的情况,因为在上述情况下,每个爬虫都需要做这项工作。其实我们可以有更好的搭配方式来最大限度的利用自己的资源。比如从列表页到详情页可以抽象成一个生产者和消费者模型:4号和5号爬虫应用只负责从列表页中提取详情页的URL,然后进行推送到一个队列,其他几个爬虫从队列中提取详情页的URL进行爬取。当列表页和详情页的数量差距比较大时,我们可以增加右边的爬虫数量,减少右边的爬虫数量(或者增加左边的爬虫数量,具体取决于情况)当差距很小。与队列的“数据采集生产线”相比,左边的爬虫程序是生产者,右边的爬虫程序是消费者。有了这样的结构,我们就可以根据实际情况调整生产者或消费者的熟练程度,以最大限度地利用资源。还有一个好处就是,当生产者拿到的URL越来越多,但是消费者一时消费不过来的时候,这些URL会一直存在队列中,等消费能力增加的时候可以再次达到平衡。有了这样的生产线,我们就不用担心突然涌入的URL,或者突然消耗掉队列中的URL。队列削峰填谷的能力不仅在后端应用中大放异彩,在爬虫中也同样如此。它在应用程序中也起着很大的作用。爬虫(和分布式爬虫)程序访问消息队列的具体实现和细节请参考《Python3 网络爬虫宝典》的第四章。6、各种形式的反爬虫,你要我就不给!网站不会轻易让您抓取网站上的内容。他们往往在网络协议、浏览器特性、编程语言差异、人机差异等方面给爬虫工程师设置障碍,常见的有滑块验证码和拼图验证码。、封IP、查COOKIE、要求登录、设置复杂的加密逻辑、混淆前端代码等等。水来掩护,兵来将挡!爬虫工程师与目标网站工程师的斗智斗勇,精彩纷呈。《Python3 反爬虫原理与绕过实战》这本书涵盖了市面上80%以上的反爬虫方法和爬虫技术,并且对双方使用的技术进行了详细的讲解,让读者可以从中学到很多技术。具体细节可以看书领略科技世界!小结今天学习了日数据量过亿的大规模爬虫实践之路上的关键技术点,包括智能文本抽取、分布式爬虫、爬虫部署调度、去重、自动化渲染。学习并掌握这些技术后,实现日数据过亿的爬虫不成问题。这些经验来自于一线爬虫工程师。同时,这些技术和设计经过了长期工作的验证,可以直接应用到工作中。