Text zwischen zwei Tags

23

Ich möchte abrufen, was sich zwischen diesen beiden Tags befindet - <tr> </tr>- aus einem HTML-Dokument. Jetzt habe ich keine spezifischen HTML-Anforderungen, die für einen HTML-Parser gerechtfertigt wären. Ich brauche einfach etwas, das passt <tr>und </tr>und alles dazwischen bekommt und es könnte mehrere trs geben. Ich habe awk ausprobiert, was funktioniert, aber aus irgendeinem Grund gibt es mir Duplikate jeder extrahierten Zeile.

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

Wie geht man vor?

TechJack
quelle
IIUC Ihre awk - Skript soll '/<tr/{p=1}; p; /<\/tr>/{p=0}'. Posten Sie einige Beispieleingaben und erwartete Ausgaben, wenn dies nicht funktioniert.
Thor
Da Sie awkarbeiten, aber geben Sie Duplikate, versuchen Sie, die Ausgabe Ihrer awk von sort -uzu übergeben, um sie zu unterscheiden
igiannak

Antworten:

14

Wenn du nur ...alles machen <tr>...</tr>willst:

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

Für mehrzeilige tun:

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

Überprüfen Sie zuerst die HTML-Datei des Zeichens "|" (nicht üblich, aber möglich) und wenn es existiert, wechseln Sie zu einem, der nicht existiert.

xx4h
quelle
1
Das funktioniert nur, wenn die Start- und End-Tags in derselben Zeile stehen.
10.
echo "bla<tr>foo</tr>bla<tr>bar</tr>bla" | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g'gibt fooblabar. Der blasollte nicht da sein?
NN
@ l0b0 richtig. wird für eine Multiline-kompatible gehen ...
xx4h
grep -Po '<tr>.*?</tr>'würde ein Ergebnis pro Zeile in @ NNs Fall zurückgeben, aber es ist nicht portierbar.
10.
Ich bin mir nicht sicher, was Sie mit "Spezifikationen" oder "Spezifikationsstil" meinen, aber beachten Sie, dass Ihr Webbrowser einen HTML-Parser verwendet und ein HTML-Parser HTML unabhängig von der Schreibweise analysiert. Es werden keine Dinge analysiert, die nicht HTML sind, aber auch nicht Ihr Browser, sodass sich niemand die Mühe macht, "HTML" zu schreiben, das ein Parser nicht analysieren kann. Mit anderen Worten: Ein anständiger Parser ist mit Sicherheit die beste Wahl dafür.
Goldlöckchen
11

Sie haben eine Anforderung, die einen HTML-Parser gewährleistet: Sie müssen HTML analysieren. Perls HTML :: TreeBuilder , Pythons BeautifulSoup und andere sind einfach zu verwenden und einfacher als das Schreiben komplexer und spröder regulärer Ausdrücke.

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

oder

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 - hör auf böse zu sein'
quelle
9

sedund awksind nicht gut für diese Aufgabe geeignet, sollten Sie lieber einen richtigen HTML-Parser verwenden. Zum Beispiel hxselectvon w3.org:

<htmlfile hxselect -s '\n' -c 'tr'
Thor
quelle
Ich weiß nicht, ob hxselect die beste Wahl ist. Ich habe es nicht benutzt, aber die Manpage sagt "liest ein wohlgeformtes XML-Dokument", was viele HTML-Dokumente nicht sind. Wahrscheinlich einen Versuch wert. Die HTML-Parser-Bibliotheken für Perl, Python, et. al. wird viel besser sein, wenn das eine Option ist.
Goldlöckchen
2
@goldilocks: Die beste Wahl hängt von der Situation ab. Meiner Erfahrung nach hxselectmacht es ziemlich gute Arbeit mit wohlgeformten HTML / XML-Dokumenten. Außerdem ist es schneller zu bedienen als Perl, Python und andere. Ich denke, es hxselectist ein guter Mittelweg zwischen sed/ awkund Parser-Bibliotheken.
Thor,
1
Wenn es funktioniert, ist das großartig! Ich habe nur eine Einschränkung für TechJack hinzugefügt, falls dies nicht der Fall war - da ich auch empfohlen hatte, eine Art Parser zu verwenden;) Die Programmierbibliotheken sind natürlich umständlicher, sollten sich aber mit allem befassen, das aus der Ferne als HTML passierbar ist.
Goldlöckchen
Thor, hxselectsieht gut aus, wird es auf jeden Fall mehr erforschen. Vielen Dank.
TechJack
@goldilocks: hxnormalizekümmert sich um nicht wohlgeformte HTML / XML-Dateien.
Tokland
5

Wenn rubyverfügbar, können Sie Folgendes tun

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

Wo fileist Ihre Eingabe-HTML-Datei. Der Befehl führt einen Ruby-Einzeiler aus. Zuerst liest es alle Zeilen aus fileund fügt sie zu einem String zusammen readlines.join. Dann wählt es aus der Zeichenfolge etwas zwischen (aber nicht einschließlich) <tr>und <\/tr>das ist ein Zeichen oder länger, unabhängig von Zeilenumbrüchen [/(?<=<tr>).+(?=<\/tr>)/m]. Anschließend werden alle <tr>oder </tr>aus der Zeichenfolge entfernt gsub(/<\/?tr>/, "")(dies ist erforderlich, um verschachtelte trTags zu verarbeiten). Schließlich wird die Zeichenfolge gedruckt puts.

Sie sagten, dass ein HTML-Parser für Sie nicht garantiert ist, aber es ist sehr einfach, mit Nokogiri zu arbeiten, rubyund es macht den Befehl einfacher.

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

-rnokogirilädt Nokogiri. Nokogiri::HTML(readlines.join)liest alle Zeilen von file. xpath("//tr")wählt jedes trElement aus und map { |e| e.content }wählt den Inhalt für jedes Element aus, dh was zwischen <tr>und ist </tr>.

NN
quelle
1

grep

Um Inhalte innerhalb eines trTags über mehrere Zeilen hinweg abzurufen , müssen Sie diese xargszuerst durchlaufen. Beispiel:

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

Um nur inneres HTML zurückzugeben, verwenden Sie:

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

Überprüfen Sie die Syntax für perlreerweiterte Muster .

Hinweis: Um eine schnellere Leistung zu erzielen, sollten Sie sich überlegen, ripgrepwelche Syntax ähnlich ist.

Kenorb
quelle
es druckte schöner aus, ohne die xargs zu suchen, erwies sich als nützlich, um Inline-Javascript mit egrep -o "<script. *? </ script>" zu finden
Andrew
0

pup

Beispiel using pup(das CSS-Selektoren verwendet ):

pup -f myfile.html tr

So drucken Sie nur Text ohne Tags, zu verwenden: pup -f myfile.html tr text{}.

Hier einige Beispiele mit curl:

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

xpup

Beispiel xpupfür die Verwendung von HTML / XML-Analyse (die XPath unterstützt):

xpup -f myfile.html "//tr"
Kenorb
quelle
0

Wenn es nur eine kurze Auflistung von <tr>s ist, könnte dies helfen:

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

Prost

eswues
quelle