设计一个网页爬虫

news2024/9/24 18:09:15

定义 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 = url
		self.contents = contents
		self.child_urls = child_urls
		self.signature = signature

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

class Crawler(object):
	def __init__(self, data_store, reverse_index_queue, doc_index_queue):
        self.data_store = data_store
        self.reverse_index_queue = reverse_index_queue
        self.doc_index_queue = doc_index_queue

    def 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:
                break
            if 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, 1

    def 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.coloradmin.cn/o/1397315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ptrade 通过mysql的链接开发一个量化管理平台。

这里只写一下界面及想法。不进行代码的实现。因为对流程不是很熟 ###界面 数据库的链接: ptrade USER 可转债量化分析 PASSWORD 123456 MYSQL_HOST mysql.sqlpub.com MYSQL_PORT 3306 MYSQL_DB ptradedef get_mysql_conn():import pymysqltry:conn pym…

maven编译时依赖报错 Caused by: java.util.zip.ZipException: zip file is empty 错误。

出现这种报错时,可能是maven仓库下对应的依赖出现了问题,需要讲报错依赖位置的依赖进行删除,在编译的时候就会重新下载,就不会出现错误了。 rm -rf /Applications/software/env/repository/org/apache/orc/orc-core/1.9.1/

Yield Guild Games 宣布与区块链游戏中心 Iskra 建立战略合作伙伴关系

Yield Guild Games (YGG) 宣布将向 Iskra 引入其任务系统,Iskra 是一个 Web3 游戏中心和发布平台,拥有超过 400 万注册钱包和 10 万月度活跃用户 (MAU)。在 LINE、Kakao、Wemade 和 Netmarble 等公司的支持下,Iskra 将游戏玩家和游戏工作室聚…

验收测试的重要性:确保交付高质量产品

在软件开发生命周期中,验收测试扮演着至关重要的角色,它不仅是项目的最后一道关卡,更是确保交付高质量产品的关键步骤。本文将介绍验收测试的重要性,以及它在软件开发过程中的作用。 1. 确认功能符合需求 验收测试的首要任务是验证…

逆向思维,去重Cube计算优化新技巧

场景描述 在做数据汇总计算和统计分析时,最头疼的就是去重类指标计算(比如用户数、商家数等),尤其还要带多种维度的下钻分析,由于其不可累加的特性,几乎每换一种统计维度组合,都得重新计算。数…

匿名发送短信

匿名发送短信 匿名发送短信啦!不用程序猿,也能定制专属推送消息!每日小惊喜! 还可以领取课程资料!软考中级软件设计师,高级信息系统项目管理师! 先说在哪里 微信搜公众号:暮看云 微…

人工智能 | 自然语言处理的发展历程

github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 自然语言处理的发展 方向一:技术进步1. 基于规则的语法(1950-1990)2. 统计语言处理(1990-2010)3. 基于深度学…

ChatGPT正确打开方式与GPT-4.5的key最新获取方式

前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家:https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言4.5key价格泄漏ChatGPT4.0使用地址ChatGPT正确打开方式最新功能语音助手存档…

计算机网络-标准化工作及相关组织与性能指标(标准分类 标准化工作 RFC 速率 带宽 吞吐量 时延 时延带宽积 RTT 利用率)

文章目录 标准化工作及相关组织标准化工作标准分类RFC流程标准化的相关组织小结 性能指标速率带宽吞吐量时延发送时延传播时延排队时延与处理时延补充 高速链路 时延带宽积往返时间RTT利用率小结 标准化工作及相关组织 标准化工作 即需要统一标准,这样才能兼容 …

Linux 时间同步 - Chrony服务

Linux 时间同步 - Chrony服务 引言一、简单使用二、详解2.1 chrony.conf2.2 chronyd2.3 chronyc 引言 为什么需要时间同步? 其意义可参考秦朝统一度量衡,车同轨,书同文。核心就是方便协同工作。 Chrony能更精确、更快的同步时钟,传统ntp需要…

014集:python访问互联网:网络爬虫实例—python基础入门实例

以pycharm环境为例: 首先需要安装各种库(urllib:requests:Openssl-python等) python爬虫中需要用到的库,大致可分为:1、实现 HTTP 请求操作的请求库;2、从网页中提取信息的解析库;3、Python与…

代码随想录算法训练营day13|239.滑动窗口最大值、347.前K个高频元素

239. 滑动窗口最大值 347.前 K 个高频元素 239. 滑动窗口最大值 (一刷至少需要理解思路) 之前讲的都是栈的应用,这次该是队列的应用了。 本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解。 题目链接/文…

css3轮播图案例

轮播图案例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>…

HTML111111111

在线编辑器 在线 HTML 空元素 没有内容的 HTML 元素被称为空元素。空元素是在开始标签中关闭的。 即使 在所有浏览器中都是有效的&#xff0c;但使用 其实是更长远的保障。 HTML 水平线 标签在 HTML 页面中创建水平线。 hr 元素可用于分隔内容。 HTML 折行 如果您希望…

mysql原理--事务的隔离级别与 MVCC

1.事前准备 为了故事的顺利发展&#xff0c;我们需要创建一个表&#xff1a; CREATE TABLE hero (number INT,name VARCHAR(100),country varchar(100),PRIMARY KEY (number) ) EngineInnoDB CHARSETutf8;然后向这个表里插入一条数据&#xff1a;INSERT INTO hero VALUES(1, 刘…

高效火情监测,科技助力森林防火【数字地球开放平台】

数字地球开放平台-以卫星遥感为核心的空天信息服务开放平台 (geovisearth.com) 2019年3月30日&#xff0c;四川省凉山州木里县爆发了一场森林火灾&#xff0c;火点位于海拔3800米左右&#xff0c;地形险峻、坡度陡峭、谷深难以抵挡火势。在扑救的过程中&#xff0c;27名森林消防…

扩散模型参数量降低87%,且提升生成质量;通过蒸馏实现一步采样扩散模型;VideoCrafter2视频生成;深度感知图像合成

本文首发于公众号&#xff1a;机器感知 扩散模型参数量降低87%&#xff0c;且提升生成质量&#xff1b;通过蒸馏实现一步采样扩散模型&#xff1b;VideoCrafter2视频生成&#xff1b;深度感知图像合成 One-Step Diffusion Distillation via Deep Equilibrium Models Diffusio…

恭贺丰果管道入围2024中国管道十大品牌

恭贺丰果管道入围2024中国管道十大品牌 丰果&#xff08;中国&#xff09;有限公司 丰果管道品牌创立于1999年&#xff0c;是国内最早从事PPR家装管道生产的品牌之一&#xff0c;在业内有着良好的口碑和市场美誉度&#xff0c;在全国的头部装企更是有相当高的市场占有率。2023…

java数据结构与算法刷题-----LeetCode209. 长度最小的子数组

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 代码:时间复杂度O(n).空间复杂度O(1) class Solution {public in…

MyBatisPlus学习笔记二

接上&#xff1a;MyBatisPlus学习笔记一&#xff1a; MyBatisPlus学习笔记一-CSDN博客 1、条件构造器 MyBatisPlus支持各种复杂的where条件&#xff0c;可以满足日常开发的所有需求。 1.1、集成体系 1.2、实例 查询 lambda查询 更新 1.3、总结 2、自定义sql 我们可以利用MyB…