Text-Processing

從日誌文件中的 URL 獲取查詢字元串

  • November 15, 2016

我有一個伺服器日誌文件,其中包含以下格式的許多日誌條目:

193.1.172.46 - - [23/Mar/2008:03:57:38 +0000] "GET /robots.txt HTTP/1.0" 404 289 "-" "gsa-crawler (Enterprise; M2-N7RQ5RABCA2JT; unix@ucd.ie,fergal@ucd.ie)"

我被要求辨識所有使用 Google 搜尋引擎的條目,然後從中獲取查詢字元串,並僅在輸出中顯示查詢字元串。

所以我使用 grep 命令來辨識所有訪問搜尋引擎的條目,如下所示:

grep "http://www.google.com/search?" logs.txt 

這給了我一個這樣的條目列表:

143.183.121.3 - - [23/Mar/2008:00:16:59 +0000] "GET /staff/jcarthy/home/2ndYearUnix/usefulcommands2col.pdf HTTP/1.0" 200 78866 "http://www.google.com/search?hl=en&q=frequently+used+unix+aliases&btnG=Google+Search"; "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)"

我現在如何只顯示僅顯示條目的 hl=en&q=frequently+used+unix+aliases&btnG=Google+Search 部分的列表?

此處的所有其他解決方案可能會在某些日誌條目上失敗,例如,在引用欄位內帶有空格或額外引號和反斜杠、大寫域名、https 而不是 http,或位置欄位和引用欄位內的關鍵字.

例如:

1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /a b/ HTTP/1.0" 200 0 "http://www.google.com/search?..." "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /i/love/http://www.google.com/search?ing HTTP/1.0" 200 0 "http://www.google.com/search?..." "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET / HTTP/1.0" 200 0 "http://www.google.com/search?spaces in referrer" "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /nohttpver" 200 0 "http://www.google.com/search?spaces in referrer" "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /" 200 0 "http://example.org/http://www.google.com/search?spaces in referrer" "Mozilla/4.0"
1.2.3.4 - - [23/Mar/2008:00:16:59 +0000] "GET /" 200 0 "http://WWW.GOOGLE.COM/search?spaces in referrer" "Mozilla/4.0"

為了處理這些,我們首先需要正確提取第二個雙引號欄位。請注意,Apache 日誌文件使用反斜杠來轉義多餘的引號或其他特殊字元。這意味著諸如天真的正則表達式"[^"]*"還不夠好。

使用 grep 提取引用欄位(第二個雙引號欄位):

grep -oP '^[^"]+"[^"\\]*(?:\\.[^"\\]*)*"[^"]+"\K[^"\\]*(?:\\.[^"\\]*)*(?=")' logfile.txt

看起來很瘋狂!讓我們分解一下:

  • o參數grep意味著我們只得到該行的匹配部分,而不是它的其餘部分
  • P參數grep告訴它使用 Perl 兼容的正則表達式
  • 此處使用的正則表達式的整體結構...\K...(?=...), 表示我們正在檢查整個模式,但只會輸出the\K和 the之間的內容(?=...)

進一步分解正則表達式:

  1. ^[^"]+- 獲取行首和第一行之間的所有內容"
  2. "[^"\\]*(?:\\.[^"\\]*)*"– 獲取整個第一個雙引號字元串。看到這個答案https://stackoverflow.com/a/5696141/1764245
  3. [^"]+– 獲取兩個字元串之間的所有內容
  4. "\K[^"\\]*(?:\\.[^"\\]*)*(?=")與上面相同,但我們\K在 first 之後"開始匹配數據,(?=")在 last 之前停止匹配數據"

在這一點之後,數據將更容易處理,因為您不再需要擔心引號和從日誌文件中正確提取欄位。

例如,您可以將輸出通過管道傳輸到另一個 grep:

grep -oP ... logfile.txt | grep -oPi '^https?://www\.google\.com/search\?\K.*'

這裡i第二個 grep 的選項使其不區分大小寫。

或者,您可以將google.com引用者開頭的檢查直接添加到第一個正則表達式中並\K酌情移動,但我建議不要這樣做,因為最好執行兩個正則表達式,它們都做一項工作並且做得很好將它們組合成一個工作不明確的地方。

請注意,如果您想從其他 Google 域收集引薦來源網址,則需要稍微修改您的正則表達式。Google擁有很多搜尋域

如果您不介意可能會擷取一些非 Google 網站,您可以這樣做:

... | grep -oPi '^https?://(www\.)?google\.[a-z]{2,3}(\.[a-z]{2})?/search\?\K.*'

否則,您將需要嘗試僅匹配 Google 擁有的搜尋域,這是一個不斷變化的目標:

... | grep -oPi '^https?://(www\.)?google\.(a[cdelmstz]|b[aefgijsty]|cat|c[acdfghilmnvz]|co\.(ao|bw|c[kr]|i[dln]|jp|k[er]|ls|m[az]|nz|t[hz]|u[gkz]|v[ei]|z[amw])|com(\.(a[fgiru]|b[dhnorz]|c[ouy]|do|e[cgt]|fj|g[hit]|hk|jm|k[hw]|l[bcy]|m[mtxy]|n[afgip]|om|p[aeghkry]|qa|s[abglv]|t[jrw]|u[ay]|v[cn]))?|d[ejkmz]|e[es]|f[imr]|g[aefglmpry]|h[nrtu]|i[emoqst]|j[eo]|k[giz]|l[aiktuv]|m[degklnsuvw]|n[eloru]|p[lnst]|r[osuw]|s[cehikmnort]|t[dgklmnot]|us|v[gu]|ws)/search\?\K.*'

另請注意,如果要包含 Google 的圖像搜尋和其他搜尋子域,則需要將(www\.)?上述 grep 命令之一中的更改為((www|images|other|sub|domains)\.)?.

通用版本

awk '$11 ~ /?/ { printf "%s\n",substr($11,1+index($11,"?")) ;}'

在哪裡

  • $11 ~ /\?/搜尋 ?在網址中
  • substr($11,1+index($11,"?")之後搜尋部分?
  • 請注意,不解析參數。
  • 這不會取消轉義 URL(例如space將顯示為%20

以前的版本

awk '$11 ~ /http:\/\/www.google.com\/search?/ { print substr($11,26) ;}' 

在哪裡

引用自:https://unix.stackexchange.com/questions/323016