Python Regular expression

11/01/2015 18:26 FreewayC#1
Hi,

ich möchte gerne einen Wert zwischen zwei HTML Elementen über "Regular expression" auslesen. Kämpf mich schon seit mehreren Stunden durch die Dokumentation, aber ich bekomme es einfach nicht gebacken.

Das ganze sieht so aus:

<br>MeinWert 1,00 Euro </br>


Wobei sich der Inhalt auch mal ändern kann (bsp: Eurowert fällt weg)

Zwischen den br Elementen sind ein Haufen Leerzeichen. Hab es schon mit BeautifulSoup probiert, aber der HTML Content ist einfach so extrem schlecht aufgebaut, sodass es nicht funktioniert hat.


freundliche Grüße
freewayc
11/01/2015 19:02 Mysthik#2
HTML gehört zu den kontextfreien Sprachen. Reguläre Ausdrücke lassen sich aber nur sinnvoll auf die regulären Sprachen anwenden und somit nicht für HTML benutzen.
Mit dem HTML-Parser (in deinem Fall BeautifulSoup) kannst du dir den Parse-Tree erstellen und mit dem relativ leicht umgehen.

Du könntest alle Inhalte durchiterieren und den jeweiligen Inhalt mit regulären Ausdrücken überprüfen. Die leerzeichen zwischen den <br> und </br> interessieren dich dann nicht mehr.

Ich hab noch nie viel mit regulären Ausdrücken gearbeitet aber der hier sollte ein paar Fälle abdecken.
Code:
MeinWert(:)? (-)?\d(,|.)\d\d( )?(Euro)?
Damit kannst du unteranderem folgende Werte finden
Quote:
MeinWert 1,00 Euro
MeinWert 1.11 Euro
MeinWert: 1.00 Euro
MeinWert -1,00
MeinWert: 1.00
MeinWert: 1,00
...
11/01/2015 19:17 FreewayC#3
Danke für deine schnelle Antwort, aber "MeinWert" war nur als Beispiel gedacht. Schlussendlich steht zwischen dem <br> irgendein random Wert
11/01/2015 19:31 Mysthik#4
Kannst du mal einen Auszug der besagten stellen aus dem HTML-Dokument geben?
11/01/2015 19:39 FreewayC#5
Quote:
<strong>MeinDatum 01.11.2015<br><br>Putin € 5,00<br><br>Dies ist ein Satz<br><br>Ein sehr kurzer Satz<br><br>Richtig scheiße formatiert 1337 €<br><br>NeuerWert (ohne Preis)<br><br>Blabla blabla 5,00 €<br><br>
HTML5 forever<br><br>http://elitepvpers.com<br><br>asdasdasd<br><br>Dies ist ein extra langer Satz mit allen Zeichen die mir gerade einfallen ~'#æ<br><br>Ich glaube das geht gar nicht<br><br>Endlich fertig 5,00 €







</strong>

Hab mal ein paar Phantasie Werte eingefügt, aber so sieht es aus

Edit: Jeder Wert zwischen den br's soll ausgelesen werden, und der letzte zwischen <br> und <strong> auch
11/01/2015 19:57 warfley#6
Also ich würde den Strong Tag etrahieren, dann nach <br> Splitten, zeilen trimmen, leere Zeilen entfernen und dann Zeile für Zeile parsen
11/01/2015 21:08 FreewayC#7
Quote:
Originally Posted by warfley View Post
Also ich würde den Strong Tag etrahieren, dann nach <br> Splitten, zeilen trimmen, leere Zeilen entfernen und dann Zeile für Zeile parsen

Wie es ablaufen muss kann ich mir auch vorstellen, aber es scheitert an der Umsetzung
11/01/2015 21:43 warfley#8
Für den Strong tag könntest du das Pattern:
Code:
<strong>(.*?)<\/strong>
verwenden. Bei den br tags dann entsprechend.
11/01/2015 23:17 algernong#9
Wieso nicht irgendwie so:
Quote:
(^<strong>|<br>)\s*(.+?)\s*(<\/strong>$|<br>)
11/02/2015 11:25 MrDami123#10
Quote:
Originally Posted by FreewayC View Post
Wie es ablaufen muss kann ich mir auch vorstellen, aber es scheitert an der Umsetzung
Die genaue Umsetzung ist stark von deinem HTML anhängig. Du könntest den Inhalt jedes <br> tags oder was auch immer das da oben sein soll, nach spezifischen Werten überprüfen.
Z.B. nach Währungszeichen, Zahlenwerten oder beidem.

Weiß nicht was genau du extrahieren möchtest, gehe davon aus den Zahlenwert mit dem Währeungszeichen?
Wenn dein HTML eine mindest Struktur hat wie Zahlenwerte nur vorhanden wenn ein € Zeichen da ist oder das € immer hinter den Zahlenwert oder der Zahlenwert da es sich um Währeung handelt immer nur zwei Nachkommastellen hat etc. muss man den Code mit mehr oder weniger Überprüfungen schreiben.

Hier ein Beispiel:
Code:
def check_for_integer(zeilen):
    """ Sucht nach Integer in Zeile. Gibt Liste aus Tuple von Zahl und Zeile zurück. """
    funde = []
    for zeile in zeilen:
        for wort in [w.replace(',', '') for w in zeile.split(' ')]:
            try:
                wert = int(wort)
                funde.append((wert, zeile))
            except:
                pass
    return funde

def check_for_string(zeilen, werte):
    """ Checkt ob Wörter in Zeilen Werte enthalten. Ignoriert Groß-Kleinschreibung. """
    funde = []
    for zeile in zeilen:
        if [wort for wort in zeile.split(' ') if any(wert in wort.lower() for wert in werte)]:
            funde.append(zeile)
    return funde


text = u"""<strong>MeinDatum 01.11.2015<br><br>Putin € 5,00<br><br>Dies ist ein Satz<br><br>Ein sehr kurzer Satz<br><br>Richtig scheiße formatiert 1337 €<br><br>NeuerWert (ohne Preis)<br><br>Blabla blabla 5,00 €<br><br>
HTML5 forever<br><br>http://elitepvpers.com eUro<br><br>asdasdasd<br><br>Diestz mit allen Zeichen die mir gerade einfallen ~'#æ<br><br>Ich glaube das geht gar nicht<br><br>Endlich fertig 5,00 €

</strong>"""

# teilt text in zeilen zwischen br tags
zeilen = [zeile for zeile in text.split('<br>')]

werte = (u'€', u'euro', u'dollar', u'$')

wert_funde = check_for_string(zeilen, werte)
print(wert_funde)

int_funde = check_for_integer(zeilen)
print(int_funde)

int_und_wert_funde = check_for_integer(wert_funde)
print(int_und_wert_funde)
11/23/2015 18:09 Moonsteroid#11
Also ich kann dir nur davon abraten mit re aus HTML Tags auszulesen!
Wie bereits erwähnt wurde solltest du dafür BeautifulSoup benutzen(ich kann mir schlecht vorstellen das es nicht geht..)!

Hier ein kleines Beispiel um dein o.g. beispiel auszulesen:

Code:
import bs4

# Dein HTML TAG 
string = "<br>MeinWert 1,00 Euro </br>"

# Parsen
soup = bs4.BeautifulSoup(string, "html.parser")

# TAG inhalt ausgeben
print soup.text
#>> MeinWert 1,00 Euro
11/23/2015 20:29 algernong#12
Quote:
Also ich kann dir nur davon abraten mit re aus HTML Tags auszulesen!
Wieso rätst du davon ab?
11/23/2015 21:31 .SkyneT.#13
Quote:
Originally Posted by algernong View Post
Wieso rätst du davon ab?
Es ist hässlich, unübersichtlich, schwerer zu verstehen/warten, und bei evtl. kleinen Fehlern in HTML (die durchaus auftreten können) nicht mehr wirklich anwendbar.

Hier noch eine detailierte Beschreibung: [Only registered and activated users can see links. Click Here To Register...]
11/23/2015 22:18 algernong#14
Quote:
Es ist hässlich, unübersichtlich, schwerer zu verstehen/warten, und bei evtl. kleinen Fehlern in HTML (die durchaus auftreten können) nicht mehr wirklich anwendbar.
Wir reden aber über sehr wenige Zeilen an Code. Ich finde nicht, dass da das eine besser oder schlechter zu warten ist als das andere.
Bei kleinen Fehlern im HTML kann der Code auch mit einem HTML Parser schief gehen. Man muss festlegen, welche Fehler auftreten könnten - und die kann man dann auch im Regexp berücksichtigen.
Quote:
Hier noch eine detailierte Beschreibung: html - RegEx match open tags except XHTML self-contained tags - Stack Overflow
Das bezieht sich aber auf HTML allgemein. Der Aufbau in Post #5 ist regulär.
11/23/2015 22:50 .SkyneT.#15
Quote:
Originally Posted by algernong View Post
Wir reden aber über sehr wenige Zeilen an Code. Ich finde nicht, dass da das eine besser oder schlechter zu warten ist als das andere.
Wenn du das hier:
Code:
(^<strong>|<br>)\s*(.+?)\s*(<\/strong>$|<br>)
als wartungsfreundlich bezeichnest, dann kennst du wohl einfach die Bedeutung dieses Wortes nicht.

Quote:
Originally Posted by algernong View Post
Bei kleinen Fehlern im HTML kann der Code auch mit einem HTML Parser schief gehen. Man muss festlegen, welche Fehler auftreten könnten - und die kann man dann auch im Regexp berücksichtigen.
Also ich muss hier nichts festlegen, bs4 kommt damit "einfach so" zurecht:
Code:
>>> from BeautifulSoup import BeautifulSoup
>>> soup = BeautifulSoup("<htm@)($*><body><table <tr><td>hi</tr></td></body><html")
>>> print soup.prettify()
<htm>
 <body>
  <table>
   <tr>
    <td>
     hi
    </td>
   </tr>
  </table>
 </body>
</htm>