【问题标题】:String manipulation of Apache Web Server data in RR 中 Apache Web 服务器数据的字符串操作
【发布时间】:2018-02-18 23:54:46
【问题描述】:

我有一个 Apache Web Server 数据的数据文件,我想解析该文件并创建一个由日志的不同部分组成的数据框。这将需要我做一些字符串操作和正则表达式的使用。但是,我在字符串操作方面的经验非常有限。

每一行数据是一个日志,像这样:

[1] "79.133.215.123 - - [14/Jun/2014:10:30:13 -0400] \"GET /home HTTP/1.1\" 200 1671 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36\""

对于 IP 地址,我使用 regexpr 函数来识别第一个空格,然后根据该第一个空格获取一个子字符串,如下所示:

> first_space <- regexpr(pattern = " ", text=web_logs)
> IP <- substr(x=web_logs, start=1, stop=first_space-1)

但是,对于我想提取的其他变量,我对我能做什么感到困惑。例如,如果我想提取方括号括起来的日期,我尝试使用 regexpr where pattern = "[",但收到错误。

我可以利用哪些其他功能来提取我需要的信息?

【问题讨论】:

  • 您究竟需要提取什么样的信息?显示您的预期结果将有助于 SO 用户帮助您。
  • 例如,假设我想检索一个向量,其中每个成员都是日期。我尝试使用子字符串来执行此操作,但每个日志的长度不同。所以这段代码:'code' Date
  • 迈克尔,我明白这一点。你只想提取日期吗?还是您也想提取其他信息?
  • 我还希望提取请求(例如 GET)、页面(例如主页)和 HTTP 版本(例如 1.1)。很抱歉我的评论代码显示不正确,我是新手。
  • 我的想法是使用 strsplit,但我不知道如何提取 strsplit 中的特定位,如果这有意义的话。

标签: r string


【解决方案1】:

dplyrtidyr 数据处理工具可以快速解决您的问题。 separate() 将通过简单的正则表达式解析您的字符串,然后您可以在列上使用select()merge() 来根据您的喜好调整数据框。

string <- "79.133.215.123 - - [14/Jun/2014:10:30:13 -0400] \"GET /home HTTP/1.1\" 200 1671 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36\""

library(tidyr)
library(stringr)

string.df <- as.data.frame(string) %>%
separate(string, paste0("x", seq(1:(str_count(string, " ")+1))), sep = " ", extra = "merge")

保持extra 参数设置为“合并”是为了安全 - 如果separate() 用完列,它将保留最后一个中剩下的所有内容。 结果:

x1 x2 x3                    x4     x5   x6    x7        x8  x9  x10 x11
1 79.133.215.123  -  - [14/Jun/2014:10:30:13 -0400] "GET /home HTTP/1.1" 200 1671 "-"
           x12      x13 x14  x15    x16                x17     x18  x19    x20
1 "Mozilla/5.0 (Windows  NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
                   x21            x22
1 Chrome/35.0.1916.153 Safari/537.36"

【讨论】:

    【解决方案2】:

    样本数据:

    web_logs <- c("79.133.215.123 - - [14/Jun/2014:10:30:13 -0400] \"GET /home HTTP/1.1\" 200 1671 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36\"",
                  "162.235.161.200 - - [14/Jun/2014:10:30:13 -0400] \"GET /department/apparel/category/featured%20shops/product/adidas%20Kids'%20RG%20III%20Mid%20Football%20Cleat HTTP/1.1\" 200 1175 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.76.4 (KHTML, like Gecko) Version/7.0.4 Safari/537.76.4\"")
    

    为了从日志中检索请求,我结合了 strsplit() 和 sapply():

    split_log <- strsplit(x = web_logs, split=" ")
    request <- sapply(split_log, "[", 6)
    

    返回一个字符向量,示例如下:

    > request[1:2]
    [1] "\"GET" "\"GET"
    

    现在我要做的就是从请求中删除 \"。

    【讨论】:

    • 我认为你想在你的问题中安排你的数据,这样你的答案才有意义。
    • 抱歉,整理我的数据是什么意思?
    • 您上面的日志示例不会导致您在答案中的输出。这就是我的意思。你想要保持一致性。最后,您的问题将成为一些有类似情况的人的参考。您想考虑帮助未来的读者,以便帮助他们。
    • 我更新了答案,现在更有意义了吗?它没有提供如何检索 HTTP 或 home 的解释,但逻辑基本上是相同的,所以我觉得没有必要。
    • 您在strsplit() 中有错字。 weblogs 应该是 web_logs。我清理了你的代码。当您提供数据时,我建议您使用dput()。这是他们通常做的事情。露头有时是不够的。
    【解决方案3】:

    这不是一个简单的正则表达式。使用http://statmodeling.com/regular-expression-for-apache-log-parsing.htmlhttps://httpd.apache.org/docs/2.4/logs.html 作为我的指南,我想出了这个:

    web_logs <- rep("79.133.215.123 - - [14/Jun/2014:10:30:13 -0400] \"GET /home HTTP/1.1\" 200 1671 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36\"",
                    3)
    
    library(stringi)
    
    apache.log.lazy.regex <- "([\\d.]+) ([\\w.-]+) ([\\w.-]+) \\[(.*)?\\] \"(.*)?\" (\\d{3}) ([\\d-]+) \"(.*)?\" \"(.*)?\""
    do.call(rbind, stri_match_all_regex(web_logs, apache.log.lazy.regex))[, -1]
    ##      [,1]             [,2] [,3] [,4]                         [,5]                 [,6]  [,7]   [,8]
    ## [1,] "79.133.215.123" "-"  "-"  "14/Jun/2014:10:30:13 -0400" "GET /home HTTP/1.1" "200" "1671" "-" 
    ## [2,] "79.133.215.123" "-"  "-"  "14/Jun/2014:10:30:13 -0400" "GET /home HTTP/1.1" "200" "1671" "-" 
    ## [3,] "79.133.215.123" "-"  "-"  "14/Jun/2014:10:30:13 -0400" "GET /home HTTP/1.1" "200" "1671" "-" 
    ##      [,9]                                                                                                           
    ## [1,] "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"
    ## [2,] "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"
    ## [3,] "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"
    

    它适用于这种情况,我认为它通常适用于大多数情况。可能存在失败的示例,例如,如果在 User-Agent 字段中嵌入了引号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多