利用 Python 分析網(wǎng)站訪問日志文件

場景介紹

有一個前臺的 Web 應(yīng)用,框架會記錄訪問日志,并定期歸檔,存儲在特定的目錄解幼,目錄格式如下:
/onlinelogs/應(yīng)用名/環(huán)境名/年/月/日/小時/,例如 /onlinelogs/<app_name>/Prod/2018/08/07/01包警。
在該目錄下:

  • 訪問日志文件可能有多個撵摆,文件名以 access-log 開頭
  • 已壓縮為 .gz 文件,并且只讀害晦,例如:
    訪問日志文件
  • 訪問日志文件中特铝,有部分行是記錄 HTTP 請求的,格式如下所示:
    • 從中可以看出壹瘟,請求的目標(biāo)資源鲫剿,響應(yīng)碼,客戶端信息
222.67.225.134 - - [04/Aug/2018:01:16:44 +0000] "GET /?ref=as_cn_ags_resource_tb&ck-tparam-anchor=123067 HTTP/1.1" 200 7798 "https://gs.amazon.cn/resources.html/ref=as_cn_ags_hnav1_re_class" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15"

222.67.225.134 - - [04/Aug/2018:01:16:54 +0000] "GET /tndetails?tnid=3be3f34dee8a4bf08baa072a478fc882 HTTP/1.1" 200 9152 "https://gs.amazon.cn/sba/?ref=as_cn_ags_resource_tb&ck-tparam-anchor=123067&tnm=Offline" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15"

222.67.225.134 - - [04/Aug/2018:01:17:37 +0000] "GET /paymentinfo?oid=10763561&rtxref=164f9f8e2b5e4d7790d02d1220eae435 HTTP/1.1" 200 7138 "https://gs.amazon.cn/sba/paymentinfo?oid=10763561&rtxref=164f9f8e2b5e4d7790d02d1220eae435" "Mozilla/5.0 (Linux; Android 8.1.0; DE106 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 AliApp(DingTalk/4.5.3) com.alibaba.android.rimet/0 Channel/10006872 language/zh-CN"

222.67.225.134 - - [04/Aug/2018:01:17:39 +0000] "GET /paymentinfo?oid=10763561&rtxref=164f9f8e2b5e4d7790d02d1220eae435 HTTP/1.1" 200 7138 "https://gs.amazon.cn/sba/paymentinfo?oid=10763561&rtxref=164f9f8e2b5e4d7790d02d1220eae435" "Mozilla/5.0 (Linux; Android 8.1.0; DE106 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 AliApp(DingTalk/4.5.3) com.alibaba.android.rimet/0 Channel/10006872 language/zh-CN"

222.67.225.134 - - [04/Aug/2018:01:17:40 +0000] "GET /paymentinfo?oid=10763561&rtxref=164f9f8e2b5e4d7790d02d1220eae435 HTTP/1.1" 200 7138 "https://gs.amazon.cn/sba/paymentinfo?oid=10763561&rtxref=164f9f8e2b5e4d7790d02d1220eae435" "Mozilla/5.0 (Linux; Android 8.1.0; DE106 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 AliApp(DingTalk/4.5.3) com.alibaba.android.rimet/0 Channel/10006872 language/zh-CN"

140.243.121.197 - - [04/Aug/2018:01:17:41 +0000] "GET /?ref=as_cn_ags_resource_tb HTTP/1.1" 302 - "https://gs.amazon.cn/resources.html/ref=as_cn_ags_hnav1_re_class" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"

分析目標(biāo)

  • 記錄不同時間段的訪問量
  • 統(tǒng)計 PC 和 Mobile 端訪問量
  • 統(tǒng)計不同頁面的訪問量

基本思想:

  • 由于原日志文件已壓縮稻轨,并且只讀灵莲,所以需要創(chuàng)建一個臨時目錄 /tmp/logs/unziped_logs 來解壓縮日志文件
  • 利用正則表達(dá)式 ^access\-log.*gz+$ 過濾日志文件
  • 利用正則表達(dá)式 ^.*GET (.*) HTTP.*$ 過濾日志文件中的 HTTP 請求
  • 通過日志行是否有 Mobile 來判斷客戶端

代碼如下:(部分內(nèi)容屏蔽)

#!/usr/bin/python3

import os
import os.path
import re
import shutil
import gzip
from collections import defaultdict

# define the ziped and unziped log file directorys
source_logs_dir = '/onlinelogs/<app_name>/Prod'
unziped_logs_dir = '/tmp/logs/unziped_logs'

# clear the unziped log file directory if exists
if os.path.exists(unziped_logs_dir):
    shutil.rmtree(unziped_logs_dir)

# create the unziped log file directory
os.mkdir(unziped_logs_dir)

# regex used to match target log file name
log_file_name_regex = re.compile(r'^access\-log.*gz+$')

# regex used to match HTTP request
http_request_regex = re.compile(r'^.*GET.*gs.amazon.cn')

# regex used to match request page
request_page_regex = re.compile(r'^.*GET (.*) HTTP.*$')
# request_page_regex = re.compile(r'^.*GET (.*)\?.*$')

# a dictionary to store the HTTP request count of each day
day_count = defaultdict(int)

# a dictionary to store the count of each device (PC or Mobile)
device_count = defaultdict(int)
device_count['PC'] = 0
device_count['Mobile'] = 0

# a dictionary to store the count of each request page
request_page_count = defaultdict(int)

for root, dirs, files in os.walk(source_logs_dir):
    for name in files:
        # find the target log files
        if log_file_name_regex.search(name):
            # parst the day
            day = root[-13:-3]

            # copy the target log files
            shutil.copyfile(os.path.join(root, name), os.path.join(unziped_logs_dir, name))

            # unzip the log files
            unziped_log_file = gzip.open(os.path.join(unziped_logs_dir, name), 'rb')

            http_request_count = 0
            pc_count = 0
            mobile_count = 0
            for line in unziped_log_file:
                if(http_request_regex.search(line)):
                    # parse the request page
                    regex_obj = request_page_regex.search(line)
                    request_page = regex_obj.group(1)
                    # remove params of the request page
                    if('?' in request_page):
                        request_page = request_page[:request_page.find('?')]

                    http_request_count = http_request_count + 1

                    if('Mobile' in line):
                        mobile_count = mobile_count + 1
                    else:
                        pc_count = pc_count + 1

                    # update the count of each request page
                    if(request_page in request_page_count):
                                        request_page_count[request_page] = request_page_count[request_page] + 1
                                else:
                                        request_page_count[request_page] = 1

            # update the HTTP request count of each day
            if(day in day_count):
                day_count[day] = day_count[day] + http_request_count
            else:
                day_count[day] = http_request_count

            # update the count of each device (PC or Mobile)
            device_count['PC'] = device_count['PC'] + pc_count
            device_count['Mobile'] = device_count['Mobile'] + mobile_count

            # remvoe the original zip log files
            os.remove(os.path.join(unziped_logs_dir, name))

# print the HTTP request count of each day
total = 0
print 'HTTP request count of each day'
for day, count in sorted(day_count.items()):
    print day, ':', count
    total = total + count
print 'Total = ', total

print '###############################'

total = 0
print 'count of each device (PC or Mobile)'
# print the count of each device (PC or Mobile)
for device, count in sorted(device_count.items()):
        print device, ':', count
    total = total + count
print 'Total = ', total

print '###############################'

total = 0
print 'count of each request page'
# print the count of each request page
for request_page, count in sorted(request_page_count.items()):
        print request_page, ':', count
    total = total + count
print 'Total = ', total
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市殴俱,隨后出現(xiàn)的幾起案子政冻,更是在濱河造成了極大的恐慌枚抵,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件明场,死亡現(xiàn)場離奇詭異汽摹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)苦锨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門逼泣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逆屡,你說我怎么就攤上這事圾旨□馓郑” “怎么了魏蔗?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長痹筛。 經(jīng)常有香客問我莺治,道長,這世上最難降的妖魔是什么帚稠? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任谣旁,我火速辦了婚禮,結(jié)果婚禮上滋早,老公的妹妹穿的比我還像新娘榄审。我一直安慰自己,他們只是感情好杆麸,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布搁进。 她就那樣靜靜地躺著,像睡著了一般昔头。 火紅的嫁衣襯著肌膚如雪饼问。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天揭斧,我揣著相機(jī)與錄音莱革,去河邊找鬼。 笑死讹开,一個胖子當(dāng)著我的面吹牛盅视,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播旦万,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼左冬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纸型?” 一聲冷哼從身側(cè)響起拇砰,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤梅忌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后除破,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牧氮,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年瑰枫,在試婚紗的時候發(fā)現(xiàn)自己被綠了踱葛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡光坝,死狀恐怖尸诽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盯另,我是刑警寧澤性含,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站鸳惯,受9級特大地震影響商蕴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芝发,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一绪商、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辅鲸,春花似錦格郁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至绵患,卻和暖如春雾叭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背落蝙。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工织狐, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筏勒。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓移迫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親管行。 傳聞我的和親對象是個殘疾皇子厨埋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時,會觸發(fā)此異常捐顷。 O...
    我想起個好名字閱讀 5,256評論 0 9
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 31,912評論 2 89
  • 常用配置指令說明 1. ServerRoot:服務(wù)器的基礎(chǔ)目錄荡陷,一般來說它將包含conf/和logs/子目錄雨效,其它...
    小僧有禮了閱讀 4,489評論 0 5
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)废赞,斷路器徽龟,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 早已過了浪蕩不羈的年紀(jì),時光磨平了我年少時的棱角唉地,我懊悔的是据悔,你再也看不到,我的男孩耘沼,祝你一生平安喜樂极颓。 一別兩...
    安念kk閱讀 258評論 1 3