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.


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.


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.


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.


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 .


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.


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.



-1
echo "<a href="http://examplewebsite.com/">"|sed -r 's:<.*"::g'|sed 's:/">$::g'

Não tenho certeza de que essas aspas "inteligentes" sejam o que você pretendia lá - talvez citações "duplas" regulares?
— Jeff Schaller
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.