分享

如何从Apache日志文件生成完整的访问者计数

 码农9527 2021-05-21

    我描述了如何从Apache日志文件创建报告,以了解本地主机与其他主机之间的匹配次数。只需将IP地址替换为另一个地址,即可轻松更改该脚本,以提供针对任何单个IP地址(相对于世界其他地方)的报告。

web

    也可以更改它以提供具有完整访问者人数的报告,以显示每个IP地址带来了多少点击。这样就很容易显示前10个来源,或以其他方式对其进行过滤。

    背景

    只需回想一下,默认格式下,Apache日志文件中的每一行都是这样开始的:

127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] ...
127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] ...
139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] ...
217.1.20.22 - - [10/Apr/2007:10:40:54 +0300] ...1234复制代码类型:[html]

    这意味着,如果我们将任何一行放入$line变量中,都可以通过以下代码提取IP地址:

my $length = index ($line, " ");
my $ip = substr($line, 0, $length);12复制代码类型:[html]

    使用代码

    为了计算任意一组字符串,我们需要一个可以将字符串映射到标量值的数据结构。在Perl中,此数据结构称为“关联数组”或简称为“哈希”。在其他语言中,类似的事物可能称为地图,字典或查找表。

    哈希基本上是一组无序的键值对,其中键是唯一的字符串,并且值可以是任何标量值(数字,字符串或引用)。

    在Perl中,井号用百分比字符(%)标记。因此,我们声明%count散列以将IP保留为“命中数”映射。大多数代码与前面的示例相同,但是我们没有增加两个单独的标量,而是使用以下结构来增加哈希的元素:

$count{$ip}++;1复制代码类型:[html]

    当我们第一次遇到IP地址时,该地址$count{$ip}尚不存在。如果尚不存在值,则Perl会假定其中包含“undef”值。如果在某些数字操作(例如++自动增量)中使用了该字符,则它会假装为数字0。该数字变为1,并且此操作还会在哈希中创建适当的条目。键值对会自动出现。这也称为自生化。

    如您所见,哈希值会自动增长。Perl负责所有内存管理。

    完成此操作后,我们将获得一个哈希值,其中每个键是一个IP地址,每个值是IP地址出现在文件中的次数。该keys函数获取哈希作为参数,并返回哈希键的无序列表。此代码将打印所有具有相应匹配数的IP地址:

foreach my $ip (keys %count) {
 print "$ip   $count{$ip}\n";
}123复制代码类型:[html]

    代码

    完整的脚本在这里:

#!/usr/bin/perl
use strict;
use warnings;

my $file = shift or die "Usage: $0 FILENAME\n";
open my $fh, '<', $file or die "Could not open '$file': $!";

my %count;

while (my $line = <$fh>) {
 my $length = index ($line, " ");
 my $ip = substr($line, 0, $length);
 $count{$ip}++;   
}

foreach my $ip (keys %count) {
 print "$ip   $count{$ip}\n";
}123456789101112131415161718复制代码类型:[html]

    兴趣点

    当然,对它们进行排序会更好,下面的代码可以做到

foreach my $ip (sort keys %count) {
 print "$ip   $count{$ip}\n";
}123复制代码类型:[html]

    但这会根据ASCII表对IP地址进行排序。可能不是很有趣。

    更好的排序可能是这样的:

foreach my $ip (reverse sort { $count{$a} <=> $count{$b} } keys %count) {
 print "$ip   $count{$ip}\n";
}123复制代码类型:[html]

    在这里,我们根据相应的值对密钥进行排序,然后我们颠倒顺序以首先获得具有最大数字的IP。这是表达式,但让我们拆开它:

reverse sort { $count{$a} <=> $count{$b} } keys %count1复制代码类型:[html]

    您可以对任何字符串列表进行排序。

sort @strings;1复制代码类型:[html]

    默认情况下,此排序基于ASCII表对每两个值进行比较。

    您还可以使用任何其他条件对它们进行排序。例如,字符串的长度:

sort { length($a) <=> length($b) } @strings;1复制代码类型:[html]

    sort()Perl的函数将采用要比较的任何两个值,将它们放在两个变量$aand中$b,然后对块进行求值。根据结果,它将保留两个值的顺序或交换它们。

sort { $count{$a} <=> $count{$b} } keys %count1复制代码类型:[html]

    该代码执行相同的操作,但是它对哈希的键进行排序,并且在比较两个键时,表达式将比较两个键的值。结果将以递增的顺序显示,但是如果我们想显示点击次数最多的IP,则需要反转结果:

reverse sort { $count{$a} <=> $count{$b} } keys %count1复制代码类型:[html]

    在最后一个示例中,我们执行相同的操作,但是在显示时,我们使用帮助程序变量将项数限制为前两个IP地址。

my $top = 2;
foreach my $ip (reverse sort { $count{$a} <=> $count{$b} } keys %count) {
 print "$ip   $count{$ip}\n";
 $top--;
 if ($top <= 0) {
  last;
 }
}

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多