Work the Shell - 分析您的搜索关键词

作者:Dave Taylor

上个月,我们开始探索如何使用 shell 脚本从 Web 服务器日志中提取和分析 HTTP_REFERER 值,并识别人们用来找到您页面的最常用词语和短语。听起来很有用,不是吗?

问题是,这个脚本比最初看起来更微妙。上个月,我们以以下 shell 脚本结束

#!/bin/sh

ACCESSLOG="/var/logs/httpd.logs/access_log"

grep 'google.com/search' $ACCESSLOG | \
  awk '{print $11}' | \
  cut -d\? -f2 | cut -d\& -f1 | \
  sed 's/+/ /g;s/%22/"/g;s/q=//' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -5

当我运行它时,我看到的是这样

$ sh google-searches.sh
  94 hl=en
  18 client=safari
   6 client=firefox-a
   4 sourceid=navclient
   4 client=opera

这很奇怪,因为它不是搜索词,而是包含在来自 Google 等网站的搜索字符串中的其他变量(hl=en表示您已将搜索限制为仅限英语网站,client=safari将用户的 Web 浏览器标识为 Apple 的 Safari 等等)。

筛选掉虚假匹配项

当我们查看前十个匹配项而不是仅查看前五个时,问题就显现出来了

$ sh google-searches.sh | head -10
  94 hl=en
  18 client=safari
   6 client=firefox-a
   4 sourceid=navclient
   4 client=opera
   3 wicked cool scripts
   3 hl=zh-CN
   2 num=100
   2 hs=wNy
   2 barbara nelson%2Bpurses

啊,所以我们可以看到这里有两个有效的搜索,一个用于“wicked cool scripts”,一个用于“Barbara nelson%2Bpurses”。不确定后者是什么,但看到它很有用也很重要。幸运的是,筛选掉虚假匹配项就像使用 grep 删除包含等号的字段一样简单grep -v '='.

但是,与其将它放在脚本中长管道的末尾,不如将其放在 sed 调用之后,以便在管道中尽快去除虚假结果,从而加快整个脚本的速度。现在它看起来像这样

grep 'google.com/search' $ACCESSLOG | \
  awk '{print $11}' | \
  cut -d\? -f2 | cut -d\& -f1 | \
  sed 's/+/ /g;s/%22/"/g;s/q=//' | \
  grep -v '=' | \
  sort | \
  uniq -c | \
  sort -rn

请注意,sed 语句本身会去除搜索的 name= 部分(q=),这样它就不会在新 grep 语句中被错误地匹配。

现在我们得到了想要的结果

$ sh google-searches.sh | head -10
   3 wicked cool scripts
   2 barbara nelson%2Bpurses
   1 wsj%20password
   1 why did animal kingdom introduce expedition everest
   1 what makes a great speaker%3F
   1 university of phoenix center of writing excellence
   1 ubuntu x problem
   1 triboot osx ubuntu ydl
   1 the best dvd players
   1 symbol html heart

这个网站的流量不大,所以让我们针对我流量更大的 AskDaveTaylor.com 网站运行相同的脚本。结果更有趣

$ sh google-searches.sh | head -10
   5 standalone player
   4 psp help
   4 create a myspace
   4 Documents and Settings"
   4 %24NtUninstall
   3 view myspace accounts that are set to private
   3 i cant hear music on runescape
   2 transfer files to psp
   2 sync v3 motorola mac
   2 running unix in windows xp

有趣得多。哦,如果您想知道您正在探索多少次搜索,只需对脚本进行另一个简单的调整,调用 wc 即可

$ sh google-searches.sh | wc -l
     501

因此,在 501 次搜索中,最常见的搜索是“standalone player”,仅占 500 次搜索中的 5 次,即我的搜索流量的 1%。

去除不需要的字符

在本月结束这个脚本之前,还有最后一步:让我们摆脱从用户 Web 浏览器的原始 URL 编码中遗留下来的奇怪字符。我在说什么? %24,Documents and Settings 中的右双引号,以及之前搜索 purses 中的 %2B。

您可以找出所有映射并进行相应的转换,但我懒得在一天结束时这样做,而是简单地找到所有 %xx 序列并将它们替换为单个空格。

这听起来很困难,但对于 sed 来说这是一项完美的工作,因为它允许您进行模式匹配,然后用您想要的任何其他内容替换匹配的材料。这就是我将要做的

sed 's/%[0-9a-fA-F][0-9a-fA-F]/ /g'

让我们仔细看看这个,然后再惊慌失措。用方括号分隔的集合在正则表达式术语中是一个集合,因此 [0-9] 将匹配 0、1、2、3、4、5、6、7、8、9 或 0 中的任何一个。事实证明,URL 编码使用十六进制,因此这些值不仅可以是 0-9,还可以是 A、B、C、D、E 和 F,大写或小写字母 - 因此模式中包含 0-9 和 a-f 和 A-F。 总体模式形式是 %,后跟这些可能值中的任何一个,然后再次跟这些可能值中的任何一个。现在您可以看到完整的模式了。

最后,在我们彻底完成此操作之前,请注意 sed 语句中更大的结构是 s/old/new/g,它在整行中将 old 替换为 new,无论它出现一次还是 15 次。

但是,我们还没有完全完成,因为我们还需要去除多余的双引号。同样,这很容易添加到 sed 语句中

sed 's/%[0-9a-fA-F][0-9a-fA-F]/ /g;s/"//g'

这是最终脚本

grep 'google.com/search' $ACCESSLOG | \
  awk '{print $11}' | \
  cut -d\? -f2 | cut -d\& -f1 | \
  sed 's/+/ /g;s/%22/"/g;s/q=//' | \
  sed 's/%[0-9a-fA-F][0-9a-fA-F]/ /g;s/"//g' | \
  grep -v '=' | sort | uniq -c | sort -rn

以及最终结果

$ sh google-searches.sh | head -15
   6  NtUninstall
   5 standalone player
   4 psp music
   4 psp help
   4 creat a myspace
   4 Documents and Settings
   3 view myspace accounts that are set to private
   3 i cant hear music on runescape
   2 transfer files to psp
   2 sync v3 motorola mac
   2 running unix in windows xp
   2 rss feed reader shell
   2 reinstall windows xp hp
   2 psp transfer music
   2 psp internet

请注意,一旦我们删除了多余的材料,事情的组织方式会略有不同(例如,在这里您可以看到 psp music 是最热门的搜索之一,但之前我们有 psp music 的不同变体,并且它没有成为热门搜索值)。

好了,对 Apache 日志文件的折磨就到此为止。让我们总结一下,在下一专栏中我们将转向完全不同的内容!有什么建议吗?请通过电子邮件发送给我!

Dave Taylor 是 UNIX 领域的 26 年资深人士,The Elm Mail System 的创建者,最近还是畅销书 Wicked Cool Shell ScriptsTeach Yourself Unix in 24 Hours 的作者,这两本书只是他的 16 本技术书籍中的一部分。他的主要网站是 www.intuitive.com

加载 Disqus 评论