在我的 Apache 日志文件中,other_vhosts_access.log
如下所示:
www.example.com:80 12.34.56.78 - - [01/Aug/2017:00:42:18 +0200] "GET /page1.html HTTP/1.1" 200 1542 " "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
www.example.com:80 99.99.99.99 - - [02/Aug/2017:06:19:44 +0200] "GET /test.jpg HTTP/1.1" 200 90749 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
www.anotherwebsite.com:80 11.11.11.11 - - [04/Aug/2017:09:39:01 +0200] "GET /test.jpg HTTP/1.1" 200 90749 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
...
www.example.com:80 12.34.56.78 - - [23/Aug/2017:01:12:11 +0200] "GET /somethingelse2.html HTTP/1.1" 200 21161 "http://www.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
我想找到访问过的访客/page1.html
和 /somethingelse2.html
,在此示例中:12.34.56.78。
如果我使用:
grep page1.html other_vhosts_access.log
我无法再过滤输出,因为其余行不包含somethingelse2.html
.
如何查找访问过一个特定页面+另一页面的访客?
答案1
使用bash
,grep
和awk
:
这是获取与该page1.html
文件相关的所有 IP 号码的方法:
awk '/page1\.html/ { print $2 }' log
对于示例数据,这将输出12.34.56.78
.
这可用于获取包含该 IP 地址的所有日志条目:
grep -wF -f <( awk '/page1\.html/ { print $2 }' log ) log
这使用命令的结果awk
作为模式,并再次扫描日志文件以输出包含该 IP 的所有行。这将返回示例中的第一行和最后一行。
和标志 to-w
用于告诉-F
grep
grep
将模式(IP 地址)解释为固定串(-F
) 并仅返回包含该字符串作为整个词( -w
)。这意味着12.34.56.789
不会与固定字符串模式匹配12.34.56.78
。
从这个结果我们可以消除page1.html
关于的线条
grep -wF -f <( awk '/page1\.html/ { print $2 }' log ) log | grep -vF 'page1.html'
现在您拥有了页面访问者生成的所有日志条目page1.html
(但不包括page1.html
页面本身)。
如果您想获取某个项目的条目特别的其他页面,然后将最后一个更改grep -vF 'page1.html'
为grep -F 'otherpage.html'
。
我很确定那里有更强大的日志解析和分析工具,但如果有的话,我不知道它们(我不经常进行日志解析)。
答案2
通常,这是在 awk 中使用关联数组来记住输入中已经看到的内容来完成的。使用默认的 awk 空白字段分隔符,我们注意到字段 2 是 ip 地址,字段 8 是 url,因此,例如,
awk '$8=="/page1.html" { ipaddr[$2] = 1; next }
$8=="/somethingelse2.html" { if(ipaddr[$2]==1)print $2 }'
这将比较 url 字段,当它与第一个 url 匹配时,它会在数组中ipaddr
为 ip 地址创建一个条目,以保存值 1。当它与第二个 url 匹配时,它会检查我们是否为同一 ip 地址设置了该条目,并且如果是这样打印它。为了避免重新打印相同的 IP 地址,我们可以将其记录在另一个数组中:
awk '$8=="/page1.html" { ipaddr[$2] = 1; next }
$8=="/somethingelse2.html" { if(ipaddr[$2]==1 && !done[$2]){print $2; done[$2]=1 } }'
如果 url 可能有查询部分(例如"/page1.html?id=77"
),您可以使用匹配而不是比较,即$8~/^\/page1.html/
。
如果可能以相反的顺序访问 url,您可以使用位掩码值来记住您已经见过的一个,例如 1 表示 page1,2 表示 someelse2,然后等到您获得值 3。位掩码仅在 awk 中可用通过or
和等函数and
。所以我们可能有
awk '
BEGIN { v["/page1.html"] = 1
v["/somethingelse2.html"] = 2
}
$8=="/page1.html" || $8=="/somethingelse2.html" {
ipaddr[$2] = or(ipaddr[$2], v[$8])
if(ipaddr[$2]==3){ print $2; ipaddr[$2] = 4 }
}'
这会在开始时完成的 BEGIN 块中设置关联数组中的映射,v
以将 url 转换为我们的位掩码值(只是一个整数)。当任一 url 匹配时,记住的值具有适当的位掩码值或 -ed。如果现在是 3,我们打印该地址,并将其设置为不会再次打印。
答案3
在此任务中,您可能会发现 other_vhosts_access.log 的格式比您关心的要丰富。我建议你挑选一些你最喜欢的列,例如awk '{print $2, $8}' other_vhosts_access.log > small.log
,然后操作small.log,这样你可以更方便地观察。
问题的解释是https://httpd.apache.org/docs/2.4/logs.html:
...常用的格式字符串称为组合日志格式。它可以按如下方式使用。 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{推荐人}i\" \"%{用户代理}i\"" 组合
这似乎就是你正在使用的。您example.com
在(经过清理的)日志中引用了该内容,表明像 example.com 这样的网站具有指向您网站的 HREF,并且浏览器在其 GET 请求中包含“Referer:www.example.com”标头。
看起来 /page1 很可能有 /page2 的 HREF。某些浏览器会在 page2 请求上发送 page1 引用标头。您可以选择依赖于此,并 grep 查找“page2.*page1”。或者您可以选择依赖源 IP,如已接受的答案中所示。在这种情况下,您可能希望删除其他会导致错误匹配的分散注意力的列,并使用简化的small.log 进行分析。