Texto entre duas tags

23

Eu quero recuperar o que estiver entre essas duas tags - <tr> </tr>- de um documento html. Agora não tenho requisitos específicos de html que justifiquem um analisador de html. Eu simplesmente precisa de algo que partidas <tr>e </tr>e fica tudo entre eles e poderia haver vários trs. Tentei o awk, o que funciona, mas, por algum motivo, acaba me fornecendo duplicatas de cada linha extraída.

awk '
/<TR/{p=1; s=$0}
p && /<\/TR>/{print $0 FS s; s=""; p=0}
p' htmlfile> newfile

Como fazer isso?

TechJack
fonte
IIUC seu script awk deve ser: '/<tr/{p=1}; p; /<\/tr>/{p=0}'. Poste algum exemplo de entrada e saída esperada se não funcionar.
Thor
desde que seu awkestá funcionando, mas dando duplicatas tentar passar a saída do seu awk de sort -ulevá-los distinta
igiannak

Respostas:

14

Se você quer apenas ...de todos, <tr>...</tr>faça:

grep -o '<tr>.*</tr>' HTMLFILE | sed 's/\(<tr>\|<\/tr>\)//g' > NEWFILE

Para multilinhas, faça:

tr "\n" "|" < HTMLFILE | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g;s/|/\n/g' > NEWFILE

Verifique o HTMLFILE primeiro do caractere "|" (não usual, mas possível) e, se existir, mude para um que não existe.

xx4h
fonte
1
Isso só funcionará se as tags de início e fim estiverem na mesma linha.
L0b0
echo "bla<tr>foo</tr>bla<tr>bar</tr>bla" | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g'fooblabar. O blanão deveria estar lá?
NN
@ l0b0 correto. vai para um compatível com
várias linhas
grep -Po '<tr>.*?</tr>'retornaria um resultado por linha no caso da @ NN, mas não é portátil.
L0b0
Não sei ao certo o que você quer dizer com 'specs' ou 'spec-style', mas observe que seu navegador da Web usa um analisador html e um analisador html analisará o html independentemente de como ele está escrito. Ele não analisará coisas que não são html, mas o navegador também não fará isso; portanto, ninguém se incomodará em escrever "html" que um analisador não pode analisar. Em outras palavras: um analisador decente é absolutamente sua melhor aposta para fazer isso.
GOLDILOCKS
11

Você tem um requisito que justifique um analisador de HTML: você precisa analisar o HTML. O HTML :: TreeBuilder do Perl , o BeautifulSoup do Python e outros são fáceis de usar, mais fáceis do que escrever expressões regulares complexas e quebradiças.

perl -MHTML::TreeBuilder -le '
    $html = HTML::TreeBuilder->new_from_file($ARGV[0]) or die $!;
    foreach ($html->look_down(_tag => "tr")) {
        print map {$_->as_HTML()} $_->content_list();
    }
' input.html

ou

python -c 'if True:
    import sys, BeautifulSoup
    html = BeautifulSoup.BeautifulSoup(open(sys.argv[1]).read())
    for tr in html.findAll("tr"):
        print "".join(tr.contents)
' input.html
Gilles 'SO- parar de ser mau'
fonte
9

sede awknão são adequados para esta tarefa, você deve usar um analisador de html adequado. Por exemplo, hxselectdo w3.org:

<htmlfile hxselect -s '\n' -c 'tr'
Thor
fonte
Não sei se o hxselect é a melhor escolha; Eu não o usei, mas a página de manual diz que "lê um documento XML bem formado", o que muitos documentos html não são. Provavelmente vale a pena tentar tho. As bibliotecas do analisador html disponíveis para perl, python, et. al. será muito melhor, se isso for uma opção.
GOLDILOCKS
2
@ goldilocks: A melhor escolha depende da situação. Na minha experiência, hxselectfaz um bom trabalho com documentos html / xml bem formados. Além disso, é mais rápido de usar do que perl, python e outros. Eu acho que hxselecté um bom meio termo entre sed/ awke as bibliotecas do analisador.
Thor
1
Se funcionar, está ótimo! Eu estava apenas adicionando uma advertência para o TechJack, caso não o fizesse - já que eu também recomendara o uso de algum tipo de analisador;) As bibliotecas de programação são obviamente mais estranhas, mas devem lidar com qualquer coisa remotamente passável como html.
25913 goldlocks
Thor, hxselectparece ser bom, definitivamente o explorará mais. Obrigado.
22413 TechJack
@ goldilocks: hxnormalizecuida de arquivos html / xml não bem formados.
tokland
5

Se rubyestiver disponível, você pode fazer o seguinte

ruby -e 'puts readlines.join[/(?<=<tr>).+(?=<\/tr>)/m].gsub(/<\/?tr>/, "")' file

Onde fileestá o seu arquivo html de entrada. O comando executa uma linha única do Ruby. Primeiro, ele lê todas as linhas de filee as une a uma string readlines.join. Em seguida, a partir da string seleciona qualquer coisa entre (mas não incluindo) <tr>e <\/tr>esse é um caractere ou mais, independentemente de novas linhas [/(?<=<tr>).+(?=<\/tr>)/m],. Em seguida, ele remove qualquer <tr>ou </tr>da string gsub(/<\/?tr>/, "")(isso é necessário para manipular trtags aninhadas ). Finalmente, imprime a string puts.

Você disse que um parser html não é garantido para você, mas é muito fácil de usar Nokogiri com rubye faz o comando mais simples.

ruby -rnokogiri -e 'puts Nokogiri::HTML(readlines.join).xpath("//tr").map { |e| e.content }' file

-rnokogiricarrega Nokogiri. Nokogiri::HTML(readlines.join)lê todas as linhas de file. xpath("//tr")seleciona cada trelemento e map { |e| e.content }o conteúdo de cada elemento, ou seja, o que está entre <tr>e </tr>.

NN
fonte
1

grep

Para recuperar o conteúdo dentro da trtag em várias linhas, passe-o xargsprimeiro, por exemplo:

curl -sL https://www.iana.org/ | xargs | egrep -o "<tr>.*?</tr>"

Para retornar apenas HTML interno, use:

curl -sL https://www.iana.org/ | xargs | grep -Po "<tr>\K(.*?)</tr>" | sed "s/..tr.//g"

Verifique a sintaxe para perlrepadrões estendidos .

Nota: Para obter um desempenho mais rápido, considere ripgrepqual possui sintaxe semelhante.

kenorb
fonte
imprimiu uma aparência mais agradável sem os xargs, veio a calhar para encontrar javascript embutido usando egrep -o "<script. *? </script>"
Andrew
0

pup

Exemplo de uso pup(que usa seletores CSS ):

pup -f myfile.html tr

Para imprimir apenas texto sem marcas, use: pup -f myfile.html tr text{}.

Aqui estão alguns exemplos com curl:

curl -sL https://www.iana.org/ | pup tr text{}
pup -f <(curl -sL https://www.iana.org/) tr text{}

xpup

Exemplo xpupde análise de HTML / XML (que suporta XPath):

xpup -f myfile.html "//tr"
kenorb
fonte
0

se for apenas uma lista rápida de <tr>s, isso pode ajudar:

perl -ne 'print if /<tr>/../</tr>/' your.html > TRs.log

Felicidades

eswues
fonte