Obtém a string de consulta de URLs em um arquivo de log

4

Eu tenho um arquivo de log do servidor que contém várias entradas de log no seguinte formato:

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

Fizemos uma solicitação para identificar todas as entradas que usam o mecanismo de pesquisa do Google e, em seguida, tirar a string de consulta delas e exibir apenas a string de consulta na saída.

Então usei o comando grep para identificar todas as entradas que acessam o mecanismo de pesquisa da seguinte forma:

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

que me fornece uma lista de entradas como esta:

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)"

Como faço para exibir a lista apenas com a parte hl = en & q = freqüentemente + usada + unix + aliases & btnG = Google + Search da entrada exibida?

    
por Joe 13.11.2016 / 18:54

5 respostas

1

Aqui está uma abordagem sed razoavelmente legível

$ cat log.txt | grep "http://www.google.com/search?" | sed  s/^.*search?// | sed s/\"\;.*//

ou seja,

Remova o início da linha com:

s/   # replace a match which is:
  ^       # from the start of the line
  .*      # any number of any characters
  search? # the text "search?"
//   # with nothing (remove it)

depois, remova o final da linha com

s/    # replace a match which is:
  \"    # a double quote (escaped with backslash)
  \;    # a semicolon (escaped with backslash)
  .*    # any number of characters
//    # with nothing (remove it)

deixando apenas os parâmetros

    
por 14.11.2016 / 02:57
4

Todas as outras soluções aqui provavelmente falharão em algumas entradas de log, por exemplo. aqueles com espaços dentro do campo de referência ou aspas extras e barras invertidas, nomes de domínio de maiúsculas, https em vez de http, ou palavras-chave dentro do campo de localização, bem como o campo de referência.

Por exemplo:

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"

Para lidar com isso, primeiro precisamos extrair adequadamente o segundo campo com aspas duplas . Observe que os arquivos de log do Apache usam barras invertidas para evitar citações extras ou outros caracteres especiais. Isso significa que expressões regulares ingênuas como "[^"]*" não são boas o suficiente.

Usando o grep para extrair o campo de referência (segundo campo de aspas duplas):

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

Parece loucura! Vamos dividir:

  • O argumento o para grep significa que acabamos de obter a parte correspondente da linha, não o restante dela
  • O argumento P para grep diz para usar expressões regulares compatíveis com Perl
  • A estrutura geral da expressão regular em uso aqui, ...\K...(?=...) , significa que estamos verificando o padrão inteiro, mas apenas as coisas entre o \K e o (?=...) serão produzidas

Quebrar ainda mais a expressão regular:

  1. ^[^"]+ - Obtenha tudo entre o início da linha e o primeiro "
  2. "[^"\]*(?:\.[^"\]*)*" - obtém toda a primeira cadeia entre aspas duplas. Veja esta resposta link
  3. [^"]+ - obtém tudo entre as duas strings
  4. "\K[^"\]*(?:\.[^"\]*)*(?=") O mesmo que acima, mas temos o \K após o primeiro " para iniciar os dados correspondentes depois disso e o (?=") para parar os dados correspondentes antes do último " .

Após este ponto, os dados serão muito mais fáceis de processar, porque você não precisa mais se preocupar com as aspas e extrair o campo corretamente do arquivo de log.

Por exemplo, você pode enviar a saída para outro grep:

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

Aqui, a opção i para o segundo grep não faz distinção entre maiúsculas e minúsculas.

Como alternativa, você pode adicionar a verificação do início do google.com referrer diretamente na primeira expressão regular e mover \K conforme apropriado, mas eu recomendaria isso, pois é melhor executar duas expressões regulares que ambos fazem um trabalho e fazem bem do que combiná-los em um, onde o seu trabalho não é claro.

Observe que, se você quiser coletar referências de outros domínios do Google, precisará modificar sua expressão regular um pouco. O Google possui muitos domínios de pesquisa .

Se você não se importasse de pegar potencialmente alguns sites que não são do Google, poderia fazer:

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

Caso contrário, você precisará tentar corresponder apenas aos domínios de pesquisa de propriedade do Google, que é um alvo em constante movimento:

... | 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.*'

Além disso, observe se você deseja incluir a pesquisa de imagens do Google e outros subdomínios de pesquisa, você precisará alterar o (www\.)? em um dos comandos grep acima para algo como ((www|images|other|sub|domains)\.)? .

    
por 14.11.2016 / 10:24
3

uma versão genérica

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

onde

  • $11 ~ /\?/ procura? na URL
  • substr($11,1+index($11,"?") procura parte depois?
  • observe que os argumentos não são analisados.
  • isto não irá remover o URL (por exemplo, espaço será mostrado como %20 )

versão anterior

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

onde

  • $11 é o número de referências de campo, talvez seja necessário ajustar
  • 28 é o tamanho do " link ?"
por 13.11.2016 / 19:08
0

Acho que descobri.

grep "http://www.google.com/search?" logs.txt | cut -d" " -f11 |  sed -r 's/^.{30}//'

Isto parece ser uma solução aceitável?

    
por 14.11.2016 / 02:24
0
awk -F"[?|;]" '/google.com\/search/{print $2}' log.txt

awk -F? '/google.com\/search/{gsub(";.*","",$2);print $2}' log.txt
    
por 14.11.2016 / 03:18