你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:技术专栏 / Web开发
WEB日志清洗 - java代码
 

需要从访问日志中梳理出每一个session(如果一个用户两次相邻请求之间的时间差 < 30 min,则该两次请求同属于同一个session,否则分属于不同的session),并且为session的历次请求打上序号

模拟日志 :

194.237.142.21 - - [18/Sep/2013:06:49:18 +0000] "GET /1.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.21 - - [18/Sep/2013:06:50:18 +0000] "GET /2.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.21 - - [18/Sep/2013:06:51:18 +0000] "GET /3.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.21 - - [18/Sep/2013:08:49:18 +0000] "GET /4.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.21 - - [18/Sep/2013:08:50:18 +0000] "GET /5.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.21 - - [18/Sep/2013:10:49:18 +0000] "GET /6.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"


194.237.142.22 - - [18/Sep/2013:06:49:18 +0000] "GET /1.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.22 - - [18/Sep/2013:06:50:18 +0000] "GET /2.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.22 - - [18/Sep/2013:06:51:18 +0000] "GET /3.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.22 - - [18/Sep/2013:08:49:18 +0000] "GET /4.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.22 - - [18/Sep/2013:08:50:18 +0000] "GET /5.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.22 - - [18/Sep/2013:10:49:18 +0000] "GET /6.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"


194.237.142.23 - - [18/Sep/2013:06:49:18 +0000] "GET /1.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.23 - - [18/Sep/2013:06:50:18 +0000] "GET /2.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.23 - - [18/Sep/2013:06:51:18 +0000] "GET /3.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.23 - - [18/Sep/2013:08:49:18 +0000] "GET /4.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.23 - - [18/Sep/2013:08:50:18 +0000] "GET /5.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.23 - - [18/Sep/2013:10:49:18 +0000] "GET /6.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"


194.237.142.24 - - [18/Sep/2013:06:49:18 +0000] "GET /1.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.24 - - [18/Sep/2013:06:50:18 +0000] "GET /2.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.24 - - [18/Sep/2013:06:52:18 +0000] "GET /3.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.24 - - [18/Sep/2013:08:49:18 +0000] "GET /4.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.24 - - [18/Sep/2013:08:50:18 +0000] "GET /5.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
194.237.142.24 - - [18/Sep/2013:10:49:18 +0000] "GET /6.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
代码
地址 :
https://gitee.com/tanghongping/hadoopMapReduce/tree/master/src/com/thp/bigdata/webLog

package com.thp.bigdata.webLog;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.Test;
/**
 *
 * 对web日志的清洗(简易版本):
 * 我们先来单独看一下web日志里面的一条数据:
 *  194.237.142.21 - - [18/Sep/2013:06:49:18 +0000] "GET /1.html HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
 * 里面有ip地址,访问时间,使用GET还是POST访问,请求的页面,访问的状态
 * 我们现在就做简化处理。我们要知道一个用户在一个页面上停留的时间
 * 由于一个ip可以被多个用用户使用,于是我们区分用户的方式就是使用sessionID
 * 但是sessionID本身在上面的web日志里面的数据是没有的,是要我们自己生成的
 * 生成sessionID是有自己的规则的,
 * 不同的ip地址肯定不是同一个sessionID
 * 同一个ip地址,当请求的时间超过了30min,我们就把这条访问记录的sessionID设置成不一样
 *
 * 所以首先我们要将所有的数据根据IP分离出来
 * 然后根据IP生成sessionID
 * 生成sessionID之后,使用sessionID作为主键,存在HashMap中,然后返回给用户
 *
 * @author 汤小萌
 *
 */
public class WashWebLog {

 public static void main(String[] args) throws IOException {

  // 得到ip对应的SessionBean 的List集合     
  Map<String, List<SessionBean>> IPListMap = getIPSessionBeanMap();
  
  
  /**
   * 之所以要对每个List中色SessionBean根据时间先后排序,
   * 因为我们需要根据时间来计算sessionID
   */
  // 对IPListMap每一个键值对数据里面的List的SessionBean按照时间进行排序
  sortByDate(IPListMap);
  
  /**
   * 到现在为止,我们还只是跟IP进行区分
   * 我们还没有生成sessionID
   * 我们需要生成sessionID,才能根据sessionID来进行区分
   */
  
  // 生成sessionId
  makeSessionId(IPListMap);

  /*
   * for(Entry<String, List<SessionBean>> entrySet : IPListMap.entrySet())
   * { System.out.println("ip : " + entrySet.getKey() + " -- " +
   * entrySet.getValue()); }
   */

  Map<String, List<SessionBean>> sessionIdListMap = new HashMap<String, List<SessionBean>>();

  /**
   * 经过了上面的步骤,每一个IP里面的每一个SessionBean 都生成了sessionID
   * 现在我们就需要将所有的数据都拿出来,进行重新洗牌
   * 我们需要的是根据sessionID来进行划分
   */
  for (Entry<String, List<SessionBean>> entrySet : IPListMap.entrySet()) {
   List<SessionBean> sessionBeans = entrySet.getValue();
   for (SessionBean sessionBean : sessionBeans) {
    // 千万要注意这些Map的区别含义,别搞混了,搞混了,那么清洗出来的数据都是错的 注意获取的是sessionId 而不是 IP
    // 如果是IP 的话,那么会
    // 一直只有一条数据
    List<SessionBean> list = sessionIdListMap.get(sessionBean.getSessionId());
    if (list == null) {
     list = new ArrayList<SessionBean>();
    }
    list.add(sessionBean);
    // 此时的key 变成sessionID了
    sessionIdListMap.put(sessionBean.getSessionId(), list);
   }
  }

  /**
   * 将数据格式化地显示出来
   */
  for (Entry<String, List<SessionBean>> entrySet : sessionIdListMap.entrySet()) {
   String sessionId = entrySet.getKey();
   List<SessionBean> sessionBeans = entrySet.getValue();
   SessionBean start = sessionBeans.get(0);
   SessionBean end = sessionBeans.get(sessionBeans.size() - 1);
   long differ = end.getDate().getTime() - start.getDate().getTime();

   String res = sessionId + "\t" + start.getIp() + "\t" + start.getDate() + "\t" + end.getDate() + "\t"
     + start.getUrl() + "\t" + end.getUrl() + "\t" + (differ / 1000);
   System.out.println(res);
  }
 }

 /**
  * 对List里面的SessionBean 按照时间排序之后,生成SessionId
  *
  * @param IPListSortedMap
  */
 private static void makeSessionId(Map<String, List<SessionBean>> IPListSortedMap) {
  for (Entry<String, List<SessionBean>> entrySet : IPListSortedMap.entrySet()) {
   List<SessionBean> sessionBeans = entrySet.getValue();
   if (sessionBeans.size() == 1) { // 长度等于1时   这个ip地址就只有一条数据,那么肯定就是直接生成sessionID
    SessionBean sessionBean = sessionBeans.get(0);
    sessionBean.setSessionId(getSessionId(sessionBean.getIp()));
    sessionBean.setOrder(1);
   }
   // 当长度大于1时     这个ip对应的访问记录有多条
   for (int i = 0; i < sessionBeans.size() - 1; i++) {
    SessionBean sb1 = sessionBeans.get(i);  // 获取这个ip  i 时刻的访问记录数据
    SessionBean sb2 = sessionBeans.get(i + 1); // 获取这个ip  i+1 时刻的访问记录
    // 同一个session的时候   (先判断是不是同属于一个session  --  根据访问时间是不是在30分钟之内)
    if (isSameSession(sb1, sb2)) {
     // 早的那个可能之前就已经设置了sessionId 就是上面的步骤设置了 那么order也一同设置了
     if (sb1.getSessionId() != null) {
      sb2.setSessionId(sb1.getSessionId());
      sb2.setOrder(sb1.getOrder() + 1);
     } else {
      // 连个sessionID都没有生成sessionID,那么就生成一个,连个SessionBean使用同一个
      sb1.setSessionId(getSessionId(sb1.getIp()));
      sb1.setOrder(1);
      sb2.setSessionId(sb1.getSessionId());
      // order后一个访问记录需要  + 1
      sb2.setOrder(sb1.getOrder() + 1);
     }
    } else {
     // 不是同一个session
     if (sb1.getSessionId() != null) {  // 前一个sessionBean经过上面的步骤已经设置了sessionID
      sb2.setSessionId(getSessionId(sb2.getIp()));
      sb2.setOrder(1); // sb2是来自新的一个session, order要设置为1
     } else {  // 连个SessionBean都没有设置sessionID
      sb1.setSessionId(getSessionId(sb1.getIp()));
      sb1.setOrder(1);
      sb2.setSessionId(getSessionId(sb2.getIp()));
      sb2.setOrder(1);
     }
    }

   }
  }
 }

 /**
  * 根据SessionBean 的时间判断是不是同一个session
  *
  * @param s1
  * @param s2
  * @return
  */
 private static boolean isSameSession(SessionBean s1, SessionBean s2) {
  long time1 = s1.getDate().getTime();
  long time2 = s2.getDate().getTime();
  // session 时间 0 - 30 分钟
  long differ = time2 - time1;
  if (differ >= 0 && differ <= (1000 * 60 * 30)) {
   return true;
  }
  return false;
 }

 /**
  * 生成sessionId的方法
  */
 private static String getSessionId(String ip) {
  // Integer.parseInt(ip);
  String[] fields = ip.split("\\.");
  StringBuffer sb = new StringBuffer();
  for (String field : fields) {
   sb.append(field);
  }
  long longIP = Long.parseLong(sb.toString());
  long nanoTime = System.nanoTime();
  return "" + longIP + nanoTime;
 }

 /**
  * 对IPListMap里的每一条数据的List中的SessionBean按照时间进行排序
  *
  * @param IPListMap
  */
 private static void sortByDate(Map<String, List<SessionBean>> IPListMap) {
  for (Entry<String, List<SessionBean>> entrySet : IPListMap.entrySet()) {
   List<SessionBean> list = entrySet.getValue();
   // 根据自己定义的方法来进行排序
   Collections.sort(list, new Comparator<SessionBean>() {
    @Override
    public int compare(SessionBean o1, SessionBean o2) {
     Date date1 = o1.getDate();
     Date date2 = o2.getDate();
     return date1.before(o2.getDate()) ? -1 : 1;
    }

   });
  }
 }
 
 /**
  * 这个方法主要的功能:
  *   1,去读取web日志数据 按照行去读取
  *   2. 按照行读取sweb日志的时候,还需要将关键的数据获取出来,存放在sessionBean中
  *   3.使用IP作为key,这个ip所对应的其他的数据都存放在这个IP所对应的List集合中
  * @return
  */
 private static Map<String, List<SessionBean>> getIPSessionBeanMap() {
  Map<String, List<SessionBean>> map1 = new HashMap<String, List<SessionBean>>();
  BufferedReader bufferedReader = null;
  try {
   bufferedReader = new BufferedReader(new
   FileReader(DemoTest.class.getResource("access.log.fensi").getPath()));
   // bufferedReader = new BufferedReader(new FileReader(DemoTest.class.getResource("data.dat").getPath()));
   String line = null;
   while ((line = bufferedReader.readLine()) != null) {
    // 数字 + . (连续出现三次) + 最后一次出现的还是数字 -- \\d+ 代表的是多个数字
    String ipRegex = "(\\d+\\.){3}\\d+";
    // [ + 任何单字符 + 数字(一个或者多个) + ]
    String dateRegex = "\\[.+\\d+\\]";
    // 首先是 GET 或者 POST (只要有一个出现就可以匹配) + 空格 + 非空格的字符(0次或者多次)
    String urlRegex = "(POST|GET){1}\\s(\\S)*\\s";

    // 匹配IP
    String ip = getConByRegex(line, ipRegex);
    // 匹配日期
    String date = getConByRegex(line, dateRegex);
    // 匹配url
    String url = getConByRegex(line, urlRegex);
    if (ip != null && date != null && url != null) {
     // 封装SessionBean
     SessionBean sessionBean = new SessionBean();
     sessionBean.setIp(ip);
     sessionBean.setDate(parDateFromStr(date));
     sessionBean.setUrl(url);
     List<SessionBean> list = map1.get(ip);
     if (list == null) { // 如果HashMap中这个ip已经存在就在这个ip对应的List中增加SessionBean
      list = new ArrayList<SessionBean>();   // 如果这个ip在HashMap中不存在,那么就为这个ip新建一个List
     }
     list.add(sessionBean);
     map1.put(ip, list);
    }
   }
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   if (bufferedReader != null) {
    try {
     bufferedReader.close();
    } catch (IOException e) {
     e.printStackTrace();
    } finally {
     bufferedReader = null;
    }
   }
  }

  return map1;
 }

 /**
  * 将日期格式的字符串转换为Date类型
  *
  * @param dataStr
  * @return
  */
 private static Date parDateFromStr(String dateStr) {
  // [19/Sep/2013:04:38:11 +0000]
  String substring = dateStr.substring(1, dateStr.length() - 1);
  // 注意是有 三个 M , 后面要加上Locale.US 否则会报错
  SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
  try {
   return dateFormat.parse(substring);
  } catch (ParseException e) {
   e.printStackTrace();
  }
  System.err.println("< 日期解析异常 >");
  return null;
 }

 /**
  * 匹配字符串
  *
  * @param line
  * @param regex
  * @return
  */
 private static String getConByRegex(String line, String regex) {
  Pattern compile = Pattern.compile(regex);
  Matcher matcher = compile.matcher(line);
  while (matcher.find()) {
   // 返回的是符合正则规则的字符串
   return matcher.group();
  }
  return null;
 }

 @Test
 public void testRegex() {

  String line = "GETGETPOST /wp-content/uploads/2013/07/rstudio-git3.png HTTP/1.1";

  // String ipRegex = "(\\d+\\.){3}\\d+";
  // String regex ="\\[.+\\d+\\]";
  String regex = "(POST|GET){1}\\s(\\S)*\\s";

  Pattern compile = Pattern.compile(regex);

  Matcher matcher = compile.matcher(line);

  while (matcher.find()) {
   System.out.println(matcher.group());
   return;
  }

  System.out.println("没有匹配");

  return;
 }

 @Test
 public void testLineData() {
  String lineData = "194.237.142.21 - - [18/Sep/2013:06:49:18 +0000] \"GET /wp-content/uploads/2013/07/rstudio-git3.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/4.0 (compatible;)\"";
  String[] fields = lineData.split(" ");
  for (String field : fields) {
   System.out.println(field);
  }

 }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
package com.thp.bigdata.webLog;

import java.util.Date;

/**
 * SessionBean
 * @author 汤小萌
 *
 */
public class SessionBean {

 private String sessionId;
 private String ip;
 private Date date;
 private String url;
 private int order;
 public String getSessionId() {
  return sessionId;
 }
 public void setSessionId(String sessionId) {
  this.sessionId = sessionId;
 }
 public String getIp() {
  return ip;
 }
 public void setIp(String ip) {
  this.ip = ip;
 }
 public Date getDate() {
  return date;
 }
 public void setDate(Date date) {
  this.date = date;
 }
 public int getOrder() {
  return order;
 }
 public void setOrder(int order) {
  this.order = order;
 }
 public String getUrl() {
  return url;
 }
 public void setUrl(String url) {
  this.url = url;
 }
 @Override
 public String toString() {
  return "SessionBean [sessionId=" + sessionId + ", ip=" + ip + ", date=" + date + ", url=" + url + ", order="
    + order + "]";
 }
 
 
}

---------------------
作者:汤愈韬
来源:CSDN
原文:https://blog.csdn.net/qq_38200548/article/details/84473624
版权声明:本文为博主原创文章,转载请附上博文链接!

  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089