设计一个网页爬虫

定义 User Case 和 约束

注意:没有一个面试官会阐述清楚问题,我们需要定义Use case和约束

Use cases

我们的作用域只是处理以下Use Case:

  1. Service 爬取一批 url
  • 生成包含搜索词的单词到页面的反向索引
  • 给页面生成标题和片段
  • – 标题和片段是静态的,他们不会基于搜索语句改变
  1. User 输入一个搜索词然后看到相关页面的List, 伴随着爬虫生成的 title 和 snippet
  • 只有描绘出High Level的组件和User Case的交互,不需要去深入
  1. Service有高可用

作用域外:

  1. 搜索分析
  2. 个人化的搜索结果
  3. 页面排名

约束和假设

状态假设:

  1. 流量分布不均匀
  • 一些搜索访问非常频繁,当其他搜索都只是执行一次
  1. 只是支持匿名用户
  2. 生成搜索结果应该是很快的
  3. 这个 Web 爬虫不应该被阻塞在无限循环
  • 如果这个图包含一个周期,我们将被阻塞在无限循环
  1. 10 亿link会被爬
  • 页面需要被规律的爬去确保刷新
  • 平均的刷新率应该是一次一周,热门网站应该更频繁
  • – 每个月会爬4 亿 link
  • 平均每个网页存储尺寸是:500 kb
  • – 为了简化,计数和新页面相同
  1. 每个月1000 亿搜索

使用更传统的系统进行练习 - 不要使用现存的系统比如 solr 或者 nutch

计算使用量

和你的面试官说清楚你权衡之后选择的最优的方案

  1. 每个月 2 PB 的存储页面内容
  • 500 KB 每页 * 40 亿 link / month
  • 3年内存储 72 PB页面内容
  1. 1600 写请求 / s
  2. 40000 搜索请求 / s

便利的转换指南

  • 每月有 250 万秒
  • 1 请求 / 秒 = 250 万请求 / 月
  • 40 请求 / 秒 = 一亿请求 / 月
  • 400 请求 / 秒 = 十亿 请求 / 月

创建一个 High Level 设计

Component Design

设计核心组件

Service 爬取 url 的 list

我们假设我们有一个初始化list links_to_crawl 基于整体站点流行度排序初始化,如果这不是一个合理的假设的话,我们可以搜索这个爬虫伴随着流行度网站。link到外面的内容,比如 Yahoo, DMOZ等

我们使用一个表 crawled_links 去存储处理过的link和他们的页面签名.
我们可以存储 links_to_crawlcrawled_links 在一个 key-value NoSQL Database. 对于排名的link 我们存进 links_to_crawl, 我们可以使用 Redis 伴随着 sorted set去维护一个页面link的排名。我们应该讨论不同 use case之间的最优解。

  • Crawler Service 通过循环处理每个页面的link:
    • 获取排名第一的page link给爬虫
      • 检查在NoSQL数据库中 crawled_links for 一个有相同页面签名的 entry
        • If 我们有一个相同的 page,减少页面link的优先级
          • 这将防止我们进入循环
          • 继续
        • Else 爬取这个 link
          • 添加一个job到 Reverse Index Service的队列去生成一个 reverse index
          • 添加一个 job 到 Document Service 队列去生成一个静态Title和代码片段
          • 生成一个页面签名
          • 从 links_to_crawl 移除 link 进 NoSQL Database
          • 插入页面link和签名到 crawled_link 进 NoSQL Database

PageDataStore 是一个抽象伴随着 Crawler Service,并且使用 NoSQL 数据库

class PagesDataStore(object):def __init__(self, db);self.db = db...def add_link_to_crawl(self, url):"""Add the given link to `links_to_crawl`."""...def remove_link_to_crawl(self, url):"""Remove the given link from `links_to_crawl`."""...def reduce_priority_link_to_crawl(self, url)"""Reduce the priority of a link in `links_to_crawl` to avoid cycles."""...def extract_max_priority_page(self):"""Return the highest priority link in `links_to_crawl`."""...def insert_crawled_link(self, url, signature):"""Add the given link to `crawled_links`."""...def crawled_similar(self, signature):"""Determine if we've already crawled a page matching the given signature"""...

Page 是一个抽象伴随着 crawler service, 用来疯涨一个 Page, 他的内容, child urls,和签名

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

Crawler 是Crawler Service中的主类, 聚合 PagePagesDataStore

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):"""Create signature based on url and contents."""...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)

处理重复Link

我们需要小心这个Web爬虫不会被阻塞在一个无限循环里面,这种情况发生在graph包含一个Cycle.

我们需要去移除重复的 urls:

  1. 对于稍小的 list 我们可以使用 sort | unique
  2. 当有十亿 link需要爬时,我们可以使用 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

决定什么时候去更新爬虫的结果

Pages 需要被常规的爬取用以刷新,爬取结果将有一个 timestamp 字段,用来指示这个pgae上一次被爬取的时间,在默认时间段,S一周所有的page会被刷新,频繁的更新或者更流行的网站会被刷新在更短的周期。

尽管我们不会深入分析细节,我们可以做一些数据修剪用来决定在特定页被更新的时间,而且使用 statistic 来决定重新爬取页面的频率

User Case: 用户输入一个搜索Term并且看到一个相关页面(包括title和片段)的list
  1. Client 发送一个请求到 Web Server
  2. Web Server 转发请求到 Query API server
  3. Query API server 做下面的事
    • 解析 Query
      • 移除 markup
      • 分解 text 进 term
      • 修复 typos
      • 格式化首字母
      • 转换 Query 去使用 bool 操作
    • 使用 Reverse Index Service 去寻找匹配 query 的文档
      • Reverse Index Service 排序匹配的结果,然后返回Top的记录
    • 使用 Document Service 去返回 titles 和 文档片段

我们可以使用 public REST API:

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

Response:

{"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",
},

扩展设计

在限制条件下,识别并解决瓶颈问题。

针对 Crawler Service目前发现这些优化点:

  1. 为了处理 data size 和 request load, Reverse Index Service 和 Document Service 将很有可能使用 Shadring 和 federation.
  2. DNS 查询会是一个 bottleneck, Crawler Service 会保持它自己的 DNS 查询,而且周期性刷新
  3. Crawler Service会提高性能并且减少内存使用(通过保持大量开放连接的方法),可以考虑切换到 UDP
  4. 网络爬虫是带宽密集型的,确保有足够的带宽来维持高吞吐量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/412799.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 安装 MongoDb4

Docker 安装mongoDb 获取mongodb安装参考 获取mongodb 注意: WARNING: MongoDB 5.0 requires a CPU with AVX support, and your current system does not appear to have that! **hub官网(需要梯子):**https://hub.docker.com/_…

sc.pl.umap 画feature plot

今天有时间尝试测试了这个scanpy的feature plot,其实很简单,就是使用 sc.pl.umap(adata,color"gene name"), 但是这个地方就有一个问题,这个画出来的值是原始的基因值还是scale之后的,这个我得搞清楚 首先看使用例子,参…

【高并发内存池】定长内存池实现

目录 一、项目介绍 二、内存池介绍 2.1、池化技术 2.2、内存池 2.3、内存池主要解决的问题 三、malloc了解 四、设计定长内存池 五、和new(实际malloc)对比性能测试 一、项目介绍 当前项目实现的高并发内存池原型是goole的开源项目tcmalloc,tcmalloc全称为T…

Docker-02-镜像项目部署

Docker-02-镜像&项目部署 文章目录 Docker-02-镜像&项目部署一、镜像①:镜像结构②:Dockerfile③:构建镜像01:构建02:查看镜像列表03:运行镜像 二、网络①:容器的网络IP地址②&#xff…

SQL性能分析

SQL性能分析 1、SQL执行频率 ​ MySQL 客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信 息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次: -- session 是查看当前会话 ; …

oracle11g的闪回技术-闪回表-时间戳

--数据库闪回表 --1创建表(登录模式system) CREATE table dept2 as select * from dept;--此语句如果加上where条件可用于工作中数据的临时备份 select * from dept2;--查询新建表信息 --进入sql>set time on 通过时间点闪回 记录弹出的时间点&#…

flutter 五点一:MaterialApp Theme

ThemeData factory ThemeData({bool? applyElevationOverlayColor, //material2的darkTheme下 增加一个半透明遮罩 来凸显阴影效果 material3下无效 貌似没啥用NoDefaultCupertinoThemeData? cupertinoOverrideTheme, //ios组件样式 Iterable<ThemeExtension<dyn…

zabbix客户端配置及自定义监控

部署zabbix客户机 1.服务端和客户端都配置时间同步 yum install -y ntpdate ntpdate -u ntp.aliyun.com 2.服务端和客户端都设置 hosts 解析 cat > /etc/hosts << EOF 172.16.23.16 localhost 172.16.23.17 zbx-server EOF 3.被监控端 //设置 zabbix 的下载源&…

MySQL深度分页优化问题

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

广告投放场景中ABtest分析的评价、优化和决策建议

目录 写在开头1. AB测试基础知识1.1 AB测试概述1.2 原理和流程1.3 广告领域中的AB测试应用 2. 评价广告投放中的AB测试2.1 关键指标选择与解释2.2 统计学方法应用 3. AB测试分析中的常见问题与解决方案3.1 样本偏差3.2 季节性影响3.3 测试时长选择3.4 结果误解与分析失误 4. 优…

老师布置作业的技巧有哪些

布置作业可不只是简单地给学生分配任务&#xff0c;而是需要运用一些技巧&#xff0c;以达到更好的教学效果。那么&#xff0c;老师应该如何布置作业呢&#xff1f; 一、作业要有针对性 布置作业时&#xff0c;老师应该根据学生的实际情况和课程要求&#xff0c;有针对性地设…

tinyxml2

使用tinyxml2&#xff0c;得知道一些xml基础 xml tutorial--菜鸟 tinyxml2类对象 链接 结构 XMLNode 什么是节点 节点&#xff1a;元素、声明、文本、注释等。 XMLDocument xml文档(文件)对象。 作用&#xff1a; 加载xml文件&#xff0c; tinyxml2作用 先定义两个宏 …