基于Python(Django)+MongoDB实现的(Web)新闻采集和订阅系统【100010319】
本科生畢業論文(設計)
基于網絡爬蟲的新聞采集和訂閱系統的設計與實現
[摘 要] 隨著互聯網的迅速發展,互聯網大大提升了信息的產生和傳播速度,網絡上每天都會產生大量的內容,如何高效地從這些雜亂無章的內容中發現并采集所需的信息顯得越來越重 要。網絡中的新聞內容也一樣,新聞分布在不同的網站上,而且存在重復的內容,我們往往只 關心其中的一部分新聞,網絡中的新聞頁面往往還充斥著大量許多與新聞不相關的信息,影響 了我們的閱讀效率和閱讀體驗,如何更加方便及時并高效地獲取我們所關心的新聞內容,本系 統能夠幫我們做到這一點。本系統利用網絡爬蟲我們可以做到對網絡上的新聞網站進行定時定 向的分析和采集,然后把采集到的數據進行去重,分類等操作后存入數據庫,最后提供個性化 的新聞訂閱服務。考慮了如何應對網站的反爬蟲策略,避免被網站封鎖爬蟲。在具體實現上會 使用 Python 配合 scrapy 等框架來編寫爬蟲,采用特定的內容抽取算法來提取目標數據,最后使用 Django 加上 weui 來提供新聞訂閱后臺和新聞內容展示頁,使用微信向用戶推送信息。用戶可以通過本系統訂閱指定關鍵字,當爬蟲系統爬取到了含有指定關鍵字的內容時會把新聞推 送給用戶。
[關鍵詞] 網絡爬蟲;新聞;個性化;訂閱;Python
1. 引言
1.2 項目的背景和意義
如今我們所處的時代是一個信息時代,信息處處影響著人們的生活,無論是個人還是企業,都希望能夠獲取自己所關心的內容。人們獲取信息的方式漸漸從傳統的紙質閱讀轉移到了信息傳播速度更快互聯網的在線閱讀上,而許多媒體和互聯網企業都推出了各自的新聞門戶來提供新聞內容閱讀和檢索等功能,但是這些新聞信息仍需要我們主動去訪問這些網站才能獲取到,而且我們還要在這些新聞中篩選出自己所關心的內容進行閱讀,這樣浪費了我們許多閱讀之外的時間。網絡中的新聞分布在不同的網站上,我們往往只關心其中的一部分新聞,網絡中的新聞頁面往往還充斥著大量許多與新聞不相關的信息,影響了我們的閱讀效率和閱讀體驗,如何更加方便及時并高效地獲取我們所關心的新聞內容,這是一個急需解決的問題,本系統就是為了解決這樣的痛點而產生的。
1.3 研究開發現狀分析
個性化新聞服務現狀
如今國內外存在眾多提供個性化新聞服務的互聯網公司,如著名的 ZAKER 和今日頭條,這些公司的產品都能夠根據你的興趣愛好來展示和推薦你喜歡的內容,這種創新性已經顛覆了傳統的新聞資訊平臺的市場格局,大眾紛紛表現出對這些個性化新聞平臺的追捧。據最新的《中國互聯網絡發展狀況統計報告》顯示, 截至 2016 年 12 月,中國網民規模達 7.31 億,移動互聯網用戶規模達到 6.95 億,其中新聞資訊領域行業用戶規模達到 6.14 億,年增長率為 8.8%,在移動端滲透率達到 82.2%。[1]新聞資訊信息的用戶需求也更加細分,用戶對內容的需求也更加精細,除了方便閱讀、時效性高、趣味性強外,個性化推薦方式也 越來越受到用戶的關注。在獵豹全球智庫發布的安卓 2016 年 1 月新聞類 APP 排行榜
中,作為個性化新聞平臺的今日頭條、一點資訊皆排在移動資訊 APP 的前三位。而前三中采用傳統編輯推薦方式的只有騰訊新聞,可見如今個性化新聞平臺已經成為絕對的主流。
網絡爬蟲研究現狀
網頁抓取工具是一種根據特定規則來自動獲取互聯網信息的腳本或程序。[2] 網頁或搜索引擎等網站通過爬蟲軟件來更新自己的網站內容或者是更新對其他網站的索引。一般來說,網絡爬蟲會保留被抓取的頁面,然后用戶可以通過搜索引擎后來生成的索引進行搜索。因為爬蟲訪問網頁的方式與人類相似,而且一般比人類訪問的速度要快,會消耗訪問的網站的系統資源。因此爬蟲在需要大量訪問頁面時,要考慮到規劃和負載等情況,否則容易被網站禁封。 網站站長可以使用 robots.txt 文件來告訴爬蟲訪問的規則。robots.txt 文件是一個具有指定格式的文件,網站站長可以通過此文件來要求爬蟲機器人不能訪問某些目錄或者只能訪問某些目錄。互聯網上的頁面極多,而且數量一直在增長,即使是像谷歌這樣的爬蟲系統也無法做出完整的索引,因此在某些地方會根據需求來做一些主題化的爬蟲,這樣的爬蟲爬到的結果往往能夠更加精確。
項目的范圍和預期結果
本文描述了基于網絡爬蟲的新聞訂閱系統的設計與實現的過程,主要工作如下:
- 編寫一個網絡爬蟲,使其能夠對網絡中指定站點的新聞進行自動收集并存入數據庫;
- 數據的去重和網絡爬蟲的反爬蟲策略應對;
- 提供一個新聞展示頁面,把爬取到的新聞展示給用戶;
- 提供新聞訂閱頁面,用戶可以在頁面輸入指定訂閱的關鍵詞;
- 編寫微信推送服務,把用戶訂閱的新聞通過微信推送給用戶;
1.4 論文結構簡介
本論文的結構安排如下:
- 第一章,引言。主要介紹了論文選題項目的背景、意義和目的;以及對相關領域中已有的研究成果和國內外研究現狀的簡要評述;介紹本系統涉及的范圍和預期結果等。
- 第二章,技術與原理。主要介紹本系統中所用到的主要技術和理論。
- 第三章,系統需求分析。使用用例析取和用例規約等系統分析方法對本系統進行了需求分析。
- 第四章,新聞采集與訂閱系統的設計。介紹了系統的架構與原理,講述本系統的各大模塊的設計以及數據庫的設計詳情。
- 第五章,新聞采集與訂閱系統的實現。介紹本系統具體的實現過程以及實現的效果。
- 第六章,系統部署。介紹本系統的部署環境與部署方法。
- 第七章,總結與展望。對本系統所做的工作進行總結,提出了需要討論的問題和一些本系統中可以改進的地方。
2. 技術與原理
2.1 技術選型
Python 語言介紹
? Python 是一種面向對象、解釋型的計算機程序編程語言。它包含了一個功能強大并且完備的標準庫,能夠輕松完成很多常見的任務。它的語法比較簡單,與其它大多數程序設計語言使用大括號把函數體包起來不一樣,它通過縮進來定義語句塊。[4]使用 Python 能夠高效靈活地實現開發的任務,內置庫以及大量的第三方庫能夠在許多地方避免重復造輪子的現象,有時使用 C++ 語言來實現的一個功能可能需要幾十行,Python 只需要幾行就足夠了。與傳統的腳本語言相比,Python 擁有更佳的可讀性和可維護性。這門語言的強大吸引到了許多開發者,擁有比較熱門的 Python 社區,許多開發者在維護著這種 Python 編寫的庫,影響力也在日益增強。在網絡爬蟲領域,Python 這門語言的使用也比較廣泛,留下了大量的前人的學習研究的資料。基于以上優點,我選擇了使用 Python 來開發本系統的網絡爬蟲部分和展示部分的服務端。
Scrapy 框架介紹
? Scrapy 是一個純 Python 基于 Twisted 實現的爬蟲框架,用戶只需要定制開發幾個模塊就可以方便地實現一個爬蟲,用來抓取網頁內容、圖片、視頻等。它最初是為了網站頁面抓取所設計的,也可以應用在獲取網絡應用 API 所返回的各類數據或者是編寫通用的網絡爬蟲。Scrapy 用途比較廣泛,可以應用于數據挖掘、自動化測試和數據監控等場景。Scrapy 提供了一些網絡爬蟲中比較通用的中間件和模塊等,也可以方便地編寫自己所需的中間件來對爬取結果進行處理,只要在配置里面引用這些中間件就可以了。使用 Scrpay 來編寫爬蟲可以降低很多需要重復編寫的爬蟲處理代碼所帶來的成本。
Django 框架介紹
? Django 是最早由 Python 實現的最著名的 Web 框架之一,最初是由美國芝加哥的 Python 用戶組來開發的,擁有新聞行業背景的 Adrian Holovaty 是 Django 框架的主要開發人員之一。 在 Adrian 的領導下,Django 團隊致力于為 Web 開發人員提供一個高效和完美的 Python 開發框架,并授權開發人員根據 BSD 開源協議許可證免費訪問。 [5] Django 是一個高效的 Web 框架,可以幫助我們減少重復的代碼,并把更多重點放在 Web 應用程序上的關鍵之處。在架構上,Django 跟 Scrapy 類似,也提供了中間件等,配置的方式也是類似的,使用類似的技術架構可以減少學習成本。本系統中我選用 Django 作為新聞訂閱的服務端來提供 API。
MongoDB 數據庫介紹
? MongoDB 是一個由 C++ 語言編寫的高性能,無模型的開源文檔型數據庫, 是當前 NoSQL 數據庫產品中最具有代表性的一種。MongoDB 是使用文檔來作為對象存儲的,一條記錄對應一個文檔,集合類似傳統的關系型數據庫中的表, 集合中存放的是那些具有同一特征或者屬性的文檔。在一個集合中,不同文檔擁有的屬性可以是不同的,這就是與傳統的關系型的數據庫的重點了,傳統的關系型數據庫要求表里的數據所擁有的屬性格式都是一致的,MongoDB 這種靈活性更利于文檔映射到一個對象或一個實體上。對于需要經常改動數據格式或者數據格式不定的一些需求來講,這種數據格式更為合適。MongoDB 在讀寫性能方面也遠超傳統的關系型數據庫的代表之一的 MySQL。在本系統中我使用 MongoDB 來存儲爬取到的數據以及用戶數據等。像 MongoDB 這樣的非關系型數據庫更合適儲存爬蟲數據,因為爬蟲數據量可能比較大,數據之間關系型也不強。MongoDB 的性能也比傳統的關系型數據庫代表 MySQL 之類要強。
AJAX 介紹
? AJAX(異步的 JavaScript + XML)本身并不是一種技術, 它是由 Jesse James Garrett 在 2005 年提出的一個術語, 描述了一種需要結合使用大量已經存在的技術的方式, 包括 HTML, JavaScript, CSS, DOM, JSON, XML 等, 還有最重要 JavaScript 中的的 XMLHttpRequest 對象。當這些技術以 AJAX 模型的方式聚合時,Web 應用程序可以更迅速地,無需加載整個頁面就能更新全部或者部分的用戶界面。這使 Web 應用能夠更快地響應用戶行為,帶來更友好的用戶體驗。盡管在 AJAX 中 X 代表 XML, 但現在 JSON 使用的更多,因為 JSON 具有許多 XML 不具備的優勢,比如它更輕量并且是 JavaScript 的一部分,各個程序語言都能夠輕松解析 JSON 格式的數據。在 AJAX 模型中,JSON 和 XML 的作用都是承載信息。[6]本系統會在新聞訂閱和展示部分的前端使用 AJAX 來跟服務端進行交互,以達到前后端分離的目的。
2.2 相關原理介紹
網絡爬蟲介紹
? 網絡爬蟲(英語:Web crawler),也叫網絡蜘蛛(spider),是一種自動提取網頁的程序,它為搜索引擎從萬維網上下載網頁。傳統的爬蟲的啟動從一個或多個初始網頁開始的,從這些初始網頁上獲得接下來要爬取的 URL,在抓取網頁內容的過程中,不斷從當前頁面的內容上抽取新的需要繼續爬取 URL 放入隊列,直到滿足系統的一定停止條件。[7]網絡爬蟲的抓取策略大致可以分為以下三類:廣度優先搜索策略、深度優先搜索策略、最佳優先搜索策略等。本系統的爬蟲部分使用的爬蟲策略是廣度優先搜索策略,因為本系統的網絡爬蟲具有針對性,所以爬取的層數不會很多。
關鍵詞提取技術
? 通過分析文本,利用關鍵詞抽取技術可以抽取出文本的關鍵詞,關鍵詞能夠簡單地反映出文本的主要內容,使人們更加直觀方便地了解到文本內容的主題。關鍵詞提取的技術有許多種,最常用的應該是基于統計的方法的 TF-IDF 算法。TF-IDF(term frequency-inverse document frequency)是一種常用的用于數據挖掘與信息檢索的加權技術。[8]詞語的重要性是在 TF-IDF 算法中主要是由它在文中出現頻率決定的。
? Jieba 是一個基于 Python 的中文分詞庫,支持三種分詞模式:精確模式、全模式和搜索引擎模式,它能夠基于 Trie 樹結構來實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖,采用了動態規劃查找最大概率路徑, 找出基于詞頻的最大切分組合。在本系統中,將考慮使用 Jieba 分詞基于 TF-IDF 算法的關鍵詞抽取來抽取出爬取到的新聞內容的關鍵詞。
智能推送技術
? 當我們使用如今的一些應用程序時,會經常收到來自這些應用的推送,過多的、不適當的推送會打擾到用戶,互聯網技術在最近幾十年里已經得到了很大的發展,但是推送通知技術仍舊停留多年以前。為了實現智能化推送,我們需要搜集和分析能夠幫助我們實現智能化推送通知的用戶數據,這些數據的來源可以是用戶的設置或者用戶在應用中產生的數據等。在智能推送通知中,與時間相關的, 個性化的,有幫助的,有聯系性的是智能推送通知中四個基本的特征。
? 在推送的時間上,我們可以做到時間智能化,時間智能化指的是推送的時間要恰當,推送發生在不恰當的時間比無用的垃圾推送消息造成的不良效果更驗證。在不恰當的時候推送的通知不但打擾到用戶,還很容易會被用戶忽略。智能推送應該能夠做到自動解決推送時間不恰當的問題。具體的實現可以通過一個對推送信息的重要性評估的引擎來決定消息推送的時間。
? 在個性化上,我們可以把推送機器人設計成人類的形態,比起傳統的系統消息,擬人化的方式能夠讓人更加容易接受,如蘋果的 Siri 和微軟的 Cortana。當我們將來自機器智能的推送通知語言根據用戶自己的特點進行調整后,用戶在查看時看到的是更像交流式的風格,會感到更有親切感,更加個人化。
? 在推送的內容上也要慎重選擇,根據不同用戶來推送不同的內容。因為對于用戶來說,只有用戶關心的內容才是對用戶有幫助的。拿新聞訂閱應用來講,就是用戶只會對某些主題內容的新聞感興趣,應用要做的就是把新聞的主題進行分析,打上不同的標簽。然后找到用戶興趣中含有這些標簽用戶進行推送。如果不經處理對全部用戶進行統一的推送,用戶需要花費大量時間在這上面去過濾出自己感興趣的內容。
? 在推送內容的數量上也有講究,如果一個服務高頻次地的使用通知推送,用戶可能會感覺到被冒犯然后會關掉它,后面的推送就都收不到了。因此,將推送的內容進行分組就很重要了。系統可以把一些相似的通知進行分組合并,可以減少對用戶的打擾,在消息很多的時候這種優勢就很明顯了。在信息較少的時候可以選擇把這些推送通知進行展開,因為此時用戶可能會比較關心這些少見的內容,也是一個不錯的選擇。
3. 系統需求分析
3.1 新聞訂閱系統用例析取
? 基于網絡爬蟲的新聞采集與訂閱系統要實現新聞數據抓取,數據過濾,數據篩選,數據展示,新聞訂閱,推送等服務和功能,本系統用例圖如圖 3.1 所示:
? 圖 3.1 系統用例圖
本系統主要用于以下幾類人員:
-
數據管理員,完成數據的抓取,過濾與篩選,新聞的推送,以及本系統管理與維護等。
-
用戶,在網頁上進行新聞訂閱,通過微信接收訂閱新聞的推送,點擊進入對應新聞展示頁面等
3.2 新聞訂閱系統用例規約
新聞訂閱
-
簡要說明
本用例允許用戶增加或者刪除自己訂閱新聞的關鍵字,以及對已經訂閱的關鍵字進行確認等操作。
-
參與者
用戶。
-
事件流
基本事件流
用例開始于用戶進入新聞訂閱頁面進行操作。
-
訂閱新聞關鍵字的狀態共有兩種,分別為“已訂閱”、“未訂閱”。顧客可以在相應的狀態下進行操作,選擇增加關鍵字或者刪除關鍵字。
-
如果關鍵字狀態為“未訂閱”,用戶可以增加該關鍵字到自己的訂閱列表中, 本用例結束。
-
如果關鍵字狀態為“已訂閱”,用戶可以選擇刪除該關鍵字,本用例結束。
-
特殊要求無。
-
前置條件
? 本用例開始前用戶必須是微信已登錄狀態。
-
后置條件
? 如果用例成功,用戶的訂閱列表將被更新。
-
活動圖
-
新聞推送
-
簡要說明
本用例允許數據管理員根據新聞的關鍵字向已經訂閱該關鍵字的用戶進行推送等操作。
-
參與者
數據管理員。
-
事件流
-
基本事件流
用例開始于爬蟲系統采集到新聞時。
-
系統將新聞內容根據算法與用戶訂閱的新聞關鍵字作對比,對比結果分別為“匹配”、“不匹配”。
-
如果匹配狀態為“匹配”,系統將調用微信推送接口向用戶推送該新聞,本用例結束。
-
如果匹配狀態為“不匹配”,用戶將不會收到該新聞的推送,本用例結束。
-
特殊要求無。
-
前置條件
? 本用例開始前采集到的新聞必須有效。
-
后置條件
? 如果用例成功,用戶將收到一條新聞推送。
-
活動圖
-
-
? 圖 3.3 新聞推送活動圖
4. 新聞采集與訂閱系統的設計
4.1 系統架構及原理
? 本新聞采集與訂閱系統分別由爬蟲部分與新聞訂閱和展示部分構成,在新聞訂閱與展示部分采用基于 C/S 的架構,代碼的組織方式為 MVC 三層結構,其中的三個層次分別為視圖層(View )、控制器層(Controller)和模型層(Model)。代碼整體采取前后端分離的方式,前端負責視圖層,后端負責模型層和控制器層,客戶端使用微信和網頁實現, 前后端通訊使用 AJAX 交換 JSON 的方式。系統的總體框架圖如圖 4.1 所示:
? 圖 4.1 系統總體架構圖
? 爬蟲部分使用了 Python 編寫 Scrapy 框架,它的基本架構如圖 4.2 所示,其中 Scrapy 引擎的作用是控制數據的流向,是整個爬蟲框架的核心。網絡蜘蛛(spiders) 定義了如何爬取某個(或某些)網站,包括了爬取的動作以及如何從網頁的內容中提取結構化數據。蜘蛛中間件(spider middleware)是在 Scrapy 引擎和網絡蜘蛛間的一個鉤子,它可以處理蜘蛛的輸入與輸出。調度器(scheduler)能夠從 Scrapy 引擎接受請求并放入隊列,在引擎請求調度器時返回對應的請求。下載器(downloader)負責下載網頁,把爬取到的內容返回給 Scrapy 引擎和網絡蜘蛛。下載器中間件(downloader middleware)是在 Scrapy 引擎和下載器間的一個鉤子,它可以處理傳入的請求跟傳出的響應。Item Pipeline 負責處理網絡蜘蛛傳過來的 Item,可以在此做數據格式化,數據清理等操作。
? 圖 4.2 Scrapy 架構圖
? 爬蟲的整體上數據流向的開始是由 Scrapy 引擎讓網絡蜘蛛以一個初始的 URL 來初始化一個請求,并設置回調函數,然后網絡蜘蛛把該請求向調度器申請任務,把申請到的任務交給下載器,這里會經過一次下載器中間件,然后下載器把下載完后產生的響應再經過一次下載器中間件,然后傳遞給引擎,引擎接收到該響應后通過蜘蛛中間件傳給網絡蜘蛛處理,網絡蜘蛛處理該響應,產生一個 item 或者是新的請求給引擎,引擎會把傳過來的 item 放入 Item Pipeline,把傳過來的新的請求傳給調度器,Item Pipeline 獲取接收到的 item 對該 item 進行逐層處理,接著這個流程就重復直到爬取完成。
4.2 系統模塊設計
爬蟲采集模塊設計
? 使用 Scrapy 框架來編寫爬蟲首先要編寫核心的蜘蛛(spiders)的代碼,Spider 類定義了如何爬取某個(或某些)網站,包括了爬取的動作以及如何從網頁的內容中提取結構化數據。本系統主要針對網易新聞和騰訊新聞的科技頻道進行主題式的爬蟲,所以設計了兩個網絡蜘蛛,名字分別為 NeteaseSpider 和 QQSpider,如果后續需要更多需要爬蟲的站點,只要增加對應站點的網絡蜘蛛就可以了,其余處理部分都是通用的。在這里選擇主題式的爬蟲的原因主要是一個通用爬蟲對于新聞這樣的每個站點的文章有固定格式的爬取解析的代價比較大,還不如手工去對需要爬取的站點進行分析,根據每個站點的特點來編寫解析的代碼。這樣的主題式的爬蟲能夠提高爬蟲的精確度,同時也提高了爬蟲的效率,這樣我們的爬蟲就能夠及時爬取到最新的新聞內容了。每個站點對應一個特定的網絡蜘蛛還有一個好處就是如果后續需要完成分布式爬蟲等需求時會很方便,因為這樣的方式代碼之間的耦合度較小,同時非常簡潔。
? 網絡蜘蛛首先從一個 start_url 開始爬取,這里我選取了網易新聞和騰訊新聞的科技頻道的首頁,蜘蛛爬取這個起始 URL 上的頁面后,對里面的內容進行解析。因為每篇新聞的 URL 都具有一定的格式,凡是該頁面上有符合這種格式的 URL,蜘蛛都會對這些 URL 進行回調,繼續爬取這些 URL 的頁面,這些頁面上就會包含所要獲取的新聞的內容了。對于同一個新聞站點來說,一般頁面上的內容的結構也是一樣的,所以按照一定的規則來對這些頁面上的內容進行解析,獲得新聞內容原始數據,對這些數據進行格式化的處理,封裝成一個 item,傳回給 Scrapy 引擎處理。
? 因為新聞具有一定時效性,一般來說我們只會關注那些新產生的新聞內容, 所以本爬蟲不需要考慮需要爬取過往產生的新聞的情況。本系統的爬蟲部分只聚焦于每個站點的首頁的新聞,因為新聞是滾動刷新的,所以我們需要定時對首頁進行爬取,獲取新的新聞內容。本系統設計了一個類似守護程序,來控制爬蟲的啟動與停止,在爬蟲結束后等待一段時間再重新開始爬取。
爬蟲去重模塊設計
? 在爬蟲過程中會遇到重復內容的情況,所以我們需要設計一個爬蟲用到的去重的模塊。考慮到每個 URL 對應的新聞內容是不變的,我們只要針對 URL 來進行去重即可,而不需要等到把內容取回來之后再判斷內容是否已經爬取過,那樣會消耗大量額外的資源,也對目標網站造成了額外的壓力,顯得不友好。我們選擇去重的時機是 Scrapy 的調度器把請求分配給下載器之前,也就是說在下載器中間件中處理,在本系統中定義了一個下載器中間件 RedisMiddleware,這個中間件的作用是在 Redis 的一個散列中判斷是否存在該 URL,如果不存在,把該請求傳給下一個中間件處理。如果該 URL 存在于散列中,則忽視掉該請求,不進行后續操作。在本系統中定義了一個 Item 管道 RedisPipeline,在爬取數據完成后,數據庫處理完后 Item 會傳到該管道,該管道的作用是把這個新聞所屬 URL 存入 Redis 的散列中,標記該 URL 已經爬取。
防反爬蟲模塊設計
? 防反爬蟲是在大多數爬蟲中需要考慮的情況,因為爬蟲對網站服務器造成的壓力比正常人要多,如果爬取頻率足夠高的話,會使網站訪問變慢,甚至無法訪問,所以網站可能會有一系列的反爬蟲措施。首先我們的爬蟲需要遵守網站的爬蟲協議,然后把爬取速率控制好,例如間隔一秒才爬取一個頁面。其次,我們需要偽裝成一個瀏覽器,有些網站會通過 HTTP 請求頭中的 User-Agent 中的信息來判斷用戶,我們不但需要在爬蟲請求中的 HTTP 設置 User-Agent 請求頭,還需要對該請求頭進行更換,因此在本系統中定義了一個下載器中間件 RotateUserAgentMiddleware,這個中間件的作用是在請求前在請求的 HTTP 請求頭中設置一個輪換的隨機的模擬用戶瀏覽器的 User-Agent 請求頭,這些 User-Agent 與真實瀏覽器的 User-Agent 一致,數據來源是 Python 中一個叫 fake-useragent 的庫。后續如果對方服務器針對 IP 進行禁封了的話可以采用代理服務器的方式來應對,在做了以上措施的情況下本系統目前沒有出現過被禁封的情況,因此該方法沒有在本系統中實現。
爬蟲存儲模塊設計
? 爬蟲的數據存儲是一個爬蟲系統中很重要的一部分,因為爬蟲的目的就是獲得數據,在這里我們需要考慮數據的存儲方式與儲存時機。在本系統中儲存部分使用了 ORM(對象關系映射)的方式來實現,ORM 的好處在于把數據訪問的細節隱藏起來,在 ORM 上的操作出錯的可能性會比手寫數據庫操作的可能性低。在 ORM 中,我們只需要關注數據的結構,這樣一來,我們只需要編寫數據儲存對象的參數定義等屬性跟方法就可以了,初始化、查詢、更新等操作都可以由 ORM 來實現。在本系統中,爬蟲部分與訂閱和展示部分都共用一個數據庫,爬蟲部分需要對數據庫進行寫操作,展示部分需要對數據庫進行讀操作。在蜘蛛解析完數據后,蜘蛛會把封裝好的 Item 通過 Scrapy 引擎傳給 Item 管道,系統定義了一個 MongoDBPipeline,這個管道的作用是維持一個 MongoDB 的數據庫鏈接,接收到傳入的 Item 后先校驗完數據的完整性,然后把合法的數據插入數據庫對應的集合中,否則丟棄該 Item。
消息推送模塊設計
? 消息推送部分本系統使用微信來實現,需要用戶關注指定公眾號。本系統需要推送消息給用戶時,先選擇一個本系統預定義的模板,在模板中填入消息標題, 內容和鏈接等數據后,通過微信提供的接口來進行推送。這里需要注意的是我們需要給推送的消息接口提供一個本系統所用的公眾號的 AccessToken,這個 AccessToken 是向微信證明本系統的憑證,它有一定的有效期,需要定時刷新。
消息訂閱與展示模塊設計
? 消息訂閱與展示模塊是本系統中與用戶交互的模塊,這個模塊負責用戶訂閱新聞的功能與向用戶展示所需新聞內容的模塊。在本系統蜘蛛解析完數據后,蜘蛛會把封裝好的 Item 傳給 MongoDBPipeline 儲存后,會繼續往下傳遞,傳遞到一個 PushPipeline 中,這個管道的作用是判斷爬取到的數據是否包含用戶所訂閱的關鍵詞,如果包含的話則調用消息推送模塊把新聞消息推送給用戶。在消息推送后,用戶會在微信端本系統的公眾號中接收到一條包含新聞消息簡要內容的消息,點擊該消息可以跳轉到新聞展示頁面。本系統提供了一個消息訂閱頁面,用戶可以在該頁面上管理自己的新聞關鍵詞。
4.3 數據庫設計
? 本系統存放數據用到的數據庫分別是 Redis 和 MongoDB,在本系統的數據庫設計中,數據庫的集合主要包括爬取到的新聞信息集合和用戶訂閱新聞關鍵詞集合,系統的配置信息都寫在配置文件中,就不需要使用數據庫來存放了。這里選擇 MongoDB 的原因是考慮到當爬蟲的數據量和并發數很大時,關系型數據庫的容量與讀寫能力會是瓶頸,另一方面,爬蟲需要保存的內容之間一般不會存在關系。另外本系統會使用 Redis 中的散列類型來存放已經爬取過的 URL 和不合法的 URL,因為判斷 URL 是否合法或者是否已經爬取過是一個高頻的操作,使用 Redis 這樣的高性能的內存鍵值對類型的數據庫可以減少主數據庫的壓力,同時提高爬蟲的性能。
表 4.1 新聞信息集合
| title | 新聞標題 | string | |
| content | 正文內容 | string | 純文本 |
| source | 來源 | string | 新聞出處 |
| published | 發布時間 | timestamp | 精確到秒 |
| url | 原文鏈接 | string | 用于跳轉 |
表 4.2 用戶訂閱新聞關鍵詞集合
| open_id | 用戶微信 openid | string | 唯一標識 |
| keywords | 訂閱的關鍵詞列表 | array | 字符串類型的數組 |
| tags | 訂閱的標簽列表 | array | 字符串類型的數組 |
5. 新聞采集與訂閱系統的實現
5.1 系統框架實現
? 本新聞采集與訂閱系統的爬蟲部分框架是利用 Scrapy 自帶的命令行工具來初始化,初始化后已經創建好了 Scrapy 引擎所需的幾個重要的文件,如中間件, 數據管道,配置文件等,這樣做的好處是能夠快速搭建起框架,并且能夠達到官方定義的最佳實踐。接下來我們可以在這個目錄下定義自己的一些模塊文件,再在這些文件中實現自己的處理函數就可以了,最終實現的爬蟲部分的目錄結構如圖 5.1 所示,其中 items.py 是用于定義數據儲存模型的文件,middlewares.py 是用于定義中間件的文件,pipelines.py 是用于定義數據管道的文件,settings.py 是本系統爬蟲部分的配置內容,spiders 文件夾中存放了不同爬蟲的網絡蜘蛛代碼, utils.py 則是一些通用的函數存放的地方,wechat_config.py 和 wechat_push.py 分別是微信推送部分的配置和推送代碼。
圖 5.1 爬蟲部分目錄結構
? 新聞訂閱和展示部分的 API 服務器端則使用 Django 自帶的命令行工具來初始化,使用 django-admin startproject 命令來新建一個項目,然后使用 django-admin startapp 命令來新建一個 app,這樣 API 服務器的基本框架就完成了,然后往創建的目錄中添加其余代碼,最終實現的新聞訂閱與展示部分的目錄結構如圖 5.2 所示,其中 frontend 文件夾存放的是本系統的前端靜態文件,分別是新聞訂閱頁面和新聞展示頁面,init_db.py 文件是一個用于初始化數據庫用的腳本,lib 文件夾中存放的是本系統中一些能夠被公用的函數文件。manage.py 是由 Django 生成的用于管理任務的命令行工具腳本, news_web 存放的是本項目的代碼, run_server.sh 是一個用于啟動服務器的腳本文件,web_server 中存放的是本系統新聞訂閱與展示部分的服務端代碼的主要文件,主要包括了用于配置路由 urls.py,存放新聞和訂閱信息數據模型 models.py 和提供 API 的 views.py。
圖 5.2 新聞訂閱與展示部分的目錄結構
5.2 爬蟲采集模塊實現
? 爬蟲采集模塊的核心的網絡蜘蛛,下面以爬取網易科技頻道新聞的蜘蛛為例講解本系統爬蟲采集模塊的實現過程。圖 5.3 為該蜘蛛的解析網頁請求響應的代碼,首選我通過分析網易科技頻道新聞中的網頁源碼,分析得到網頁中所需的新聞內容的數據所在的位置特征信息,例如通過分析發現標題位置是處于 HTML 標簽下的 head 標簽里的 title 標簽里的文本。24-27 行中的代碼的作用是通過 xpath 使用之前分析出來的格式來從抓取到的數據中提取出新聞相關的信息,包括新聞標題、新聞消息來源、新聞內容、新聞發布時間。29-32 行的代碼作用是把時間解析為時間戳,這樣做的目的是為了方便把時間轉換成不同的表現格式,時間表現會更為準確。34-40 行的代碼作用則是把數據封裝成一個本系統中的新聞 Item, 然后傳給 Item 管道來處理。另外一個用于爬取騰訊新聞科技頻道蜘蛛的分析方法和代碼寫法是類似的,在這就不詳細介紹了。
圖 5.3 蜘蛛解析網頁請求響應的代碼
? 為了實現定時爬蟲的功能,在本系統中實現了一個名為 worker.py 的守護進程腳本和一個 start_crawl.py 的用于調用爬蟲的腳本,運行 worker.py 腳本后會每三十秒調用啟動一次 start_crawl.py,start_crawl.py 每次啟動會調用爬蟲主程序, 程序核心代碼如下:
圖 5.4 守護進程核心代碼
5.3 防反爬蟲模塊實現
? 為了防止反爬蟲對本系統爬蟲部分的影響,對于每次請求,本系統都會偽裝成一個真實的用戶,防止被爬取的網站通過 User-Agent 等信息來判斷或者禁封掉本系統的爬蟲,導致后續爬蟲無法正常進行。本系統在發送請求之前會在請求的頭部加上 User-Agent 的請求頭信息,這個請求頭的信息會在本系統配置中的 User-Agent 列表中隨機選取一個,圖 5.5 為部分 User-Agent 信息。除此之外,還可以利用代理服務器來代理請求,防止被爬取的網站通過 IP 信息來禁封本系統爬蟲。
圖 5.5 部分 User-Agent 列表
5.4 爬蟲存儲模塊實現
? 爬蟲儲存模塊的數據設計與格式等在上一章已經說明,在這介紹在數據庫中的具體實現。爬蟲爬取到的新聞數據會存放于 MongoDB 中,使用 ORM 來映射數據對象模型到數據庫,使用的 ORM 框架是 MongoEngine,下面通過講解一個新聞內容的數據模型的定義來說明這種定義方式,在圖 5.6 中的第 9 行,我們定義了一個父類為 MongoEngine 的 Document 類的類,這樣定義就使這個類擁有了關系對象映射的能力,再在這個類中定義一個 to_json 的方法,作用是把本類的實例轉化為一個 Dict 類型的數據,方便 API 調用時將對象轉換成 JSON 格式的數據返回給前端。圖 5.7 展示了部分爬取到的新聞數據的內容。
圖 5.6 新聞數據庫 ORM 模型
圖 5.7 部分爬取到的新聞數據的內容
5.5 消息推送模塊實現
? 消息推送模塊使用了微信公眾號的推送,在本系統中使用微信的接口測試號來代替公眾號,微信的接口測試號是一種用于測試的,可以使用微信號掃一掃登錄的賬號,而且這種賬號能夠直接體驗和測試公眾平臺所有高級接口。在申請完后登錄系統,獲得該系統的 appID 和 appsecret,這兩個字符串是使用該賬號的憑據。需要注意的是,用戶需要關注本賬號后才能夠收到本賬號推送的消息。
圖 5.8 測試號管理
? 接下來我們在網頁下方新增一個消息模板,填入推送新聞消息的模板內容, 填寫完成后記錄對應的模板 ID。
圖 5.9 測試模板消息
? 獲得以上信息后把信息寫入消息推送模塊的配置文件中,供消息推送模塊調用。下面講解消息推送模塊核心部分的實現,核心部分如圖 5.10 所示,是一個名為 send_msg 的函數,這個函數接收四個參數,分別為新聞標題、新聞內容、新聞的 ID 和訂閱者的 openid。訂閱者的 openid 是用戶微信的唯一標識,在測試號的頁面可以查看已關注該賬號的用戶微信的 openid。該函數的 29-42 行的作用是把數據封裝成微信推送接口所需的格式,然后在 45 行使用 requests 模塊來 POST 一個請求到微信推送接口,微信推送接口收到請求后會在公眾號中把該消息推送給用戶。該函數使用了一個自定義的裝飾器 update_token 來裝飾,之前存放的 appID 和 appsecret 可以用來生成推送用的 access token,而這個 access token 有固定的存活期限的,這個裝飾器的作用就是定時去獲取這個 access token 并存放,直到過期之后再重新獲取。
? 爬蟲模塊爬取到含有用戶訂閱的關鍵詞的新聞時會向該用戶推送這則新聞, 圖 5.11 是用戶在微信公眾號上收到的該新聞的推送消息示例。
圖 5.10 推送消息函數
圖 5.11 用戶收到的推送消息
5.6 消息訂閱與展示模塊實現
? 消息訂閱與展示模塊主要由前端靜態文件部分和后端 API 部分組成。在開發方式上本系統選擇了使用前后端分離的方式,前端通過 AJAX 的方式來跟后端提供的 API 進行交互,后端 API 服務器收到請求后返回對應的 JSON 格式的數據給前端,前端根據數據來渲染出最終展示給用戶的頁面,這種前后端分離的方式有效地降低了代碼之間的耦合度。在前端實現方面,使用了 jQuery 來對 DOM 元素進行操作以及進行異步請求等,另外使用了 WeUI 的樣式庫,WeUI 是一套提供了同微信原生一致的視覺體驗的基礎樣式庫,由微信官方設計團隊為微信內網頁和微信小程序量身設計,令用戶的使用感知更加統一。
? 接下來以用戶端的角度來展示消息訂閱與展示模塊的實現。
? 用戶想要收到新聞推送,需要先關注本系統的公眾號,然后打開新聞訂閱頁面:
圖 5.12 新聞訂閱界面
這時可以輸入要訂閱的關鍵詞,這里填 IT,點擊添加訂閱關鍵詞,系統提示添加關鍵詞 IT 成功,刷新已訂閱關鍵詞列表:
圖 5.13 新聞訂閱界面-添加關鍵詞
點擊已訂閱關鍵詞列表中的項會彈出對話框詢問是否刪除該關鍵詞:
圖 5.14 新聞訂閱界面-提示刪除關鍵詞
點擊確定,提示操作成功,同時刷新已訂閱關鍵詞列表:
圖 5.14 新聞訂閱界面-刪除關鍵詞成功
在訂閱關鍵詞后,系統爬蟲爬取到相關內容時會把內容通過微信推送給用戶,用戶點擊后可以看到新聞內容,在此頁面可以點擊查看原文按鈕打開原新聞頁面,還有可以點擊訂閱更多前往訂閱新聞關鍵詞的頁面:
圖 5.15 新聞內容界面 1 圖 5.16 新聞內容界面 2
點擊查看原文,會跳轉到新聞的原頁面:
圖 5.17 新聞原頁面
第六章 系統部署
6. 部署機器概述
? 為了運行本新聞采集與訂閱系統,至少需要一臺擁有公網 IP 的 Linux 服務器, 這是為了用戶在外網能夠訪問到。至于配置方面則不需要太高,在測試時我選用了一臺騰訊云上的服務器,這臺服務器的配置如下:
表 6.1 服務器配置
| 操作系統 | Ubuntu Server 14.04.1 LTS 64 位 |
| CPU | 1 核 |
| 內存 | 1GB |
| 系統盤 | 20GB |
| 公網帶寬 | 1Mbps |
6.2 配置環境
- 安裝 Nginx 作為反向代理服務器,并編輯 Nginx 相關配置文件,這樣做是為了把不同的請求分發到后端不同的地方,例如請求前端文件就返回靜態文件, 請求 API 就把請求轉發給 API 服務器,Ningx 的配置文件部分內容如圖 6.1 所示。這樣就實現前后端分離而又不受到跨域請求限制的影響了。編輯完 Nginx 配置文件后,重啟 Nginx 服務器。
- 安裝 PIP,PIP 是 Python 用于管理第三方庫的一個軟件,這里用于安裝本系統所需的第三方庫。
- 使用 PIP 安裝本系統所依賴的第三方庫,包括 pymongo, scrapy, redis, fake-useragent, django, mongoengine, jieba, lxml, gevent, gunicorn 等。
圖 6.1 Nginx 配置
6.3 系統運行
? 由于本新聞采集與訂閱系統是由爬蟲部分與展示部分組成,所以需要分別運行爬蟲的守護進程和后端 API 服務器,靜態頁面是由 Nginx 指定的一個目錄來提供的,不需要后臺服務器。
? 使用 python worker.py 命令來運行爬蟲的守護進程,得到以下輸出:
圖 6.2 爬蟲守護進程運行
? 使用 sh run_server.sh 命令來運行后端 API 服務器,這個腳本的實際作用是使用 gevent 作為 gunicorn 的 worker 來運行了四個后端 API 服務器進程,成功運行會得到以下輸出:
圖 6.3 后端 API 服務器啟動
7. 總結與展望
7.1 總結
? 本系統是一個基于網絡爬蟲實現的新聞采集與訂閱系統,實現了對網絡上新聞內容的自動化采集、用戶新聞關鍵詞訂閱、新聞內容展示以及新聞推送等功能。為實現本系統的功能,查閱了大量學習資料,在實現方面使用了一些比較前沿的技術以及較多的第三方庫,從中能夠學習到很多新知識和新技能。在本文中較為完整地從系統的需求分析、不同模塊的設計與實現幾個方面來展示了一個完整的爬蟲系統以及對應的新聞訂閱 API 服務器等的實現過程,最后在云服務器上部署本系統并測試,達到了預期的效果。
7.2 展望
? 本新聞采集與訂閱系統在設計上考慮了許多來降低代碼之間的耦合度,同時提高代碼的健壯性與性能,使本系統能夠達到容易擴展以及高可用的需求,即便后續需要爬取另外一個新的新聞網站上的新聞,只需要編寫對應網站的解析部分就可以了,大部分代碼已經被模塊化,能夠被重用。對比了已有的類似的成熟大型新聞服務系統,發現還有以下能夠改進的地方:
- 本系統只對新聞的基本文字信息等進行了采集與展示,后續可以考慮實現對新聞中圖片與視頻等多媒體信息的采集。
- 本系統缺乏一個較為完善的用戶模塊,目前用戶是在配置文件中配置的, 用戶模塊對于這類的訂閱系統是比較重要的。
- 訂閱機制不夠智能,也沒有智能推薦等功能,后期可以采用機器學習等人工智能方法來實現智能化推送與推薦功能。
除了以上幾點,本系統仍然存在許多能夠改進的地方,但由于本文作者水平有限以及時間限制,未能夠將這些一一實現,還希望各位專家學者能夠給予批評與建議。
?? 資源
大小: 7.04MB
?? 資源下載:https://download.csdn.net/download/s1t16/87359325
總結
以上是生活随笔為你收集整理的基于Python(Django)+MongoDB实现的(Web)新闻采集和订阅系统【100010319】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 码绘VS手绘
- 下一篇: c语言程序中u8是什么意思,c – __