作为长期深耕在爬虫行业的程序猿来说,对于设计一个网页爬虫想必很简单,下面就是一些有关网页爬虫设计的一些思路,可以过来看一看。

第一步:简述用例与约束条件

把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

我们将在没有面试官明确说明问题的情况下,自己定义一些用例以及限制条件。

用例

我们把问题限定在仅处理以下用例的范围中。

服务

抓取一系列链接:
生成包含搜索词的网页倒排索引
生成页面的标题和摘要信息
页面标题和摘要都是静态的,它们不会根据搜索词改变

用户

输入搜索词后,可以看到相关的搜索结果列表,列表每一项都包含由网页爬虫生成的页面标题及摘要
只给该用例绘制出概要组件和交互说明,无需讨论细节。

服务
具有高可用性

无需考虑

搜索分析
个性化搜索结果
页面排名

1.2 限制条件与假设

提出假设

搜索流量分布不均
有些搜索词非常热门,有些则非常冷门
只支持匿名用户
用户很快就能看到搜索结果
网页爬虫不应该陷入死循环
当爬虫路径包含环的时候,将会陷入死循环
抓取 10 亿个链接
要定期重新抓取页面以确保新鲜度
平均每周重新抓取一次,网站越热门,那么重新抓取的频率越高
每月抓取 40 亿个链接
每个页面的平均存储大小:500 KB
简单起见,重新抓取的页面算作新页面
每月搜索量 1000 亿次
用更传统的系统来练习 —— 不要使用 solr 、nutch 之类的现成系统。

计算用量

如果你需要进行粗略的用量计算,请向你的面试官说明。

每月存储 2 PB 页面
每月抓取 40 亿个页面,每个页面 500 KB
三年存储 72 PB 页面
每秒 1600 次写请求
每秒 40000 次搜索请求

简便换算指南:

一个月有 250 万秒
每秒 1 个请求,即每月 250 万个请求
每秒 40 个请求,即每月 1 亿个请求
每秒 400 个请求,即每月 10 亿个请求

第二步: 概要设计

列出所有重要组件以规划概要设计。

第三步:设计核心组件

对每一个核心组件进行详细深入的分析。

用例:爬虫服务抓取一系列网页

假设我们有一个初始列表 links_to_crawl(待抓取链接),它最初基于网站整体的知名度来排序。当然如果这个假设不合理,我们可以使用 Yahoo、DMOZ 等知名门户网站作为种子链接来进行扩散 。

我们将用表 crawled_links (已抓取链接 )来记录已经处理过的链接以及相应的页面签名。

我们可以将 links_to_crawl 和 crawled_links 记录在键-值型 NoSQL 数据库中。对于 crawled_links 中已排序的链接,我们可以使用 Redis 的有序集合来维护网页链接的排名。我们应当在 选择 SQL 还是 NoSQL 的问题上,讨论有关使用场景以及利弊 。

爬虫服务按照以下流程循环处理每一个页面链接:

选取排名最靠前的待抓取链接

在 NoSQL 数据库的 crawled_links 中,检查待抓取页面的签名是否与某个已抓取页面的签名相似
若存在,则降低该页面链接的优先级
这样做可以避免陷入死循环
继续(进入下一次循环)
若不存在,则抓取该链接
在倒排索引服务任务队列中,新增一个生成倒排索引任务。
在文档服务任务队列中,新增一个生成静态标题和摘要的任务。
生成页面签名
在 NoSQL 数据库的 links_to_crawl 中删除该链接
在 NoSQL 数据库的 crawled_links 中插入该链接以及页面签名

向面试官了解你需要写多少代码。

PagesDataStore 是爬虫服务中的一个抽象类,它使用 NoSQL 数据库进行存储。

class PagesDataStore(object):def __init__(self, db);self.db = db...def add_link_to_crawl(self, url):"""将指定链接加入 `links_to_crawl`。"""...def remove_link_to_crawl(self, url):"""从 `links_to_crawl` 中删除指定链接。"""...def reduce_priority_link_to_crawl(self, url)"""在 `links_to_crawl` 中降低一个链接的优先级以避免死循环。"""...def extract_max_priority_page(self):"""返回 `links_to_crawl` 中优先级最高的链接。"""...def insert_crawled_link(self, url, signature):"""将指定链接加入 `crawled_links`。"""...def crawled_similar(self, signature):"""判断待抓取页面的签名是否与某个已抓取页面的签名相似。"""...

Page 是爬虫服务的一个抽象类,它封装了网页对象,由页面链接、页面内容、子链接和页面签名构成。

class Page(object):def __init__(self, url, contents, child_urls, signature):self.url = urlself.contents = contentsself.child_urls = child_urlsself.signature = signature

Crawler 是爬虫服务的主类,由Page 和 PagesDataStore 组成。

class Crawler(object):def __init__(self, data_store, reverse_index_queue, doc_index_queue):self.data_store = data_storeself.reverse_index_queue = reverse_index_queueself.doc_index_queue = doc_index_queuedef create_signature(self, page):"""基于页面链接与内容生成签名。"""...def crawl_page(self, page):for url in page.child_urls:self.data_store.add_link_to_crawl(url)page.signature = self.create_signature(page)self.data_store.remove_link_to_crawl(page.url)self.data_store.insert_crawled_link(page.url, page.signature)def crawl(self):while True:page = self.data_store.extract_max_priority_page()if page is None:breakif self.data_store.crawled_similar(page.signature):self.data_store.reduce_priority_link_to_crawl(page.url)else:self.crawl_page(page)

处理重复内容

我们要谨防网页爬虫陷入死循环,这通常会发生在爬虫路径中存在环的情况。

向面试官了解你需要写多少代码。

删除重复链接:

假设数据量较小,我们可以用类似于 sort | unique 的方法。(译注: 先排序,后去重)
假设有 10 亿条数据,我们应该使用 MapReduce 来输出只出现 1 次的记录。

class RemoveDuplicateUrls(MRJob):def mapper(self, _, line):yield line, 1def reducer(self, key, values):total = sum(values)if total == 1:yield key, total

比起处理重复内容,检测重复内容更为复杂。我们可以基于网页内容生成签名,然后对比两者签名的相似度。可能会用到的算法有 Jaccard index 以及 cosine similarity。

抓取结果更新策略

要定期重新抓取页面以确保新鲜度。抓取结果应该有个 timestamp 字段记录上一次页面抓取时间。每隔一段时间,比如说 1 周,所有页面都需要更新一次。对于热门网站或是内容频繁更新的网站,爬虫抓取间隔可以缩短。

尽管我们不会深入网页数据分析的细节,我们仍然要做一些数据挖掘工作来确定一个页面的平均更新时间,并且根据相关的统计数据来决定爬虫的重新抓取频率。

当然我们也应该根据站长提供的 Robots.txt 来控制爬虫的抓取频率。

用例:用户输入搜索词后,可以看到相关的搜索结果列表,列表每一项都包含由网页爬虫生成的页面标题及摘要

1、客户端向运行反向代理的 Web 服务器发送一个请求
2、Web 服务器 发送请求到 Query API 服务器
3、查询 API 服务将会做这些事情:

解析查询参数
删除 HTML 标记
将文本分割成词组 (译注: 分词处理)
修正错别字
规范化大小写
将搜索词转换为布尔运算

使用倒排索引服务来查找匹配查询的文档

倒排索引服务对匹配到的结果进行排名,然后返回最符合的结果

使用文档服务返回文章标题与摘要

我们使用 REST API 与客户端通信:

$ curl https://search.com/api/v1/search?query=hello+world

响应内容:

{"title": "foo's title","snippet": "foo's snippet","link": "https://foo.com",
},
{"title": "bar's title","snippet": "bar's snippet","link": "https://bar.com",
},
{"title": "baz's title","snippet": "baz's snippet","link": "https://baz.com",
},

对于服务器内部通信,我们可以使用 远程过程调用协议(RPC)

第四步:架构扩展

根据限制条件,找到并解决瓶颈。

重要提示:不要直接从最初设计跳到最终设计!

现在你要 1) 基准测试、负载测试。2) 分析、描述性能瓶颈。3) 在解决瓶颈问题的同时,评估替代方案、权衡利弊。4) 重复以上步骤。请阅读设计一个系统,并将其扩大到为数以百万计的 AWS 用户服务 来了解如何逐步扩大初始设计。

讨论初始设计可能遇到的瓶颈及相关解决方案是很重要的。例如加上一套配备多台 Web 服务器的负载均衡器是否能够解决问题?CDN呢?主从复制呢?它们各自的替代方案和需要权衡的利弊又有哪些呢?

我们将会介绍一些组件来完成设计,并解决架构规模扩张问题。内置的负载均衡器将不做讨论以节省篇幅。

为了避免重复讨论,请参考系统设计主题索引相关部分来了解其要点、方案的权衡取舍以及替代方案。

DNS
负载均衡器
水平扩展
Web 服务器(反向代理)
API 服务器(应用层)
缓存
NoSQL
一致性模式
可用性模式

有些搜索词非常热门,有些则非常冷门。热门的搜索词可以通过诸如 Redis 或者 Memcached 之类的内存缓存来缩短响应时间,避免倒排索引服务以及文档服务过载。内存缓存同样适用于流量分布不均匀以及流量短时高峰问题。从内存中读取 1 MB 连续数据大约需要 250 微秒,而从 SSD 读取同样大小的数据要花费 4 倍的时间,从机械硬盘读取需要花费 80 倍以上的时间。1

以下是优化爬虫服务的其他建议:

为了处理数据大小问题以及网络请求负载,倒排索引服务和文档服务可能需要大量应用数据分片和数据复制。
DNS 查询可能会成为瓶颈,爬虫服务最好专门维护一套定期更新的 DNS 查询服务。
借助于连接池,即同时维持多个开放网络连接,可以提升爬虫服务的性能并减少内存使用量。
改用 UDP 协议同样可以提升性能
网络爬虫受带宽影响较大,请确保带宽足够维持高吞吐量。

其它要点

是否深入这些额外的主题,取决于你的问题范围和剩下的时间。

如何设计一个网页爬虫相关推荐

  1. 设计 一个高性能爬虫系统

    资料来源 http://www.xuebuyuan.com/1296711.html 开源中国 http://my.oschina.net/eshijia/blog/136595 最近看了一篇来自纽约 ...

  2. dw网页设计期末设计一个网页_Dreamweaver网页设计模拟试题

    <网页设计与制作-- Dreamweaver8 >期末模拟试题一 一.选择题 1 .打开 Dreamweaver 8 窗口后,如果没有出现属性面板.可执行 _______ 菜单中的 &qu ...

  3. dw网页设计期末设计一个网页_Dreamweaver网页设计模拟试题一及答案

    Dreamweaver网页设计模拟试题一及答案,帮助你更好的学习网页设计 版权所有-中职教学资源网 <网页设计与制作--Dreamweaver8>期末模拟试题一 一.选择题 1.打开Dre ...

  4. 设计一个网络爬虫(Python)

    第 1 步:概述用例和约束 收集需求并确定问题的范围.提出问题以澄清用例和约束.讨论假设. 如果没有面试官来解决澄清问题,我们将定义一些用例和约束. 用例 我们将问题范围限定为仅处理以下用例 服务抓取 ...

  5. dw网页设计期末设计一个网页_制作网站与设计网页可以用什么软件?

    网站制作确实是项技术活,要不然怎么一个前端设计师工资都可以到6-7K呢,早在读书时代稍有爱好网页设计时就听说过网页三剑客. 网页三剑客 网页三剑客,是一套强大的网页编辑工具,最初是由Macromedi ...

  6. python urllib dns 缓存_新手用Python做一个网页爬虫

    咱们好哈,最近博主在学习Python,学习时期也遇到一些问题,获得了一些经历,在此将自个的学习体系地整理下来,假如咱们有爱好学习爬虫的话,能够将这些文章作为参阅,也期待咱们总共同享学习经历. 首要py ...

  7. dw网页设计期末设计一个网页_Dreamweaver网页设计期末模拟试题(1)

    山东广播电视大学 开放教育Dreamweaver网页设计期末模拟试题 (1) 一.单项选择题 1.下图为Dreamweaver 8的新建文档页面,一般情况下,创建完全空白的静态页面应选择(). A. ...

  8. html设计一个网页表格,21个新奇古怪的网页表格设计

    当谈到表格数据的设计时,没有太多的网页设计师会有太大的兴趣.在此我们已经收集了20多个功能超大且看上去挺漂亮的Ajax/CSS表格设计,并且教你一些表格设计中所运用的技巧,例如表格数据的排序和过滤等. ...

  9. dw网页设计期末设计一个网页_《网页设计与制作Dreamweaver》期末考试试题

    <网页设计与制作Dreamweaver>期末考试试题 1<网页设计与制作>期末考试试题一.单项选择题(每个题只有一个的答案是正确的.每题 3 分,共 60 分)1.目前在 In ...

最新文章

  1. 第十三届蓝桥杯Java_C组题目
  2. jieba.cut与jieba.lcut的区别
  3. 终于在VirtualBox中装好了Mac OS的虚拟机了!(
  4. Eclipse中的,ER图生成工具:【ERMaster】
  5. ip模拟工具modify headers
  6. PyQt5中打开网址方法
  7. DBeaver打开sql文件中文乱码问题解决
  8. 域名泛解析,二级域名转向问题- -完美解决
  9. react 下载 excel 文件
  10. 高斯列主元消去法解线性方程组
  11. 中国医用显示器械市场现状调查与投资前景预测报告2022-2028年
  12. RK3568平台开发系列讲解(USB篇)libusb流程简介
  13. 电脑打开播放器提示服务器运行失败,电脑中打开WMP播放器提示服务器运行失败如何解决...
  14. 上海财经应用统计考python_上海财经大学应用统计专硕考研经验帖
  15. ES6 数组转为对象 ,以及 find 在数组里面找到对应一条数据
  16. 荣耀play4t能升级鸿蒙吗,荣耀30 Pro已开始测试华为鸿蒙HarmonyOS 2.0 荣耀Play4 Pro下月升级...
  17. Lotus Notes 邮件归档设置
  18. 基于以太坊的拍卖系统-合约编写(一)
  19. linux下添加中文包,LINUX下中文语言包的安装
  20. terminate called after throwing an instance of ‘std::runtime_error‘

热门文章

  1. 正则(?=)(?:)
  2. allegro中design size无法修改
  3. ES 查询一,基于URL 的查询
  4. C/C++植物大战僵尸之CE找基址+修改器制作(基础版)
  5. jquery点击图片进行放大缩小
  6. 洪柱森老师介绍--沪师经纪-刘建
  7. 淘宝长辈模式技术实践万字总结
  8. WEB应用开发设计实验报告四
  9. word之表格如何自动换页?
  10. Ng深度学习笔记-卷积神经网络-目标检测