時間:2023-09-18 11:06:01 | 來源:網(wǎng)站運營
時間:2023-09-18 11:06:01 來源:網(wǎng)站運營
系統(tǒng)設(shè)計面試之網(wǎng)頁爬蟲:本文翻譯自GitHub上有關(guān)系統(tǒng)設(shè)計的repo:system design primer里面關(guān)于面試系統(tǒng)設(shè)計之網(wǎng)頁爬蟲,6w+的star。Note: 為了避免重復,當前文檔直接鏈接到系統(tǒng)設(shè)計主題的相關(guān)區(qū)域,請參考鏈接內(nèi)容以獲得綜合的討論點、權(quán)衡和替代方案。
收集這個問題的需求和范疇。 問相關(guān)問題來明確用例和約束。 討論一些假設(shè)。因為沒有面試官來明確這些問題,所以我們自己將定義一些用例和約束。
概述一個包括所有重要的組件的高層次設(shè)計
深入每一個核心組件的細節(jié)
links_to_crawl
列表。 如果這不是一個合理的假設(shè),我們可以使用鏈接到外部內(nèi)容(如 Yahoo,DMOZ 等)的熱門網(wǎng)站為爬蟲播種。crawled_links
來存儲已處理的鏈接及其頁面簽名。links_to_crawl
和 crawled_links
存儲在鍵值 NoSQL Database 中。 對于 links_to_crawl
中的排名鏈接,我們可以使用 Redis 和排序集來維護頁面鏈接的排名。我們應該討論選擇 SQL 或 NoSQL 之間的用例和權(quán)衡。crawled_links
以獲取具有類似頁簽名的條目links_to_crawl
刪除crawled_links
PagesDataStore
是爬蟲服務中使用 NoSQL Database 的抽象: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
是爬蟲服務中的一個抽象,它封裝了一個頁面,以及它的內(nèi)容,子URL和簽名: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
是爬蟲服務中的主要類,由 Page
和 PagesDataStore
組成。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)
sort | unique
class RemoveDuplicateUrls(MRJob): def mapper(self, _, line): yield line, 1 def reducer(self, key, values): total = sum(values) if total == 1: yield key, total
檢測重復內(nèi)容更復雜。 我們可以根據(jù)頁面內(nèi)容生成簽名,并比較這兩個簽名的相似性。 一些潛在的算法是 雅克卡指數(shù) 和余弦相似度。timestamp
字段,表示爬取頁面的最后時間。 在默認時間段(例如一周)之后,應刷新所有頁面。 經(jīng)常更新或更受歡迎的網(wǎng)站可以在較短的時間間隔內(nèi)刷新。Robots.txt
文件,該文件可讓網(wǎng)站管理員控制爬取頻率。$ 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",},
用于內(nèi)部通信,我們可以用 RPC。基于給定的約束條件,確定并解決瓶頸問題。重要提示: 不要簡單的從最初的設(shè)計直接跳到最終的設(shè)計
是否更深入探討額外主題,取決于問題的范圍和面試剩余的時間。
關(guān)鍵詞:爬蟲,設(shè)計,系統(tǒng)
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。