如何从Perl的Apache访问日志中提取外部引用?

时间:2009-01-14 08:47:23

标签: regex perl apache parsing logging

我需要一些帮助才能让正则表达式解析来自apache访问日志文件的所有引用来自来自异地的真实链接,这些是来自真人而不是机器人或蜘蛛的有效推荐。我在Perl工作。

这段代码几乎已经可以[使用文件句柄$ fh打开访问日志]:

my $totalreferals = 0;
while ( my $line = <$fh> ) {
    if ($line !~ m!

        \[\d{2}/\w{3}/\d{4}(?::\d\d){3}.+?\]
        \s"GET\s\S+\sHTTP/\d.\d"
        \s\S+
        \s\S+
        \s("-"|"http://(www\.|)mywebsite\.com.*"                

        !xi
        )
    {
          $totalreferals++;  
    }

    $line =~ m!

        \[(\d{2}/\w{3}/\d{4})(?::\d\d){3}.+?\]
        \s"GET\s(\S+)\sHTTP/\d.\d"
        \s(\S+)
        \s\S+
        \s"http://w{1,3}\.google\.
        (?:[a-z]{2}|com?\.[a-z]{2}|com)\.?/
        [^\"]*q=([^\"&]+)[^\"]*"

    !xi or next;

    my ( $datestr, $path, $status, $query ) = ( $1, $2, $3, $4 );
    .
    .
    #do other stuff  
    .
    .
}

上面的正则表达式成功地消除了access_log中记录的所有内部链接以及没有引用者的记录,但是它给出了一个$ totalfferals,否则它太大了。

第一个正则表达式计算的log $行的示例,但我想要排除的是:

61.247.221.45 - - [02/Jan/2009:20:51:41 -0600] "GET /oil-paintings/section.php/2451/0 HTTP/1.1" 200 85856 "-" "Yeti/1.0 (NHN Corp.; http://help.naver.com/robots/)"

- 似乎是来自韩国的蜘蛛


93.84.41.131 - - [31/Dec/2008:02:36:54 -0600] "GET /paintings/artists/w/Waterhouse_John_William/oil-big/Waterhouse_Destiny.jpg HTTP/1.1" 200 19924 "http://smrus.web-box.ru/Schemes" "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5"

- 请求是嵌入在另一个网站中的图像(我们允许这样)


87.115.8.230 - - [31/Dec/2008:03:08:17 -0600] "GET /paintings/artists/recently-added/july2008/big/Crucifixion-of-St-Peter-xx-Guido-Reni.JPG HTTP/1.1" 200 37348 "http://images.google.co.uk/im........DN&frame=small" "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5" 

- 请求来自谷歌图片(可能正在查看图片的全尺寸,或抓住它)


216.145.5.42 - - [31/Dec/2008:02:21:49 -0600] "GET / HTTP/1.1" 200 53508 "http://whois.domaintools.com/mywebsite.com" "SurveyBot/2.3 (Whois Source)" 

- 请求来自whois bot


5 个答案:

答案 0 :(得分:3)

除非你有一些非常奇怪的要求重新发明轮子,

http://search.cpan.org/search?query=apache+log&mode=all

答案 1 :(得分:1)

我认为你的问题在这里:

\s"http://w{0,3}\.mywebsite\.com[^\"]*" 

这不会捕捉到“http://mywebsite.com”的情况,因为在“mywebsite”之前它总是需要一个点。

此外,您只排除GET请求。 POST和HEAD怎么样?

修改 如果您仍然得到看似错误的数字,那么您一定要使用正则表达式捕获引荐来源并打印它。

答案 2 :(得分:1)

Manni建议消除POST和HEAD确实是正确的,因为我正在寻找负面匹配(因此在解析查询字符串时不应该限制为GET)。同样在没有www的主机之前的点中的错误,并且还需要消除“ - ”(没有推荐人)

此外,我删除了针对图片文件的所有匹配,这些图片文件通常不是来自外部网站的直接引荐,而是嵌入在这些网站中,或者被搜索引擎(主要是谷歌图片)编入索引。

我还发现许多服务器的图像文件在文件名中包含空格,这打破了使用\ S +用于文件名的正则表达式,我已将其更改为。+

最后,因为我不需要在删除记录时grep日期,所以我可以简化正则表达式的第一部分。

结果更接近我期待的数字。虽然我还没有找到一个好方法来消除机器人和蜘蛛的所有请求。

对于那些感兴趣的人,最终的代码如下:

my $totalreferals = 0;
while ( my $line = <$fh> ) {
    if ($line !~ m!

        \[.+\]
        \s("\S+\s.+\sHTTP/\d.\d"
        \s\S+
        \s\S+
        \s("-"|"http://(www\.|)mywebsite\.com.*")|
        "\S+\s.+\.(jpg|jpeg|gif|png)\sHTTP/\d.\d"
        \s\S+
        \s\S+
        \s".*")
        !xi
        )
    {   
      $totalreferals++;  
    }

    $line =~ m!

        \[(\d{2}/\w{3}/\d{4})(?::\d\d){3}.+?\]
        \s"GET\s(\S+)\sHTTP/\d.\d"
        \s(\S+)
        \s\S+
        \s"http://w{1,3}\.google\.
        (?:[a-z]{2}|com?\.[a-z]{2}|com)\.?/
        [^\"]*q=([^\"&]+)[^\"]*"

    !xi or next;

    my ( $datestr, $path, $status, $query ) = ( $1, $2, $3, $4 );
    .
    .
    #do other stuff  
    .
    .
}

编辑:在我的研究过程中,区分自动抓取工具和真正的人类访问者的唯一真正可行的方法似乎是跟踪Cookie。我怀疑用纯日志分析可以解释这个问题。如果有人知道通过分析日志的方法,请告诉我。要知道我只会在我的日志报告中添加一个脚注,表明它们包含来自机器人的流量。

答案 3 :(得分:0)

对于正则表达式的匹配URI,请尝试Regex :: Common(或更具体地说Regexp :: Common :: URI :: http)。

答案 4 :(得分:0)

目前,我的选择是根据IP过滤日志。最活跃的机器人是google,yahoo,msn等。所以,我把他们的IP范围从记录中删除了。