私のウェブサイトを訪問する各ユーザー(IPアドレス)が一連のページを見ている時間を比較して、ウェブサイト上の人ではなく活動を識別し、IPアドレスを分析から除外したいと思います。
私はawkを学び、改善したいので、できるだけ使いたいです(私はGAWKを使っています)。しかし、私はbashで他のツールを使用するためにオープンです。
次の形式の変更されたログファイル(output.csv)があります。
29/Oct/2020:07:41:42|111.111.111.111|200|/page-a/
29/Oct/2020:08:30:40|000.111.026.111|200|/page-a/
29/Oct/2020:08:30:44|000.111.026.111|200|/page-b/
29/Oct/2020:08:30:45|000.111.026.111|200|/page-c/
29/Oct/2020:08:30:47|000.111.026.111|200|/page-d/
29/Oct/2020:08:30:47|220.171.008.221|200|/page-h/
29/Oct/2020:08:30:48|000.111.026.111|200|/page-e/
29/Oct/2020:08:41:49|221.651.943.323|200|/page-a/
29/Oct/2020:08:41:52|060.121.125.144|200|/page-f/
29/Oct/2020:08:41:52|060.121.125.144|200|/page-g/
29/Oct/2020:08:41:54|000.111.026.111|200|/page-k/
29/Oct/2020:08:41:55|060.121.125.144|200|/page-l/
29/Oct/2020:08:41:57|060.121.125.144|200|/page-n/
29/Oct/2020:08:41:58|060.121.125.144|200|/page-s/
私は次のことをしたいと思います:
- すべての一意のIP検索
output.csv
- このIPのインスタンスが5つ以上の場合は、各行の最初の日付/時刻と5番目の日付/時刻の差(秒単位)を計算します。
- 15秒以内に5ページに接続したIPアドレスの分離
- この IP アドレスを次に追加します。
file.txt
私が試したこと
特定の数のIPアドレスインスタンス間の時間差(秒)を取得するには、次のコマンドセットを使用しました。
egrep "000.111.000.111" output.csv | awk 'BEGIN{FS="|"; ORS=" "} NR==1 || NR==5 {print $1,$2}' | sed -e 's/[\/:]/\ /g' -e 's/Jan/1/g' -e 's/Feb/2/g' -e 's/Mar/3/g' -e 's/Apr/4/g' -e 's/May/5/g' -e 's/Jun/6/g' -e 's/Jul/7/g' -e 's/Aug/8/g' -e 's/Sep/9/g' -e 's/Oct/10/g' -e 's/Nov/11/g' -e 's/Dec/12/g' | awk '{print $3,$2,$1,$4,$5,$6 "," $10,$9,$8,$11,$12,$13","$14}' | awk -F, '{d2=mktime($2);d1=mktime($1);print d2-d1, $3}' | awk '{if($1<15)print $2}' >> file.txt
特定のIPアドレスが15秒以内に5ページにアクセスすると、上記のコマンドはIPをファイルに追加します。
これが機能している間は、単一のコマンド/スクリプトですべての一意のIPでこれを行う方法を探しています。
私も面倒だと思うので、よりエレガントなアプローチで開いています。
希望する結果
望ましい結果は、14秒間に5ページ以上の速度でサーバーにアクセスしたIPアドレスのリストを含むファイルです(時間調整可能)。
例えば。file.txt
上記の例によると、内容は次のとおりです。
000.111.026.111
060.121.125.144
理想的には、あなたの方法を段階的に説明し、それがどのように機能するかを説明していただきありがとうございます。これは私が学ぶのに役立ちます。
ベストアンサー1
GNU awkを使用してmktime()を実行します。
$ cat tst.awk
BEGIN { FS = "|" }
(++count[$2]) ~ /^[15]$/ {
split($1,t,"[/:]")
monthNr = (index("JanFebMarAprMayJunJulAugSepOctNovDec",t[2])+2)/3
currSecs = mktime(t[3] " " monthNr " " t[1] " " t[4] " " t[5] " " t[6])
if ( count[$2] == 1 ) {
firstSecs[$2] = currSecs
}
else if ( (currSecs - firstSecs[$2]) < 15 ) {
print $2
}
}
$ awk -f tst.awk file
000.111.026.111
060.121.125.144
私はこれが何をしているのかは非常に明確だと思うので、テキストの説明を追加する必要はありませんが、質問があればいつでもお問い合わせください。
ああ、特定の問題を解決するのに十分な包括的な例を投稿できるように、IPアドレスをダミー値に変換する方法を知りたいとコメントしています。
$ awk '
BEGIN { FS=OFS="|" }
!($2 in map) { ip=sprintf("%012d",++cnt); gsub(/.../,"&.",ip); sub(/.$/,"",ip); map[$2]=ip }
{ $2=map[$2]; print }
' file
29/Oct/2020:07:41:42|000.000.000.001|200|/page-a/
29/Oct/2020:08:30:40|000.000.000.002|200|/page-a/
29/Oct/2020:08:30:44|000.000.000.002|200|/page-b/
29/Oct/2020:08:30:45|000.000.000.002|200|/page-c/
29/Oct/2020:08:30:47|000.000.000.002|200|/page-d/
29/Oct/2020:08:30:47|000.000.000.003|200|/page-h/
29/Oct/2020:08:30:48|000.000.000.002|200|/page-e/
29/Oct/2020:07:41:49|000.000.000.004|200|/page-a/
29/Oct/2020:08:41:52|000.000.000.005|200|/page-f/
29/Oct/2020:08:41:52|000.000.000.005|200|/page-g/
29/Oct/2020:08:41:54|000.000.000.002|200|/page-k/
29/Oct/2020:08:41:55|000.000.000.005|200|/page-l/
29/Oct/2020:08:41:57|000.000.000.005|200|/page-n/
29/Oct/2020:08:41:58|000.000.000.005|200|/page-s/
編集:私のスクリプトで生成された出力と実行されたDavesスクリプトのバージョンで生成された出力の違いを調べることができます。
$ awk -f morton-botfilter.awk.txt output3test.csv > morton.out
$ awk -f dave-botfilter.awk.txt output3test.csv > dave.out
$ ip=$(comm -13 <(sort morton.out) <(sort dave.out) | head -1)
$ grep "$ip" output3test.csv | head -5
03/Nov/2020:07:52:55|000.000.000.007|200|/page-7/
03/Nov/2020:08:05:32|000.000.000.007|200|/page-11/
03/Nov/2020:11:28:56|000.000.000.007|200|/page-77/
03/Nov/2020:13:52:32|000.000.000.007|200|/page-143/
03/Nov/2020:13:52:33|000.000.000.007|200|/page-144/
上記の最初のタイムスタンプと最後のタイムスタンプの間の間隔が15秒をはるかに超えることに注意してください。これは、dave-botfilter.awk.txt のスクリプトが破損していることを示します。詳しくは下記のコメントをご覧ください。