Tekst między dwoma tagami


23

Chcę odzyskać wszystko, co znajduje się między tymi dwoma znacznikami - <tr> </tr>- z dokumentu HTML. Teraz nie mam żadnych konkretnych wymagań HTML, które uzasadniałyby parser HTML. Po prostu potrzebuję czegoś, co pasuje <tr>i </tr>dostaje wszystko pomiędzy, a może być wiele trs. Próbowałem awk, który działa, ale z jakiegoś powodu kończy się to otrzymaniem duplikatów każdego wyodrębnionego wiersza.

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

Jak sobie z tym poradzić?


IIUC skrypt awk powinno być: '/<tr/{p=1}; p; /<\/tr>/{p=0}'. Opublikuj przykładowe dane wejściowe i oczekiwane dane wyjściowe, jeśli to nie zadziała.
Thor

ponieważ twój awkdziała, ale sort -u
podajesz

Odpowiedzi:


14

Jeśli chcesz tylko ...wszystkich <tr>...</tr>:

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

W przypadku multilinii wykonaj:

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

Sprawdź HTMLFILE jako pierwszy znak „|” (nie zwykle, ale możliwe), a jeśli istnieje, zmień na taki, który nie istnieje.


1
Działa to tylko wtedy, gdy tagi początkowy i końcowy znajdują się w tej samej linii.
l0b0

echo "bla<tr>foo</tr>bla<tr>bar</tr>bla" | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g'daje fooblabar. Nie blapowinno tam być?
NN

@ L0B0 poprawne. pójdzie na kompatybilny z multilinią ...
xx4h

grep -Po '<tr>.*?</tr>'zwróci jeden wynik w wierszu w przypadku @ NN, ale nie jest przenośny.
l0b0

Nie jestem pewien, co rozumiesz przez „specyfikacje” lub „styl specyfikacji”, ale zauważ, że twoja przeglądarka używa parsera HTML, a parser HTML będzie analizował HTML niezależnie od tego, jak jest napisany. Nie będzie parsować rzeczy, które nie są HTML, ale wtedy również przeglądarka, więc nikt nie zawracałby sobie głowy pisaniem „HTML”, którego parser nie może przeanalizować. Innymi słowy: Przyzwoity parser jest absolutnie najlepszym rozwiązaniem.
goldilocks

11

Masz wymóg, który gwarantuje analizator składni HTML: musisz przeanalizować HTML. HTML :: TreeBuilder Perla , BeautifulSoup Pythona i inne są łatwe w użyciu, łatwiejsze niż pisanie złożonych i kruchych wyrażeń regularnych.

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

lub

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

9

sedi awknie nadają się do tego zadania, powinieneś raczej użyć odpowiedniego parsera HTML. Na przykład hxselectz w3.org:

<htmlfile hxselect -s '\n' -c 'tr'

Nie wiem, czy hxselect jest najlepszym wyborem; Nie korzystałem z niego, ale strona podręcznika mówi, że „czyta dobrze sformatowany dokument XML”, czego nie ma w wielu dokumentach HTML. Prawdopodobnie warto spróbować. Biblioteki parsera HTML dostępne dla Perla, Pythona i innych. glin. będzie znacznie lepiej, jeśli taka jest opcja.
goldilocks

2
@Goldilocks: Najlepszy wybór zależy od sytuacji. Z mojego doświadczenia hxselectwynika, że ​​dobrze sobie radzi z dobrze sformatowanymi dokumentami HTML / XML. Ponadto jest szybszy w użyciu niż Perl, Python i inne. Myślę, że hxselectto dobry środek między bibliotekami parser i sed/ awk.
Thor

1
Jeśli to działa, to świetnie! Właśnie dodałem ostrzeżenie dla TechJacka na wypadek, gdyby tak się nie stało - ponieważ zaleciłem także użycie jakiegoś parsera;) Liby programistyczne są oczywiście bardziej niezręczne, ale powinny radzić sobie z czymkolwiek zdalnie dostępnym jako HTML.
złotowłosa

Thor, hxselectwygląda dobrze, na pewno to odkryje. Dzięki.
TechJack

@goldilocks: hxnormalizezajmuje się niepoprawnie sformatowanymi plikami html / xml.
tokland

5

Jeśli rubyjest dostępny, możesz wykonać następujące czynności

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

gdzie filejest twój wejściowy plik HTML. Polecenie wykonuje Rubinowy jednowarstwowy. Po pierwsze, czyta wszystkie wiersze z filei dołącza je do łańcucha, readlines.join. Następnie z ciągiem wybiera coś pomiędzy (ale nie włącznie) <tr>i <\/tr>to jest jeden znak lub dłużej niezależnie od nowej linii, [/(?<=<tr>).+(?=<\/tr>)/m]. Następnie usuwa dowolny ciąg <tr>lub </tr>ciąg gsub(/<\/?tr>/, "")(jest to konieczne do obsługi zagnieżdżonych trznaczników). Wreszcie, drukuje ciąg, puts.

Powiedziałeś, że parser HTML nie jest dla ciebie uzasadniony, ale jest bardzo łatwy w użyciu z Nokogiriruby i sprawia, że ​​polecenie jest prostsze.

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

-rnokogiriładuje Nokogiri. Nokogiri::HTML(readlines.join)czyta wszystkie linie file. xpath("//tr")wybiera każdy trelement i map { |e| e.content }wybiera zawartość dla każdego elementu, tj. co znajduje się pomiędzy <tr>i </tr>.


1

grep

Aby pobrać treść w obrębie trznacznika w wielu wierszach, xargsnajpierw przepisz ją , na przykład:

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

Aby zwrócić tylko wewnętrzny HTML, użyj:

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

Sprawdź składnię dla perlrerozszerzonych wzorców .

Uwaga: w celu zwiększenia wydajności można rozważyć, ripgrepktóra ma podobną składnię.


wydrukowano ładniej wyglądając bez xargs, przydał się do znalezienia wbudowanego javascript za pomocą egrep -o "<skrypt. *? </script>"
Andrew

0

pup

Przykład użycia pup(który korzysta z selektorów CSS ):

pup -f myfile.html tr

Aby wydrukować tylko tekst bez użycia tagów: pup -f myfile.html tr text{}.

Oto kilka przykładów z curl:

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

xpup

Przykład użycia xpupdo analizowania HTML / XML (który obsługuje XPath):

xpup -f myfile.html "//tr"

0

jeśli jest to tylko krótka lista, <tr>może to pomóc:

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

Twoje zdrowie

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.