Como usar o grep e recortar o script para obter URLs de sites de um arquivo HTML

21

Estou tentando usar grep e recortar para extrair URLs de um arquivo HTML. Os links são parecidos com:

<a href="http://examplewebsite.com/">

Outros sites têm .net, .govmas eu suponho que eu poderia fazer o corte fora do ponto certo antes >. Então, eu sei que posso usar grep e cut de alguma forma para cortar tudo antes de http e depois de .com, mas estou preso há um tempo.

eltigre
fonte
Eu editei. Para alguns ignorar o espaço entre <e a, o HTML não apareceria sem ele. Obrigado por capturar isso!
Eltigre
Use a formatação do código (selecione o texto e pressione Ctrl-K). Caso contrário, as <>forças a serem vistas como uma tag HTML.
muru
por que não coincidir com a citação de abertura e final do parâmetro href? Além disso, acredito que expressões regulares não são mais adequadas para html.
把友情留在无盐
Eu quero escrever um comando usando especificamente grep e cut para fazer isso. Sei que existem outras maneiras, mas eu queria saber sobre elas.
Eltigre
9
Em geral, não é uma boa ideia analisar o HTML com expressões regulares, pois o HTML não é uma linguagem comum. Se você pode garantir que o HTML que você está analisando é bastante simples, e o material que você está tentando extrair é previsível, você poderá se safar. Mas, por favor, veja stackoverflow.com/a/1732454/4014959
PM 2Ring

Respostas:

25

Como eu disse no meu comentário, geralmente não é uma boa ideia analisar HTML com Expressões regulares, mas às vezes você pode se safar se o HTML que estiver analisando for bem-comportado.

Para obter apenas URLs que estão no hrefatributo de <a>elementos, acho mais fácil fazê-lo em vários estágios. A partir dos seus comentários, parece que você deseja apenas o domínio de nível superior, não o URL completo. Nesse caso, você pode usar algo como isto:

grep -Eoi '<a [^>]+>' source.html |
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

onde source.htmlé o arquivo que contém o código HTML para analisar.

Este código imprimirá todos os URLs de nível superior que ocorrem como hrefatributo de qualquer <a>elemento em cada linha. A -iopção para o primeiro grepcomando é garantir que ele funcione nos elementos <a>e <A>. Eu acho que você também pode dar -iao segundo greppara capturar HREFatributos em maiúsculas , OTOH, eu prefiro ignorar HTML quebrado. :)

Para processar o conteúdo de http://google.com/

wget -qO- http://google.com/ |
grep -Eoi '<a [^>]+>' | 
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

saída

http://www.google.com.au
http://maps.google.com.au
https://play.google.com
http://www.youtube.com
http://news.google.com.au
https://mail.google.com
https://drive.google.com
http://www.google.com.au
http://www.google.com.au
https://accounts.google.com
http://www.google.com.au
https://www.google.com
https://plus.google.com
http://www.google.com.au

Minha saída é um pouco diferente dos outros exemplos, pois sou redirecionado para a página australiana do Google.

PM 2Ring
fonte
OBRIGADO. Agora, isso é exatamente o que eu estava procurando. Esta é a maneira mais limpa de fazer isso.
Eltigre
@eltigre: O prazer é meu! Mas preste atenção ao aviso ao qual vinculei meu comentário acima. :)
PM 2Ring
Eu vim a esta pergunta esperando pontos fáceis ... e você já tinha batido o prego na cabeça completamente
Mark K Cowan
Obrigado, @MarkKCowan. :) FWIW, originalmente comecei a escrever uma resposta usando o awk, mas depois decidi que uma solução baseada em grep seria mais fácil de entender para aqueles que não estão familiarizados com o awk. De qualquer forma, o código acima é mais curto que o meu código awk.
usar o seguinte comando
2
@mavavilj: Como o OP queria apenas o domínio de nível superior, então após o ://aceitamos apenas caracteres antes do primeiro /ou ". Mas se você quiser ver a URL completa, altere esse comando para grep -Eo '(http|https)://[^"]+. Outra opção para essa linha é grep -Eo '(http|https)://[^?"]+'que corta as opções de consulta. No entanto, essa variação ainda imprimirá URLs contidos em outro URL como parâmetro de consulta, mas eles serão impressos em uma linha separada.
PM 2Ring
25

Não tenho certeza se você está limitado em ferramentas:

Mas regex pode não ser o melhor caminho a percorrer, como mencionado, mas aqui está um exemplo que reuni:

cat urls.html | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
  • grep -E: é o mesmo que egrep
  • grep -o: gera apenas o que foi recebido
  • (http | https): é um / ou
  • az: é tudo em minúsculas
  • AZ: é todo o caso
  • . : é ponto
  • \?: é ?
  • *: repete o grupo [...]
  • uniq: remove todas as duplicatas

Saída:

bob@bob-NE722:~s$  wget -qO- https://stackoverflow.com/ | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
https://stackauth.com
https://meta.stackoverflow.com
https://cdn.sstatic.net/Img/svg-icons
https://stackoverflow.com
https://www.stackoverflowbusiness.com/talent
https://www.stackoverflowbusiness.com/advertising
https://stackoverflow.com/users/login?ssrc=head
https://stackoverflow.com/users/signup?ssrc=head
https://stackoverflow.com
https://stackoverflow.com/help
https://chat.stackoverflow.com
https://meta.stackoverflow.com
...

Você também pode adicionar \dpara capturar outros tipos de números.

jmunsch
fonte
2
IRI regexes! Use um deles e assuste o OP! :)
muru
2
@ muru ... tremendo eu ... eu não sei o que dizer. São mesmo reais !?
precisa saber é
4
@jmunsch, uniq apenas remova duplicatas adjacentes. sort -u?
precisa saber é
11
funciona muito bem, melhor resposta !!
Gery
@JJoao é a fonte para a classificação -u mais rápido que a tubulação? Apenas um experimento mental, eu tenho que procurar. Mas você provavelmente está certo sobre o middleware do shell.
jmunsch
9

Se o seu grep suportar as expressões regulares Perl:

grep -Po '(?<=href=")[^"]*(?=")'
  • (?<=href=")e (?=")são expressões de busca para o hrefatributo. Isso precisa da -Popção.
  • -o imprime o texto correspondente.

Por exemplo:

$ curl -sL https://www.google.com | grep -Po '(?<=href=")[^"]*(?=")'
/search?
https://www.google.co.in/imghp?hl=en&tab=wi
https://maps.google.co.in/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
https://www.youtube.com/?gl=IN&tab=w1
https://news.google.co.in/nwshp?hl=en&tab=wn
...

Como de costume, não há garantia de que sejam URIs válidos ou que o HTML que você está analisando seja válido.

muru
fonte
8

Como alternativa não regex , use pup :

pup 'a[href] attr{href}' < yourfile.html

Encontrará todos os aelementos que possuem um hrefatributo e exibirá o valor do hrefatributo.

Para instalar pup, você precisa do Go (uma linguagem de programação):

sudo apt-get install golang
sudo go get github.com/ericchiang/pup

A vantagem desta solução é que ela não depende do HTML estar formatado corretamente .

Kroltan
fonte
11
+1 para pup, na hora de instalar que ....
Mark K Cowan
Você pode colocá-los em arquivo também. pup 'a.classname[href] attr{href}' < tut.html >links.md
Ahmad Awais
1

Eu encontrei uma solução aqui que é IMHO muito mais simples e potencialmente mais rápida do que o que foi proposto aqui. Eu ajustei um pouco para suportar arquivos https. Mas a versão TD; TR é ...

PS: Você pode substituir o URL do site por um caminho para um arquivo e ele funcionará da mesma maneira.

lynx -dump -listonly -nonumbers "http://www.goggle.com" > links.txt

lynx -dump -listonly -nonumbers "some-file.html" > links.txt

Se você quiser apenas ver os links em vez de colocá-los em um arquivo, tente fazer isso ...

lynx -dump -listonly -nonumbers "http://www.google.com"

lynx -dump -listonly -nonumbers "some-file.html"

O resultado será semelhante ao seguinte ...

http://www.google.ca/imghp?hl=en&tab=wi
http://maps.google.ca/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?gl=CA&tab=w1
http://news.google.ca/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
https://www.google.ca/intl/en/options/
http://www.google.ca/history/optout?hl=en
...
etc.

Para o meu caso de uso, isso funcionou bem. Mas cuidado com o fato de que hoje em dia, as pessoas adicionam links como src = "// blah.tld" para o CDN URI das bibliotecas. Eu não queria ver aqueles nos links recuperados.

Não é necessário tentar verificar href ou outras fontes quanto a links, porque "lynx -dump" extrai por padrão todos os links clicáveis ​​de uma determinada página. Portanto, a única coisa que você precisa fazer depois disso é analisar o resultado do "lynx -dump" usando o grep para obter uma versão bruta mais limpa do mesmo resultado.

asiby
fonte
Mas a pergunta diz "extrair URLs de um arquivo HTML [que parece]" (exemplo), NÃO "extrair URLs de uma página da web". Se sua resposta puder ser usada em um arquivo que está na máquina local, explique como. Por favor, não responda nos comentários; edite sua resposta para torná-la mais clara e completa.
G-Man diz 'Reinstate Monica'
11
Você pode substituir o URL por um nome de arquivo.
Asiby
@ G-Man, por que o -1? Você precisa experimentar o código e verificar se ele também funciona para arquivos locais. Eu adicionei esse esclarecimento caso não fosse óbvio.
precisa
Isso é realmente útil .. se você estiver usando o xargs, vale a pena adicionar | ordenar | uniq para aparar os links duplicados.
Stuart Axon #
0
wget -qO- google.com |
tr \" \\n | grep https\*://

... provavelmente faria muito bem. Como está escrito, ele imprime:

http://schema.org/WebPage
http://www.google.com/imghp?hl=en&tab=wi
http://maps.google.com/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?tab=w1
http://news.google.com/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
http://www.google.com/intl/en/options/
http://www.google.com/history/optout?hl=en
https://accounts.google.com/ServiceLogin?hl=en&continue=http://www.google.com/
https://www.google.com/culturalinstitute/project/the-holocaust?utm_source=google&amp;utm_medium=hppromo&amp;utm_campaign=auschwitz_q1&amp;utm_content=desktop
https://plus.google.com/116899029375914044550

Se for importante que você corresponda apenas a links e dentre esses domínios de nível superior, você pode:

wget -qO- google.com |
sed '/\n/P;//!s|<a[^>]*\(https*://[^/"]*\)|\n\1\n|;D'

... ou algo parecido - embora, para alguns seds, seja necessário substituir um \ncaractere literal de linha por cada um dos dois últimos ns.

Conforme escrito, o comando acima é impresso:

http://www.google.com
http://maps.google.com
https://play.google.com
http://www.youtube.com
http://news.google.com
https://mail.google.com
https://drive.google.com
http://www.google.com
http://www.google.com
http://www.google.com
https://www.google.com
https://plus.google.com

... e em ambos os casos (mas provavelmente com mais utilidade com o último), você pode aplicar um |sort -ufiltro até o final para obter a lista sorte eliminar duplicatas.

mikeserv
fonte
0

Mais curto

grep -r http . --color
golpear
fonte
-1
echo "<a href="http://examplewebsite.com/">"|sed -r 's:<.*"::g'|sed 's:/">$::g'
Praveen Kumar BS
fonte
Não tenho certeza de que essas aspas "inteligentes" sejam o que você pretendia lá - talvez citações "duplas" regulares?
Jeff Schaller