staging.inyokaproject.org

sed: html tags mit variierendem Inhalt entfernen

Status: Gelöst | Ubuntu-Version: Ubuntu MATE 20.04 (Focal Fossa)
Antworten |

UsualRedFox

Anmeldungsdatum:
23. Juli 2017

Beiträge: 95

Kurze Frage, die mir fortgeschrittene sicher schnell beantworten können.

ich habe: <a href="https://beispielseite.de/bla" rel="tag">Thema</a>

ich würde gerne mit sed den Befehl so bearbeiten, dass nur noch "Thema" übrig bleibt. Sprich <a ....> und </a> entfernen.

Leider hab ich (noch) nicht so den Kopf dafür sed so richtig einzusetzen.

Theoretisch müsste doch folgendes funktionieren:

1
sed 's/<a PLATZHALTER>//g'

was aber nicht zutrifft. kann mir das jemand nochmal erklären? Ich hab https://wiki.ubuntuusers.de/sed/ schon gelesen, aber ich stehe wohl auf dem sprichwörtlichen Schlauch.

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

sed ist IMHO nicht das richtig Werkzeug dafür. HTML/XML geht man in der Regel nicht mit regulären Ausrücken und ähnlichem an, sondern mit einem HTML/XML Parser. Damit kannst du dann auch Attribute auslesen.

Allerdings kann ich dir nicht sagen, was ein geeigneter HTML/XML Parser für die Kommandozeile wäre.

Gruß, noisefloor

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

XML mit regulären Ausdrücken zu parsen hat wie schon geschrieben seine Tücken (gerade wenn ein Tag über mehrere Zeilen geht oder verschachtelt ist) - falls ein Tag zuverlässig in der selben Zeile abgeschlossen wird, könnte man das mit sed so lösen:

$ sed -E 's/<a[^>]*>([^<]*)<\/a[^>]*>/\1/g' <<< '<a href="https://beispielseite.de/bla" rel="tag">Thema</a>'
Thema 

Falls es komplexer wird, könnte man z.B. zu Python3 mit python3-beautifulsoup4 greifen - z.B. um den Text aus allen <a>-Tags zu holen:

1
2
3
4
5
6
7
#!/usr/bin/env python3
import fileinput
from bs4 import BeautifulSoup

soup = BeautifulSoup("".join(fileinput.input()), features="lxml")
for link in soup.find_all("a"):
    print(link.text)

Das HTML-Dokument bzw. den Schnipsel kann man dann auf stdin oder über den Dateinamen übergeben:

./extract_link_text.py <<< '<a href="https://beispielseite.de/bla" rel="tag">Thema</a>'
Thema 

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1303

seahawk1986 schrieb:

... könnte man das mit sed so lösen:

$ sed -E 's/<a[^>]*>([^<]*)<\/a[^>]*>/\1/g' <<< '<a href="https://beispielseite.de/bla" rel="tag">Thema</a>'
Thema 

Das Problem mit regex ist leider nicht nur das Verteilen der Tags auf mehrere Zeilen sondern auch das greedy/non greedy matching.

Wenn im <a ...> ... </a> Konstrukt weitere Tags eingebaut sind, zieht das [^<]* Konstrukt nicht.

$ sed -E 's/<a[^>]*>([^<]*)<\/a[^>]*>/\1/g' <<< '<a href="https://beispielseite.de/bla" rel="tag"><span>Thema</span></a>'
<a href="https://beispielseite.de/bla" rel="tag"><span>Thema</span></a>

Aus diesem Grund ist es stabiler, die "</*a[^>]*>" Tags zu löschen, also deine sed Zeile wie folgt anzupassen

$ sed -z -E 's#</*a[^>]*>##g' <infile.html >outfile.html

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Zugegebenermaßen ist es etwas ausführlich, aber dafür hat man ein Tool, das HTML und XML ordentlich verarbeiten kann:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ curl 'https://ubuntuusers.de' > page.html
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 18561  100 18561    0     0  48462      0 --:--:-- --:--:-- --:--:-- 48335
$ ruby -r nokogiri -e 'd=Nokogiri.HTML($stdin);d.xpath("//a").each {|n|n.replace(n.text)};puts d' < page.html > conv.html
$ diff -wU3 page.html conv.html | head -200
--- page.html	2021-08-14 12:40:00.403768406 +0200
+++ conv.html	2021-08-14 12:44:29.832529005 +0200
...
@@ -47,12 +41,11 @@
   </head>
   <body>
   <nav class="navi_global">
-    <a href="#main" class="skip-link">Zum Hauptinhalt springen</a>
-    <a href="#sidebar" class="skip-link">Zur Seitenleiste springen</a>
-    <a href="https://verein.ubuntu-de.org/">
-      <img src="//static-cdn.ubuntu-de.org/img/ubuntu-logo-set-web-svg/SVG_small_use/ubuntu_white_hex_su-ubuntu_Deutschland_eV-no_font.svg"
-           alt="ubuntu Deutschland e.V. Logo">
-    </a>
+    Zum Hauptinhalt springen
+    Zur Seitenleiste springen
+    
+      
+    
 
   <ul>
     <li>
...

PS: Man sieht auch, dass das für den Fall, dass man ein <img> innerhalb eines <a> hat, nicht so schön funktioniert. Da müsste man dann den <img>-Tag erst durch seinen @alt-Text ersetzen. Das ginge dann so

1
$ ruby -r nokogiri -e 'd=Nokogiri.HTML($stdin);d.xpath("//a[img]").each {|n|n.replace(n.at_xpath("./img/@alt").text)};d.xpath("//a").each {|n|n.replace(n.text)};puts d' < page.html >| conv.html

Würde man aber besser in ein Skript packen.

UsualRedFox

(Themenstarter)

Anmeldungsdatum:
23. Juli 2017

Beiträge: 95

Vielen Dank für die ausführlichen Antworten! Das bringt mich weiter (und hoffentlich auch alle anderen, die ein ähnliches Problem haben und den Thread finden).

Antworten |