2017-10-07 1 views
1

Je suis en train d'écrire un script qui analyse de gros fichiers (apache) de 400 Mo dans une table pandas.Comment accélérer l'analyse du journal Apache avec RegEx pour étendre la base de données Pandas?

Mon ancien ordinateur portable analyse le fichier journal apache avec le script en environ 2 minutes. Maintenant je me demande si ça ne pourrait pas être plus rapide?

La structure du fichier journal apache est comme ceci: Ip - - [timestamp] « GET ... méthode » http le code d'état octets « adresse » « useragent » Par exemple:

93.185.11.11 - - [13/Aug/2016:05:34:12 +0200] "GET /v1/con?from=…" 200 575 "http://google.com" "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" 

Mon code utilise regex findall. J'ai aussi testé avec le match et la méthode de recherche. Mais ils semblent être plus lents.

reg_dic = { 
    "ip" : r'\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b', 
    "timestamp" : r'\[\d+\/\w+\/\d+\:\d+\:\d+\:\d+\s\+\d+\]', 
    "method" : r'"(.*?)"', 
    "httpstatus" : r'\s\d{1,3}\s', 
    "bytes_" : r'\s\d+\s\"', 
    "adress" : r'\d\s\"(.*?)"', 
    "useragent" : r'\"\s\"(.*?)"' 
} 

    for name, reg in reg_dic.items() : 
     item_list = [] 
     with open (file) as f_obj: 
      for line in f_obj : 
       item = re.findall(reg , line) 
       item = item[0] 
       if name == "bytes_" : 
        item = item.replace("\"", "") 
       item = item.strip() 
       item_list.append(item) 
     df[ name ] = item_list 
     del item_list 
+2

Voir [cette démo Python] (https://ideone.com/LLW3Uf) et le (https [demo regex]: // regex101 .com/r/UOtsAL/1). Si vos lignes de journal ont toujours le même format, cela devrait être assez rapide et sûr. –

Répondre

2

Vous pouvez utiliser extract avec expand paramter true pour que renvoie une trame de données à partir des données extraites. Espérons que cela aide

Exemple df

df = pd.DataFrame({"log":['93.185.11.11 - - [13/Aug/2016:05:34:12 
+0200] "GET /v1/con?from=…" 200 575 "http://google.com" "Mozilla/5.0 
(Windows NT 6.2; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0"', 

'93.185.11.11 - - [13/Aug/2016:05:34:12 +0200] "GET /v1/con?from=…" 
200 575 "http://google.com" "Mozilla/5.0 (Windows NT 6.2; WOW64; 
rv:54.0) Gecko/20100101 Firefox/54.0"', 

'93.185.11.11 - - [13/Aug/2016:05:34:12 +0200] "GET /v1/con?from=…" 
200 575 "http://google.com" "Mozilla/5.0 (Windows NT 6.2; WOW64; 
rv:54.0) Gecko/20100101 Firefox/54.0"']}) 

Ceci est basé sur @ amélioration de regex Wiktor Stribiżew

ws = '^(?P<ip>[\d.]+)(?:\s+\S+){2}\s+\[(?P<timestamp>[\w:/\s+]+)\]\s+"(?P<method>[^"]+)"\s+(?P<httpstatus>\d+)\s+(?P<bytes>\d+)\s+(?P<adress>"[^"]+")\s+(?P<useragent>"[^"]+")$' 

new = df['log'].str.extract(ws,expand=True) 

Sortie:

 
      ip     timestamp    method httpstatus \ 
0 93.185.11.11 13/Aug/2016:05:34:12 +0200 GET /v1/con?from=…  200 
1 93.185.11.11 13/Aug/2016:05:34:12 +0200 GET /v1/con?from=…  200 
2 93.185.11.11 13/Aug/2016:05:34:12 +0200 GET /v1/con?from=…  200 

    bytes    adress \ 
0 575 "http://google.com" 
1 575 "http://google.com" 
2 575 "http://google.com" 

              useragent 
0 "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) ... 
1 "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) ... 
2 "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) ... 
1

Je ne pense pas que nous avons besoin de trop beaucoup de RegEx pour cette tâche simple:

fn = r'D:\temp\.data\46620093.log' 
cols = ['ip','l','userid','timestamp','tz','request','status','bytes','referer','useragent'] 

df = pd.read_csv(fn, delim_whitespace=True, names=cols).drop('l', 1) 

qui nous donne:

In [179]: df 
Out[179]: 
      ip userid    timestamp  tz    request \ 
0 93.185.11.11  - [13/Aug/2016:05:34:12 +0200] GET /v1/con?from=… 
1 93.185.11.11  - [13/Aug/2016:05:34:12 +0200] GET /v1/con?from=… 
2 93.185.11.11  - [13/Aug/2016:05:34:12 +0200] GET /v1/con?from=… 

    status bytes   referer \ 
0  200 575 http://google.com 
1  200 575 http://google.com 
2  200 575 http://google.com 

              useragent 
0 Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) G... 
1 Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) G... 
2 Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) G... 

maintenant nous avons juste besoin de concaténer timestamp et tz dans une colonne et se débarrasser de [ et ]:

df['timestamp'] = df['timestamp'].str.replace(r'\[(\d+/\w+/\d+):(\d+:\d+:\d+)', r'\1 \2') \ 
        + ' ' + df.pop('tz').str.strip(r'[\]]') 

Résultat:

In [181]: df 
Out[181]: 
      ip userid     timestamp    request \ 
0 93.185.11.11  - 13/Aug/2016 05:34:12 +0200 GET /v1/con?from=… 
1 93.185.11.11  - 13/Aug/2016 05:34:12 +0200 GET /v1/con?from=… 
2 93.185.11.11  - 13/Aug/2016 05:34:12 +0200 GET /v1/con?from=… 

    status bytes   referer \ 
0  200 575 http://google.com 
1  200 575 http://google.com 
2  200 575 http://google.com 

              useragent 
0 Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) G... 
1 Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) G... 
2 Mozilla/5.0 (Windows NT 6.2; WOW64; rv:54.0) G... 

NOTE: nous pouvons eas convertir ily datetime en datetime DTYPE (dans le temps UTC sans fuseau horaire):

In [182]: pd.to_datetime(df['timestamp']) 
Out[182]: 
0 2016-08-13 03:34:12 
1 2016-08-13 03:34:12 
2 2016-08-13 03:34:12 
Name: timestamp, dtype: datetime64[ns]