邢羽琪, 楊 檉
(云南民族大學(xué)數(shù)學(xué)與計(jì)算機(jī)科學(xué)學(xué)院, 云南 昆明 650500)
互聯(lián)網(wǎng)經(jīng)濟(jì)時(shí)代,數(shù)據(jù)既是基礎(chǔ)性資源也是戰(zhàn)略性資源,更是重要的生產(chǎn)力,對(duì)各行各業(yè)的發(fā)展都有著重要影響[1]。在大數(shù)據(jù)架構(gòu)中,網(wǎng)絡(luò)爬蟲(chóng)技術(shù)作為數(shù)據(jù)獲取的重要技術(shù)近年來(lái)得以快速發(fā)展。另一方面,Ajax(Asynchronous Javascript And XML,異步的JavaScript和XML)技術(shù)在Web站點(diǎn)中的使用卻增加了數(shù)據(jù)采集的難度。Ajax可以實(shí)現(xiàn)瀏覽器與服務(wù)器的異步通信,提升Web站點(diǎn)的響應(yīng)能力。XML是一種描述、存儲(chǔ)、傳輸數(shù)據(jù)的標(biāo)記語(yǔ)言。Ajax通過(guò)使用XMLHttpRequest對(duì)象從服務(wù)器異步請(qǐng)求數(shù)據(jù),并將響應(yīng)數(shù)據(jù)以XML格式返回。Ajax技術(shù)可以在不刷新整個(gè)頁(yè)面的情況下更新局部?jī)?nèi)容,許多網(wǎng)站采用了動(dòng)態(tài)生成頁(yè)面內(nèi)容的方式。這使得爬取網(wǎng)頁(yè)變得更復(fù)雜,網(wǎng)頁(yè)中的內(nèi)容可能在用戶(hù)與頁(yè)面交互過(guò)程中動(dòng)態(tài)加載或改變。爬蟲(chóng)需要解析JavaScript代碼,并模擬用戶(hù)與頁(yè)面的交互過(guò)程,以獲取最終的完整內(nèi)容。
如今,大部分Web站點(diǎn)都采用Ajax動(dòng)態(tài)請(qǐng)求、異步刷新方式生成數(shù)據(jù),使得采取Python爬蟲(chóng)爬取靜態(tài)網(wǎng)頁(yè)的方法難以直接提取動(dòng)態(tài)網(wǎng)頁(yè)數(shù)據(jù)[2-3]。本文在前人研究方法的基礎(chǔ)上,依據(jù)靜態(tài)網(wǎng)址信息構(gòu)造動(dòng)態(tài)請(qǐng)求鏈接,以爬取某購(gòu)物網(wǎng)站評(píng)論數(shù)據(jù)的過(guò)程為例,詳細(xì)描述了構(gòu)造動(dòng)態(tài)網(wǎng)頁(yè)URL的全過(guò)程,可為Ajax動(dòng)態(tài)數(shù)據(jù)采集技術(shù)的研究提供參考。
JavaScript(通常縮寫(xiě)為JS)是一種高級(jí)、解釋型的編程語(yǔ)言,它的解釋器被稱(chēng)為JavaScript引擎,是瀏覽器的一部分,廣泛用于HTML網(wǎng)頁(yè),增強(qiáng)了網(wǎng)頁(yè)的互動(dòng)性。通過(guò)對(duì)JavaScript源代碼進(jìn)行混淆加密,既可以做到網(wǎng)頁(yè)打開(kāi)的速度和加密前相差不大,又可以做到加密結(jié)果不可逆,提高數(shù)據(jù)的安全性。但是,對(duì)于爬蟲(chóng)技術(shù)而言,JS加密的應(yīng)用會(huì)成為影響數(shù)據(jù)分析人員采集數(shù)據(jù)的瓶頸。當(dāng)前,JS逆向技術(shù)是應(yīng)對(duì)以上瓶頸的有效措施[4]。JS逆向技術(shù)實(shí)質(zhì)上是根據(jù)結(jié)果向前推導(dǎo),分析構(gòu)造URL所需的參數(shù),找出后臺(tái)參數(shù)生成原理(即參數(shù)加密過(guò)程),動(dòng)態(tài)模擬瀏覽器JS生成結(jié)果,并最終獲取目標(biāo)數(shù)據(jù)的過(guò)程。實(shí)施JS逆向技術(shù)的難點(diǎn)是需要在被改寫(xiě)的源代碼中破解加密算法、拆解相關(guān)參數(shù)?;诖?本文以某購(gòu)物網(wǎng)站商品評(píng)論頁(yè)面為例,采用JS逆向技術(shù),使用Python程序還原參數(shù)加密過(guò)程,構(gòu)造完整目標(biāo)網(wǎng)頁(yè)的URL信息,實(shí)現(xiàn)Python環(huán)境下的JS逆向技術(shù)爬取商品評(píng)論數(shù)據(jù),同時(shí)進(jìn)行簡(jiǎn)單的數(shù)據(jù)挖掘,使整個(gè)數(shù)據(jù)分析過(guò)程完整。
爬蟲(chóng)可以分為搜索引擎網(wǎng)絡(luò)爬蟲(chóng)、基于Agent的網(wǎng)絡(luò)爬蟲(chóng)、遷移的網(wǎng)絡(luò)爬蟲(chóng)、通用網(wǎng)絡(luò)爬蟲(chóng)和聚焦爬蟲(chóng)等[5]。根據(jù)要爬取的Web頁(yè)面的存在方式,又可將爬蟲(chóng)分為表層網(wǎng)絡(luò)爬蟲(chóng)和深層網(wǎng)絡(luò)爬蟲(chóng)。表層網(wǎng)絡(luò)爬蟲(chóng)通常用于爬取以表層網(wǎng)頁(yè)(即靜態(tài)網(wǎng)頁(yè))為主的Web站點(diǎn)。本文的目標(biāo)購(gòu)物網(wǎng)站需要用戶(hù)登錄、提交關(guān)鍵詞才能動(dòng)態(tài)生成相應(yīng)頁(yè)面,是典型的由深層網(wǎng)頁(yè)構(gòu)成的網(wǎng)站,需要使用深層網(wǎng)絡(luò)爬蟲(chóng)技術(shù),動(dòng)態(tài)構(gòu)造URL請(qǐng)求信息,才能批量爬取指定數(shù)量的商品評(píng)論信息?;赑ython的JS逆向技術(shù)爬蟲(chóng)算法流程圖如圖1所示。
圖1 基于Python的JS逆向技術(shù)爬蟲(chóng)算法流程圖Fig.1 Flow chart of Python-based JS reverse technology crawler algorithm
2.1.1 查看URL構(gòu)成
靜態(tài)網(wǎng)頁(yè)是指不應(yīng)用程序而直接或間接制作成HTML的網(wǎng)頁(yè),每一個(gè)頁(yè)面都有一個(gè)固定的URL地址,可以使用Python代碼直接獲取網(wǎng)頁(yè)的URL和相應(yīng)的HTML信息。動(dòng)態(tài)網(wǎng)頁(yè)一般使用腳本語(yǔ)言(PHP、ASP等)將網(wǎng)站內(nèi)容存儲(chǔ)于數(shù)據(jù)庫(kù)中,由于Python無(wú)法直接獲取URL動(dòng)態(tài)鏈接,因此爬取內(nèi)容時(shí)需要?jiǎng)討B(tài)構(gòu)造URL鏈接。
在某購(gòu)物網(wǎng)站商品評(píng)論頁(yè)面,利用F12開(kāi)發(fā)者工具,選擇Network模塊,再篩選XHR請(qǐng)求,刷新網(wǎng)頁(yè)并不斷下拉頁(yè),使開(kāi)發(fā)者工具可以抓取到多個(gè)動(dòng)態(tài)Ajax請(qǐng)求,選中其中一個(gè)重點(diǎn)查看URL的請(qǐng)求頭(圖2)。
圖2 獲取動(dòng)態(tài)Ajax請(qǐng)求并查看URLFig.2 Obtaining dynamic Ajax requests and viewing URLs
2.1.2 確定請(qǐng)求頭中的加密參數(shù)
在動(dòng)態(tài)URL構(gòu)造過(guò)程中,URL參數(shù)的變化信息一般可以在相關(guān)靜態(tài)URL及源代碼中尋找。通過(guò)多次請(qǐng)求分析,利用靜態(tài)的URL地址的變化構(gòu)造動(dòng)態(tài)鏈接,從而實(shí)現(xiàn)數(shù)據(jù)采集程序自動(dòng)對(duì)動(dòng)態(tài)網(wǎng)頁(yè)的爬取。
對(duì)比多個(gè)頁(yè)面URL內(nèi)容,最終確定“t”“sign”“data”三個(gè)動(dòng)態(tài)變化且對(duì)采集有效的參數(shù),觀察多次請(qǐng)求的返回結(jié)果,發(fā)現(xiàn)參數(shù)“t”為13位時(shí)間戳,“sign”為加密參數(shù),“data”為商品查詢(xún)參數(shù)。由此,進(jìn)入本研究的難點(diǎn)環(huán)節(jié),即逆向破解參數(shù)的加密方式以及構(gòu)造動(dòng)態(tài)URL。多個(gè)頁(yè)面URL參數(shù)對(duì)比內(nèi)容如圖3所示。
2.1.3 推導(dǎo)參數(shù)“sign”加密方式
推導(dǎo)參數(shù)“sign”的加密方式,具體步驟如下。
步驟1:在控制臺(tái)中使用length()函數(shù)查看參數(shù)“sign”的長(zhǎng)度,結(jié)果顯示32位,由此初步推測(cè)該網(wǎng)站采用MD5加密算法。
步驟2:使用全局搜索查找“sign”,返回21條相關(guān)數(shù)據(jù),發(fā)現(xiàn)返回的js文件中多次出現(xiàn)了“sign”,經(jīng)逐一排查,排除若干干擾項(xiàng),最終在mtop.js文件中追溯到參數(shù)“sign”。
步驟3:查看mtop.js文件的源代碼,從中篩選出純參數(shù)數(shù)據(jù),在其位置打上斷點(diǎn)并進(jìn)行編譯。斷點(diǎn)查看參數(shù)“sign”加密方式如圖4所示。
步驟4:查看運(yùn)行過(guò)程得知,構(gòu)成參數(shù)“sign”的信息包括參數(shù)“i”“d.token”“g”“c.data”和函數(shù)“h”,對(duì)其逐一分析發(fā)現(xiàn)。參數(shù)“i”為實(shí)時(shí)生成的13位時(shí)間戳信息;參數(shù)“g”由“||”語(yǔ)法得出,“c”是參數(shù)對(duì)象,因此“g”為請(qǐng)求頭中的appKey,是一個(gè)定值;參數(shù)“c.data”與參數(shù)“g”同理,也是參數(shù)對(duì)象的“data”字段;參數(shù)“d.token”是放在cookie信息中的m_h5_tk值。對(duì)于函數(shù)“h”,前文已根據(jù)加密結(jié)果為32位信息推測(cè)該網(wǎng)站使用的是MD5加密算法,現(xiàn)將上述內(nèi)容拼接的原始參數(shù)使用MD5在線(xiàn)加密器計(jì)算結(jié)果,同時(shí)使用斷點(diǎn)測(cè)試程序查看加密后的結(jié)果,對(duì)比兩者發(fā)現(xiàn)結(jié)果一致,驗(yàn)證了之前函數(shù)“h”為MD5加密函數(shù)的推測(cè)。對(duì)比函數(shù)“h”與MD5在線(xiàn)加密器結(jié)果如圖5所示。
圖5 對(duì)比函數(shù)“h”與MD5在線(xiàn)加密器結(jié)果Fig.5 Online encryptor results comparison of “h” function and MD5
步驟5:根據(jù)斷點(diǎn)運(yùn)行過(guò)程,逐步查看各參數(shù)構(gòu)成方式,據(jù)此拼接完整的參數(shù)“sign”。
2.1.4 模擬生成URL
分析URL的構(gòu)成,使用Python編寫(xiě)程序,具體為自定義時(shí)間戳和隨機(jī)數(shù),生成并拼接“t”“sign”“data”參數(shù),構(gòu)造完整的URL信息,對(duì)整個(gè)訪(fǎng)問(wèn)請(qǐng)求進(jìn)行模擬并獲得響應(yīng)。將上述參數(shù)拼接成完整的URL,用requests的get/post方法發(fā)送請(qǐng)求并接收數(shù)據(jù)res=requests.get(url=url,headers=headers).content,返回得到JSON格式數(shù)據(jù)。
JSON作為一種輕量級(jí)的數(shù)據(jù)交換格式,結(jié)構(gòu)簡(jiǎn)單緊湊,是互聯(lián)網(wǎng)上常用的數(shù)據(jù)傳輸與交換格式。JSON有兩種結(jié)構(gòu)形式,一是鍵值對(duì)形式,以“{”開(kāi)始,以“}”結(jié)束,中間部分由0個(gè)或者多個(gè)“,”分隔的鍵值對(duì)構(gòu)成,是一個(gè)無(wú)序的“‘名稱(chēng)/值’對(duì)”集合;二是數(shù)組形式,以“[”開(kāi)始,以“]”結(jié)束,是一個(gè)值的有序集合。本次爬取返回的結(jié)果是以上兩種情況的嵌套,需要通過(guò)分析找到所需數(shù)據(jù)所在層次,即res[′data′][′module′][′reviewVOList′]。之后,可利用Python爬蟲(chóng)解析庫(kù)逐條分別提取評(píng)論用戶(hù)、商品詳情、評(píng)論時(shí)間及評(píng)論內(nèi)容等信息。評(píng)論頁(yè)面JSON代碼的嵌套關(guān)系如圖6所示。
圖6 評(píng)論頁(yè)面JSON代碼的嵌套關(guān)系Fig.6 Nested relationship of JSON code for comment pages
使用pip安裝第三方庫(kù),以及對(duì)應(yīng)的數(shù)據(jù)庫(kù)軟件,可以將結(jié)果保存至MySQL、MongoDB等數(shù)據(jù)庫(kù)中。本文選擇自定義saveCsv()函數(shù),將爬取結(jié)果保存至csv文件中,實(shí)現(xiàn)該步驟的代碼段如下。
def saveCsv(datas):
with open(′result.csv′,′a′,newline=″)as f:
csvwriter = csv.writer(f)
csvwriter.writerow([datas[′uid′],datas[′評(píng)論用戶(hù)′],datas[′評(píng)論時(shí)間′],datas[′評(píng)論內(nèi)容′]])
按照上述流程,本文共獲取該網(wǎng)站樂(lè)高商品數(shù)據(jù)356條,爬取數(shù)據(jù)樣本示例如表1所示。
表1 爬取數(shù)據(jù)樣本示例
2.5.1 應(yīng)對(duì)反爬
(1)請(qǐng)求頭。爬蟲(chóng)可以在程序中添加請(qǐng)求頭信息達(dá)到偽裝成瀏覽器的目的,從而實(shí)現(xiàn)反反爬機(jī)制,程序?yàn)閞es=requests.get(url=url,headers=headers),其中url為請(qǐng)求網(wǎng)頁(yè)地址,headers為開(kāi)發(fā)者工具中獲取的“User-Agent”請(qǐng)求頭信息[6]。
(2)Cookie。部分需要登錄的網(wǎng)站,需要添加cookie信息。由于cookie具有生命周期,因此本研究在程序設(shè)計(jì)上采用分部爬取(20頁(yè)信息為一個(gè)部分)方式,爬取間隔更換cookie信息,防止反爬。
(3)Token。Token實(shí)質(zhì)是訪(fǎng)問(wèn)資源的憑證,一般是用戶(hù)通過(guò)用戶(hù)名和密碼登錄成功后,服務(wù)器將登錄憑證作為數(shù)字簽名,加密之后得到的字符串即token。查找源代碼發(fā)現(xiàn)token就是放在cookie中的m_h5_tk值,并且token值也存在生命周期,需要定期更換。
2.5.2 遵守robot協(xié)議
在使用爬蟲(chóng)進(jìn)行數(shù)據(jù)采集的過(guò)程中,應(yīng)注意遵守對(duì)方網(wǎng)站robot協(xié)議的規(guī)定,本文在實(shí)驗(yàn)過(guò)程中充分考慮到這一點(diǎn),在采集程序加入time.sleep(10)語(yǔ)句用于將爬蟲(chóng)訪(fǎng)問(wèn)的頻率近似到類(lèi)人水平[3]。
由于商品的評(píng)論內(nèi)容是日??谡Z(yǔ)評(píng)論,所以文本存在語(yǔ)言隨性、表達(dá)多樣、噪聲大、語(yǔ)言不唯一等情況,進(jìn)行數(shù)據(jù)清洗可以讓評(píng)論文本更加簡(jiǎn)潔明了。因此,本文對(duì)“評(píng)論內(nèi)容”屬性列進(jìn)行去除空格、網(wǎng)址、日期及時(shí)間等處理。
中文分詞是中文文本處理的一個(gè)基礎(chǔ)步驟,也是中文人機(jī)自然語(yǔ)言交互的基礎(chǔ)模塊,在進(jìn)行中文自然語(yǔ)言處理時(shí),通常需要先進(jìn)行分詞。jieba分詞支持三種分詞模式,即精確模式、全模式、搜索引擎模式[7]。精確模式是將句子精確地切分,更適用于文本分析;全模式是把句子中所有可以成詞的詞語(yǔ)掃描出來(lái),較為煩瑣;搜索引擎模式是在精確模式的基礎(chǔ)上,對(duì)長(zhǎng)詞再次切分,更適用于搜索引擎數(shù)據(jù)的分詞?;诒狙芯恐信廊〉臄?shù)據(jù)全部為文本數(shù)據(jù),因此采用精確模式j(luò)ieba.lcut( )對(duì)評(píng)論內(nèi)容進(jìn)行分詞,為情感分析環(huán)節(jié)奠定基礎(chǔ)。
SnowNLP是一個(gè)功能強(qiáng)大的中文文本處理庫(kù),它具有中文分詞、詞性標(biāo)注、情感分析、文本分類(lèi)、關(guān)鍵字/摘要提取、TF/IDF、文本相似度等諸多功能[8]。SnowNLP利用機(jī)器學(xué)習(xí)和自然語(yǔ)言處理技術(shù),對(duì)文本進(jìn)行情感分析,將其歸類(lèi)為積極、消極或中性等情感類(lèi)別,并給出相應(yīng)的情感得分emotion。emotion是一個(gè)介于0到1的實(shí)數(shù),其中0表示強(qiáng)烈的消極情感,1表示強(qiáng)烈的積極情感,中間的值表示中性或較弱的情感傾向。
3.3.1 情感得分
使用SnowNLP模塊對(duì)評(píng)論進(jìn)行情感打分,得分示例如表2 所示。由SnowNLP模塊計(jì)算可知,emotion的平均值約為0.61,中位數(shù)約為0.81,單純從評(píng)論情感分來(lái)看,得出好評(píng)多于差評(píng)的結(jié)果。
表2 SnowNLP情感得分示例
3.3.2 繪制情感分直方圖
使用matplotlib.pyplot庫(kù)繪制情感分直方圖(圖7)。
圖7 情感分直方圖Fig.7 Histogram of sentiment score
由圖7可以看出,大部分用戶(hù)的評(píng)論情感分較高,介于0.8~1.0,反映出用戶(hù)對(duì)于樂(lè)高銷(xiāo)售的整體反響較好,態(tài)度積極向上;但也存在部分得分相對(duì)較低評(píng)論,并且絕大部分得分介于0.0~0.2,這也對(duì)商家起到了警示作用,需要注重用戶(hù)反饋的信息,及時(shí)采取措施糾正或完善??傮w來(lái)說(shuō),評(píng)論數(shù)據(jù)情感分布兩級(jí)分化較為嚴(yán)重,提醒商家需要調(diào)整銷(xiāo)售策略,做到揚(yáng)長(zhǎng)避短。
3.3.3 劃分積極評(píng)論
根據(jù)情感評(píng)分模型的特點(diǎn),觀察得到當(dāng)評(píng)論為“不錯(cuò)”時(shí),輸出得分為0.861 213;評(píng)論為“好”時(shí),輸出得分為0.655 863;評(píng)論為“一般”時(shí),輸出得分為0.526 233。根據(jù)多條輸出結(jié)果,判定情感傾向的標(biāo)準(zhǔn)是得分大于等于0.6時(shí),可認(rèn)定為積極態(tài)度評(píng)論,統(tǒng)計(jì)得到積極評(píng)論數(shù)量為235條且占比約為66%,繪制其積極評(píng)論占比圖如圖8所示。
圖8 積極評(píng)論占比圖Fig.8 Proportion of positive comments
根據(jù)圖8得知大部分用戶(hù)對(duì)樂(lè)高商品較為滿(mǎn)意,可進(jìn)一步挖掘積極態(tài)度的評(píng)論,探究用戶(hù)評(píng)論高頻詞,幫助商家調(diào)整銷(xiāo)售策略,做到優(yōu)勢(shì)最大化。
3.3.4 提取評(píng)論高頻詞
對(duì)上述劃分為積極態(tài)度的評(píng)論內(nèi)容進(jìn)行分詞并按詞頻統(tǒng)計(jì),提取評(píng)論中出現(xiàn)的高頻詞,并繪制評(píng)論高頻詞云圖(圖9)。
圖9 評(píng)論高頻詞云圖Fig.9 Word cloud diagram of high frequency comments
根據(jù)詞頻展示結(jié)果,可以清楚地看到“喜歡”“不錯(cuò)”等字眼占據(jù)評(píng)論數(shù)據(jù)的主要地位,“快遞”“盒子”“包裝”等詞匯顯示出樂(lè)高玩具的用戶(hù)比較注重快遞包裝外觀,樂(lè)高銷(xiāo)售商可在這個(gè)方面進(jìn)一步做提升,獲得更高的用戶(hù)滿(mǎn)意度。
目前,JS逆向技術(shù)儼然成為爬蟲(chóng)領(lǐng)域的重要探索工具:首先通過(guò)對(duì)網(wǎng)頁(yè)的結(jié)構(gòu)進(jìn)行分析,找出請(qǐng)求信息中的加密參數(shù);其次通過(guò)斷點(diǎn)技術(shù),尋找有用參數(shù)的加密流程;最后模擬瀏覽器動(dòng)態(tài)構(gòu)造請(qǐng)求信息獲得數(shù)據(jù)。與傳統(tǒng)的爬蟲(chóng)技術(shù)相比,整個(gè)爬取過(guò)程的復(fù)雜度和難度都增加了。本文在前人研究的基礎(chǔ)上,以某購(gòu)物網(wǎng)站樂(lè)高商品評(píng)論數(shù)據(jù)的爬取過(guò)程為例,基于Python語(yǔ)言采用JS逆向技術(shù),詳細(xì)描述JS逆向技術(shù)流程,批量爬取了多個(gè)商品的評(píng)論數(shù)據(jù),并對(duì)其結(jié)果進(jìn)行SnowNLP情感分析、提取評(píng)論高頻詞,挖掘樂(lè)高商品銷(xiāo)售可能存在的優(yōu)勢(shì)與不足。所使用的爬蟲(chóng)算法及具體實(shí)踐對(duì)使用了Ajax和JS加密的數(shù)據(jù)獲取有一定的參考作用。