本發(fā)明涉及一種基于Ajax的新聞網(wǎng)頁動態(tài)數(shù)據(jù)的抓取方法及系統(tǒng)。
背景技術(shù):
目前,新聞網(wǎng)站的信息具有類別繁多,更新頻率快,多平臺發(fā)布的特點,數(shù)據(jù)的調(diào)取方式也十分靈活。很多新聞網(wǎng)站的頁面都采用Ajax調(diào)用數(shù)據(jù)的方式,這樣通過一個數(shù)據(jù)來源,可以在不同的平臺進行解析,比如PC端網(wǎng)頁和手機版網(wǎng)頁可以共享一個數(shù)據(jù)請求,通過不同的模板來呈現(xiàn)出不同的排版樣式。
在采集和抓取網(wǎng)絡(luò)站點的新聞數(shù)據(jù)時,會發(fā)現(xiàn)很多網(wǎng)站數(shù)據(jù)是通過Ajax獲取的動態(tài)內(nèi)容,并沒有一個固定的靜態(tài)模板。獲取數(shù)據(jù)的JavaScript腳本程序往往是在整個頁面的DOM結(jié)構(gòu)加載完之后才會執(zhí)行。如果整個網(wǎng)頁頁面的DOM結(jié)構(gòu)尚未加載完,網(wǎng)絡(luò)爬蟲訪問此地的時候并不會獲取到數(shù)據(jù)內(nèi)容,這就大大降低了網(wǎng)絡(luò)數(shù)據(jù)采集的效率和質(zhì)量。
如果需要獲取到通過Ajax請求動態(tài)加載的數(shù)據(jù),就需要對網(wǎng)站的請求的數(shù)據(jù)源地址進行分析,Ajax調(diào)用的數(shù)據(jù)格式往往是JSON、JSONP、XML或Inc等格式。經(jīng)過分析之后,不同網(wǎng)站采用的網(wǎng)絡(luò)技術(shù)不同,所以調(diào)用Ajax請求時采取的方案也有很大差別,數(shù)據(jù)源存儲的格式也是多種多樣的。
通過對現(xiàn)有技術(shù)進行分析,發(fā)現(xiàn)目前并沒有一個統(tǒng)一的自動化分析Ajax數(shù)據(jù)源的方法,已有的方法不能一次性解決所有的Ajax獲取動態(tài)內(nèi)容的問題。
首先,大部分的實現(xiàn)方法還是通過JavaScript腳本中的特征值來檢索,從而進一步猜測和推斷Ajax的請求內(nèi)容。然而這樣做并不能準(zhǔn)確地找出想要采集的目的數(shù)據(jù)。當(dāng)前來看,一個頁面當(dāng)中很可能包含多個Ajax請求,有些是關(guān)于用戶信息認證的請求,有些是訂閱信息的返回數(shù)據(jù),還有一些廣告推送信息。這些信息混雜在一起,只靠腳本代碼中的特征值很難分辨出哪些是需要采集的數(shù)據(jù)源。另外,對腳本代碼的特征值分析也只限于JavaScript代碼沒有加密的情況,現(xiàn)在很多站點基于安全性的和訪問效率的要求,可能會對多個JavaScript腳本文件進行合并然后做加密處理,這樣一來會使本來存在的特征值消失。
其次,Ajax的調(diào)用方式本身會存在跨域問題,這是它自身所特有的一種安全機制。即不在同一個域名下,使用腳本語言仍然無法成功執(zhí)行請求并返回數(shù)據(jù)。在處理這樣的調(diào)用方式時,因為不具備統(tǒng)一域名下的網(wǎng)絡(luò)環(huán)境,就難以自動完成Ajax觸發(fā)請求。還有一些站點在程序中會有反爬蟲的程序,如果頻繁訪問會出現(xiàn)二維碼等內(nèi)容阻斷新聞數(shù)據(jù)的繼續(xù)采集。
最后,即便是找到了Ajax請求的數(shù)據(jù)源,也會存在格式和編碼方式不匹配的問題。比如JAVA語言生成的JSON數(shù)據(jù),PHP語言就無法直接處理。有些返回數(shù)據(jù)中會帶有英文雙引號與JSON格式本身的符號沖突問題。還有些請求采取的是JSONP的請求方式,即附帶請求頭的JSON格式。
技術(shù)實現(xiàn)要素:
本發(fā)明的目的就是為了解決上述問題,提供一種基于Ajax的新聞網(wǎng)頁動態(tài)數(shù)據(jù)的抓取方法及系統(tǒng),它把重點放在數(shù)據(jù)源的策略分析上,對不同的情況采取定制化的方案。
為了實現(xiàn)上述目的,本發(fā)明采用如下技術(shù)方案:
基于Ajax的新聞網(wǎng)頁動態(tài)數(shù)據(jù)的抓取方法,包括如下步驟:
步驟(101):建立新聞網(wǎng)頁爬取內(nèi)容數(shù)據(jù)庫,設(shè)置新聞網(wǎng)頁爬取內(nèi)容數(shù)據(jù)庫的編碼方式;獲得待抓取新聞網(wǎng)頁的新聞列表頁面的URL地址;
步驟(102):訪問待抓取新聞網(wǎng)頁的新聞列表頁面的URL地址,通過瀏覽器開發(fā)者工具判斷新聞列表頁面是否是通過Ajax動態(tài)加載數(shù)據(jù)的;如果是,通過瀏覽器開發(fā)者工具找到Ajax請求的數(shù)據(jù)源;如果不是,就結(jié)束;
步驟(103):判斷Ajax請求的數(shù)據(jù)源和步驟(101)的編碼方式是否一致,如果不一致,則對數(shù)據(jù)源進行編碼轉(zhuǎn)換,然后,進入步驟(104);如果一致,就直接進入步驟(104);
步驟(104):解析數(shù)據(jù)格式:將數(shù)據(jù)源的格式解析成為新聞列表頁面的后臺語言處理的對象格式或者數(shù)組格式;
步驟(105):將步驟(104)解析后的數(shù)據(jù)封裝成對象或數(shù)組類型;判斷封裝是否成功,若成功就直接進入步驟(106);否則將數(shù)據(jù)作為字符串來處理;完成后進入步驟(106);
步驟(106):將數(shù)據(jù)對象或數(shù)組類型遍歷輸出列表;
步驟(107):利用網(wǎng)絡(luò)爬蟲采集步驟(106)得到的輸出列表;
步驟(108):將采集到的數(shù)據(jù)存儲到數(shù)據(jù)庫中。
所述步驟(101)URL地址包括臨時存在的URL地址、跳轉(zhuǎn)地址、需要添加時間戳參數(shù)或者簽名參數(shù)后訪問到的URL地址。
所述跳轉(zhuǎn)地址是指最終跳轉(zhuǎn)的URL地址。
所述步驟(101)的新聞網(wǎng)頁爬取內(nèi)容數(shù)據(jù)庫的字段包括:新聞標(biāo)題、新聞發(fā)布時間、新聞爬取時間、新聞來源和新聞內(nèi)容;
所述步驟(101)的新聞網(wǎng)頁爬取內(nèi)容數(shù)據(jù)庫的編碼方式包括:UTF-8的編碼方式或GBK編碼方式;
所述步驟(102)的瀏覽器開發(fā)者工具包括:谷歌瀏覽器開發(fā)者工具。
所述步驟(103)如果Ajax請求的數(shù)據(jù)源存在特殊字符或者亂碼,則把特殊字符或者亂碼進行批量替換,轉(zhuǎn)換成為可以進行處理的字符。
所述特殊字符包括:斜線、反斜線、冒號、星號、問號、引號、大于號、小于號或豎線符號等可能對JSON格式產(chǎn)生影響的字符。
所述可以進行處理的字符例如:中文引號、中文逗號、中文冒號等。
步驟(103):如果編碼方式不同,則將編碼方式統(tǒng)一,統(tǒng)一采用UTF-8的編碼方式。
所述步驟(102)和步驟(103)之間設(shè)有步驟如下:
步驟(1020):如果Ajax請求是跨域請求,則通過PHP的CURL方式模擬來路頁面,并通過host來獲取請求數(shù)據(jù)地址;
所述步驟(1020)通過PHP函數(shù)修改Referer來模擬在一個域名下進行請求,可以獲得請求數(shù)據(jù)地址返回來的結(jié)果,從而解決了跨域請求沒有權(quán)限獲取數(shù)據(jù)的問題。
步驟(1021):如果Ajax請求是POST請求,使用PHP語言http_build_query函數(shù)來模擬HTTP的POST請求,以便獲取到POST請求返回的數(shù)據(jù)。
步驟(1022):如果無法獲取數(shù)據(jù)內(nèi)容,則通過PHP的CURL來偽造來路頁面對Ajax請求的數(shù)據(jù)源進行訪問。
所述步驟(104)聞列表頁面的后臺語言包括JAVA,C++、PHP。
所述步驟(104)的步驟如下:
步驟(1041):如果數(shù)據(jù)是JSON格式,則直接進入步驟(105);
步驟(1042):如果數(shù)據(jù)是JSONP格式,則進行過濾處理;所述過濾處理是將JSONP格式數(shù)據(jù)的請求頭及括弧剔除,然后進入步驟(105);
步驟(1043):如果返回的內(nèi)容中出現(xiàn)中英文單雙引號使用不規(guī)范的問題,則通過PHP語言的字符替換函數(shù)進行過濾,將特殊字符替換為空字符。
所述步驟(1042)的JSONP是JSON格式的一種使用模式,通常用來進行跨域調(diào)用時使用。因為要對請求做出標(biāo)識,通常會帶有一個callback的參數(shù)作為請求頭,使用引文半角圓括號將JSON內(nèi)容包裹起來。JSON格式為帶請求頭的JSON格式。然而在JSON格式解析中,需要將其去掉才可以成為標(biāo)準(zhǔn)的JSON格式?;谏鲜鲈?,需要將返回內(nèi)容的請求頭及括號剔除掉。
所述步驟(1043):因為有些特殊字符會影響格式的規(guī)范,有些特殊字符則不能夠被識別,所以在封裝數(shù)據(jù)之前,要對這些特殊字符進行處理,即把它們批量替換成空字符。
所述步驟(105):
如果步驟(104)解析后的數(shù)據(jù)不是鍵值對類型,則將步驟(104)解析后的數(shù)據(jù)封裝成為數(shù)據(jù)對象,
如果步驟(104)解析后的數(shù)據(jù)是鍵值對類型,則將步驟(104)解析后的數(shù)據(jù)轉(zhuǎn)換成為數(shù)組類型。
所述步驟(105)將數(shù)據(jù)作為字符串來處理:
利用PHP語言的字符串分割函數(shù)對字符串的特征值進行分割,利用字符串拼接函數(shù)對字符串的特征值進行拼合,最終形成格式規(guī)范的數(shù)據(jù);
解析后的數(shù)據(jù)是一個新聞數(shù)據(jù)的集合,包含了多篇新聞數(shù)據(jù),所述特征值是指步驟(104)是每一篇新聞數(shù)據(jù)之間的分割字符。例如,在JSON格式中采用引文半角的逗號來分割。
如果不是通過逗號來分割,則分析數(shù)據(jù)找到數(shù)據(jù)單元的分割符號來進行處理,并把分割符號更新到特征值庫中。特征值需要不斷積累才能提高對各種類型數(shù)據(jù)特征值分隔符的識別程度。
所述步驟(106)相當(dāng)于通過解析需要抓取的新聞列表頁面的請求數(shù)據(jù)源在自己的服務(wù)器上面重新還原了新聞網(wǎng)頁。因為這個新聞網(wǎng)頁并不是Ajax調(diào)用的,而且是在自己的服務(wù)器中,不存在跨域問題或者請求數(shù)據(jù)的腳本程序在網(wǎng)頁DOM結(jié)構(gòu)加載后執(zhí)行的問題,網(wǎng)絡(luò)爬蟲可以進行采集。
所述步驟(106)的輸出列表包括:新聞標(biāo)題、新聞發(fā)布時間、新聞爬取時間、新聞來源、新聞內(nèi)容和新聞鏈接。
基于Ajax的新聞網(wǎng)頁動態(tài)數(shù)據(jù)的抓取系統(tǒng),包括:
數(shù)據(jù)庫建立模塊:建立新聞網(wǎng)頁爬取內(nèi)容數(shù)據(jù)庫,設(shè)置新聞網(wǎng)頁爬取內(nèi)容數(shù)據(jù)庫的編碼方式;獲得待抓取新聞網(wǎng)頁的新聞列表頁面的URL地址;
訪問模塊:訪問待抓取新聞網(wǎng)頁的新聞列表頁面的URL地址,通過瀏覽器開發(fā)者工具判斷新聞列表頁面是否是通過Ajax動態(tài)加載數(shù)據(jù)的;如果是,通過瀏覽器開發(fā)者工具找到Ajax請求的數(shù)據(jù)源;如果不是,就結(jié)束;
判斷模塊:判斷Ajax請求的數(shù)據(jù)源和步驟(101)的編碼方式是否一致,如果不一致,則對數(shù)據(jù)源進行編碼轉(zhuǎn)換,然后,進入步驟(104);如果一致,就直接進入步驟(104);
解析數(shù)據(jù)格式模塊:將數(shù)據(jù)源的格式解析成為新聞列表頁面的后臺語言處理的對象格式或者數(shù)組格式;
封裝模塊:將解析后的數(shù)據(jù)封裝成對象或數(shù)組類型;判斷封裝是否成功,若成功就直接進入輸出模塊;否則將數(shù)據(jù)作為字符串來處理;完成后進入輸出模塊;
輸出模塊:將數(shù)據(jù)對象或數(shù)組類型遍歷輸出列表;利用網(wǎng)絡(luò)爬蟲采集得到的輸出列表;將采集到的數(shù)據(jù)存儲到數(shù)據(jù)庫中。
本發(fā)明的有益效果:
本方案可以解決Ajax等動態(tài)生成內(nèi)容的多種復(fù)雜情況的采集問題,包括跨域調(diào)用,加密腳本數(shù)據(jù)源。另外本方案不僅僅適用于各種復(fù)雜網(wǎng)頁新聞的采集,可以應(yīng)用到微信數(shù)據(jù)的采集和處理。
附圖說明
圖1為本發(fā)明的方法流程圖;
圖2為本發(fā)明的功能模塊圖。
具體實施方式
下面結(jié)合附圖與實施例對本發(fā)明作進一步說明。
如圖1所示,首先需要通過開發(fā)者工具的網(wǎng)絡(luò)請求探測的XHR(XMLHttpRequests)和JavaScript來監(jiān)聽數(shù)據(jù)源地址。通過獲得數(shù)據(jù)源地址來判斷Ajax請求的模式。
如果是能夠直接解析的JSON格式,則直接進行數(shù)據(jù)封裝處理,但實際情況中會遇到如下問題:
情況一:如果是JSONP格式,則需要通過請求頭過濾器把請求頭過濾掉;
情況二:如果返回格式中存在亂碼,則需要通過轉(zhuǎn)碼處理模塊進行轉(zhuǎn)碼處理;
情況三:如果返回格式中出現(xiàn)中英文單雙引號使用不規(guī)范和亂碼問題,需要經(jīng)過特殊字符過濾器進行過濾;
情況四:如果是跨域請求,則需要通過php的cURL方式來模擬來路頁面和host來獲取請求地址的返回數(shù)據(jù)。
情況五:如果請求方式是POST請求的,還要使用php后臺語言的http模塊進行模擬POST請求
情況六:如果Ajax動態(tài)生成內(nèi)容的網(wǎng)頁采用了一些反蜘蛛技術(shù)也可能導(dǎo)致無法獲取數(shù)據(jù)內(nèi)容。需要通過PHP的CURL來偽造來路頁面進行訪問。
經(jīng)過一系列處理,仍不能對數(shù)據(jù)進行夠轉(zhuǎn)換封裝的,就說明返回數(shù)據(jù)的格式與后臺語言的格式不相匹配。只能夠?qū)⒎祷財?shù)據(jù)作為字符串來處理,通過特征值對數(shù)據(jù)進行分割和拼合,形成格式規(guī)范的數(shù)據(jù)。
關(guān)于特殊字符過濾和特征值庫的建立除了基本的常規(guī)過濾還需要在實踐中不斷積累和補充。在數(shù)據(jù)抓取的過程中,還有一些鏈接是動態(tài)的或者是跳轉(zhuǎn)鏈接,這些鏈接有可能是臨時存在的,需要通過解析器的函數(shù)進行預(yù)加載處理,把生成的靜態(tài)鏈接輸出到列表頁當(dāng)中。
可以用后臺語言對這些存儲格式進行結(jié)構(gòu)解析,封裝成為對象或者集合類型,然后遍歷輸出成為列表存儲到服務(wù)器某個地址。這樣一來可以繼續(xù)采用網(wǎng)絡(luò)爬蟲對生成的列表地址進行采集,也可以直接導(dǎo)入到數(shù)據(jù)采集的庫中
Ajax抓取內(nèi)容的主要架構(gòu)如圖2所示。
采集器負責(zé)采集站點數(shù)據(jù)和經(jīng)過解析生成的新聞列表頁面,針對不同情況(上文提到的情況一至情況六)來選擇采集方案。這樣根據(jù)不同情況進行來采集更有利于對不同類型的數(shù)據(jù)更加精細化的采集,大大提高了爬蟲采集數(shù)據(jù)的效率和準(zhǔn)確率。
數(shù)據(jù)過濾器主要是根據(jù)在實際運行中遇到的不同的情況進行格式統(tǒng)一化的過程,包括前面所提到的數(shù)據(jù)字符集的編碼轉(zhuǎn)換,特殊符號的過濾,字符串的規(guī)范化處理。
解析器負責(zé)處理站點訪問的數(shù)據(jù)源,把JSON,XML等格式解析成為可以存儲和讀取的數(shù)據(jù)庫格式。主要是通過分析數(shù)據(jù)地址的數(shù)據(jù)結(jié)構(gòu)來進行聚合數(shù)據(jù)的工作。
數(shù)據(jù)封裝模塊負責(zé)把解析的數(shù)據(jù)封裝成對象通過程序把數(shù)據(jù)遍歷輸出生成列表頁。
上述雖然結(jié)合附圖對本發(fā)明的具體實施方式進行了描述,但并非對本發(fā)明保護范圍的限制,所屬領(lǐng)域技術(shù)人員應(yīng)該明白,在本發(fā)明的技術(shù)方案的基礎(chǔ)上,本領(lǐng)域技術(shù)人員不需要付出創(chuàng)造性勞動即可做出的各種修改或變形仍在本發(fā)明的保護范圍以內(nèi)。