明星不是梦#利用Python进行网站日志分析
?
網(wǎng)站的訪問(wèn)日志是一個(gè)非常重要的文件,通過(guò)分析訪問(wèn)日志,能夠挖掘出很多有價(jià)值的信息。本文介紹如何利用Python對(duì)一個(gè)真實(shí)網(wǎng)站的訪問(wèn)日志進(jìn)行分析,文中將綜合運(yùn)用Python文件操作、字符串處理、列表、集合、字典等相關(guān)知識(shí)點(diǎn)。本文所用的訪問(wèn)日志access_log來(lái)自我個(gè)人的云服務(wù)器,大家可以從文末的附件中下載。?
1.提取指定日期的日志下面是一條典型的網(wǎng)站訪問(wèn)日志,客戶端訪問(wèn)網(wǎng)站中的每個(gè)資源都會(huì)產(chǎn)生一條日志。?
193.112.9.107 - - [25/Jan/2020:06:32:58 +0800] "GET /robots.txt HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0"?
每條日志都由空格分隔為九部分,其中比較重要的是:?
第1部分,193.112.9.107?,客戶端的IP地址。第4部分,[25/Jan/2020:06:32:58 +0800],用戶訪問(wèn)請(qǐng)求發(fā)生的時(shí)間。第5部分,GET /robots.txt HTTP/1.1,客戶端發(fā)來(lái)的HTTP請(qǐng)求報(bào)文首部的第一行信息。這部分采用“請(qǐng)求方法 請(qǐng)求資源 請(qǐng)求協(xié)議”的格式表示,是日志中最重要的部分。“GET /robots.txt HTTP/1.1”表示客戶端以GET方法請(qǐng)求訪問(wèn)服務(wù)器的/robots.txt文件,所使用的HTTP協(xié)議版本為HTTP/1.1。第6部分,?“404”,HTTP響應(yīng)狀態(tài)碼。狀態(tài)碼用于表示用戶的請(qǐng)求是否成功,如果該值為200,則表示用戶的訪問(wèn)成功,否則就可能存在問(wèn)題。一般來(lái)說(shuō),以2開頭的狀態(tài)碼均可以表示用戶的訪問(wèn)成功,以3開頭的狀態(tài)碼表示用戶的請(qǐng)求被頁(yè)面重新定向到了其它位置,以4開頭的狀態(tài)碼表示客戶端遇到了錯(cuò)誤,以5開頭的狀態(tài)碼表示服務(wù)器遇到了錯(cuò)誤。第7部分,“208”,響應(yīng)報(bào)文的大小,單位字節(jié),這個(gè)數(shù)值不包括響應(yīng)報(bào)文的首部。把日志記錄中的這些值加起來(lái)就可以得知服務(wù)器在一定時(shí)間內(nèi)發(fā)送了多少數(shù)據(jù)。第9部分,?"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0",表示客戶端發(fā)來(lái)的HTTP請(qǐng)求報(bào)文中首部“User-Agent”的值,即發(fā)出請(qǐng)求的應(yīng)用程序,通常都是瀏覽器。一個(gè)日志文件中會(huì)包含很多天的日志記錄,而我們通常都是針對(duì)某一天進(jìn)行日志分析,所以首先需要從日志文件中把我們要分析的那一天的日志提取出來(lái)。?
比如要提取1月25日產(chǎn)生的日志,可以執(zhí)行下面的代碼:?
>>> with open('access_log','r') as f1, open('access_log-0125','w') as f2:... ????for line in f1:... ????????????if '25/Jan/2020' in line:... ????????????????????f2.write(line)在這段代碼中,以r讀取模式打開日志文件access_log,作為文件對(duì)象f1。以w寫入模式創(chuàng)建文件access_log-0125,作為文件對(duì)象f2。?
然后遍歷f1中的每一行,并判斷是否包含關(guān)鍵字“25/Jan/2020”,如果有的話,就將這行寫入到f2中。?
這樣就提取出了1月25日的所有日志記錄,并保存到了文件access_log-0125中。下面我們就針對(duì)文件access_log-0125進(jìn)行分析。?
2.統(tǒng)計(jì)PV和UVPV是指PageView,網(wǎng)站的訪問(wèn)請(qǐng)求數(shù)。用戶每次對(duì)網(wǎng)站中的一個(gè)頁(yè)面的請(qǐng)求或訪問(wèn)均被記錄為1個(gè)PV,例如某個(gè)用戶訪問(wèn)了網(wǎng)站中的4個(gè)頁(yè)面,那么PV就+4。而且用戶對(duì)同一頁(yè)面的多次訪問(wèn),PV也是累計(jì)的。?
UV是指UniqueView,網(wǎng)站的獨(dú)立訪客數(shù),訪問(wèn)網(wǎng)站的一個(gè)IP被視為一個(gè)訪客,在同一天內(nèi)相同的IP只被計(jì)算一次。?
因而,我們只要取出每條日志中的IP并統(tǒng)計(jì)數(shù)量,那么就可以得到PV,將IP去重,就可以得到UV。?
執(zhí)行下面的代碼,將每條日志的IP提取出來(lái),并存放到列表ips中。?
>>> ips = []>>> with open('access_log-0125','r') as f:... ????for line in f:... ????????????ips.append(line.split()[0])在這段代碼中,首先定義了一個(gè)空列表ips,然后打開文件access_log-0125并對(duì)其進(jìn)行遍歷,每遍歷一行,就將該行以空格作為分隔符分割成一個(gè)列表,并取出列表中的第一個(gè)元素(也就是IP地址),再追加到列表ips中。?
下面我們只要統(tǒng)計(jì)列表ips的長(zhǎng)度就是PV,將列表元素去重之后,再統(tǒng)計(jì)長(zhǎng)度就是UV。去重這里采用了set()函數(shù),將列表轉(zhuǎn)換為集合,利用Python集合本身的特性,簡(jiǎn)單高效的完成去重操作。?
>>> pv = len(ips)>>> uv = len(set(ips))>>> print(pv,uv)1011 483.統(tǒng)計(jì)網(wǎng)站出錯(cuò)頁(yè)面比例網(wǎng)站的出錯(cuò)比例是很重要的一份數(shù)據(jù),直接關(guān)系到網(wǎng)站的用戶體驗(yàn)。要統(tǒng)計(jì)用戶訪問(wèn)出錯(cuò)的比例,可以通過(guò)統(tǒng)計(jì)每個(gè)請(qǐng)求的HTTP狀態(tài)碼得到,狀態(tài)碼為2xx或3xx的,視為訪問(wèn)正確,狀態(tài)碼為4xx或5xx,則視為訪問(wèn)出錯(cuò)。?
首先可以提取所有頁(yè)面的狀態(tài)碼,并保存到列表中。?
>>> codes = []>>> with open('access_log-0125','r') as f:... ????for line in f:... ????????????codes.append(line.split()[8])再統(tǒng)計(jì)出每種狀態(tài)碼的出現(xiàn)次數(shù),保存到字典中:?
>>> ret = {}>>> for i in codes:... ????if i not in ret:... ????????????ret[i] = codes.count(i)... >>> >>> ret{'200': 192, '404': 796, '"-"': 4, '400': 13, '403': 3, '401': 2, '405': 1}上面這段代碼用到了字典,這里是對(duì)存放狀態(tài)碼的列表codes進(jìn)行遍歷,從中取出狀態(tài)碼作為字典的鍵,并統(tǒng)計(jì)這種狀態(tài)碼在列表codes中出現(xiàn)的次數(shù),作為字典的值。?
如果要統(tǒng)計(jì)404頁(yè)面的比例,可以執(zhí)行下面的代碼:?
>>> ret['404']/sum(ret.values())0.7873392680514342在這段代碼中,ret['404']表示從字典ret中取出鍵為‘404’的元素的值,也就是404狀態(tài)碼的個(gè)數(shù)。ret.values()表示取出字典中所有元素的值,再用sum()函數(shù)求和,得到所有狀態(tài)碼的總數(shù)量。兩者的比值也就是錯(cuò)誤頁(yè)面的比例了。?
從結(jié)果中可以看出,我這個(gè)網(wǎng)站的頁(yè)面出錯(cuò)比例特別高,竟然達(dá)到了78.7%,如果是一個(gè)正常網(wǎng)站,這肯定是有問(wèn)題的。但我這并不是一個(gè)公開網(wǎng)站,也沒有什么有價(jià)值的頁(yè)面,因而大部分訪問(wèn)日志其實(shí)都是由一些漏洞掃描軟件產(chǎn)生的,這也提醒我們,隨時(shí)都有人在對(duì)我們線上的網(wǎng)站進(jìn)行著各種掃描測(cè)試。?
4.統(tǒng)計(jì)網(wǎng)站熱門資源下面我們繼續(xù)統(tǒng)計(jì)出每個(gè)頁(yè)面的用戶訪問(wèn)量,并進(jìn)行排序。?
首先仍然是遍歷日志文件,取出用戶訪問(wèn)的所有頁(yè)面,并保存到列表中:?
>>> webs = []>>> with open('access_log-0125','r') as f:... ????for line in f:... ????????????webs.append(line.split()[6])接著再統(tǒng)計(jì)出每個(gè)頁(yè)面的訪問(wèn)次數(shù),并存放到字典中:?
>>> counts = {}>>> for i in webs:... ????if i not in counts:... ????????????counts[i] = webs.count(i)...按頁(yè)面的訪問(wèn)量降序排序:?
>>> sorted(counts.items(),key=lambda x:x[1],reverse=True)[('/', 175), ('/robots.txt', 25), ('/phpinfo.php', 6), ('/Admin13790d6a/Login.php', 4), ……為了更好地理解上面這個(gè)sorted()函數(shù)的用法,下面舉例說(shuō)明。比如我們定義一個(gè)名叫services的字典,如果直接用sorted()函數(shù)對(duì)這個(gè)字典排序,默認(rèn)是按照鍵進(jìn)行升序排序。為了顯示字典中的所有內(nèi)容,可以使用items()方法,此時(shí),字典中的每個(gè)鍵值對(duì)會(huì)被組合成一個(gè)元組,并且默認(rèn)是按照元組中的第一個(gè)元素,也就是字典的鍵進(jìn)行排序的。?
>>> services = {'http':80,'ftp':21,'https':443,'ssh':22}>>> sorted(services)['ftp', 'http', 'https', 'ssh']>>> sorted(services.items())[('ftp', 21), ('http', 80), ('https', 443), ('ssh', 22)]如果希望按照字典中的值進(jìn)行排序,也就是要按照元組中的第二個(gè)元素排序,可以用key參數(shù)指定一個(gè)lambda表達(dá)式,以每個(gè)元組中的第二個(gè)元素作為關(guān)鍵字。?
>>> sorted(services.items(),key=lambda x:x[1])[('ftp', 21), ('ssh', 22), ('http', 80), ('https', 443)]所以這也就解釋了之前那個(gè)sorted()函數(shù)的含義。至于lambda表達(dá)式,其實(shí)就是一個(gè)根據(jù)需要可以隨時(shí)定義使用的小函數(shù),“l(fā)ambda x:x[1]”,冒號(hào)左側(cè)的x是函數(shù)要處理的參數(shù),冒號(hào)右側(cè)的表達(dá)式是函數(shù)要執(zhí)行的操作,最后再將這個(gè)表達(dá)式的結(jié)果返回。?
?云專線接入兩側(cè)的地址規(guī)劃,IP地址不能沖突,而且必須是私網(wǎng)地址,如果用戶側(cè)存在公網(wǎng)地址,還需要提交工單進(jìn)行配置,一般不建議這樣做。
總結(jié)
以上是生活随笔為你收集整理的明星不是梦#利用Python进行网站日志分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SCCM管理 - 更新部署
- 下一篇: python并发入门(part5 eve