Etwas auswählen und anklicken

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
needsch
User
Beiträge: 15
Registriert: Donnerstag 22. Dezember 2011, 21:28

@BlackJack:
HTTP ist das einzige Protokoll, dessen Grundprinzip er hier kennen sollte. Die Einarbeitung in "Netzwerk-Protokolle" vorzuschlagen oder zu fordern ist IMO etwas überzogen. Die unteren Schichten des TCP/IP-Modells braucht er erstmal sowieso nicht zu kennen.

@ente:
Wenn die Nummer, nach der du suchst, in einem HTML-Code eingebettet ist, der nicht überall auf der Seite ständig auftaucht, dann wäre ein regulärer Ausdruck das einfachste:
"In computing, a regular expression provides a concise and flexible means for "matching" (specifying and recognizing) strings of text, such as particular characters, words, or patterns of characters."

Man kann reguläre Ausdrücke also dafür nutzen, bestimmte Muster in Strings (auch Byte-Strings) zu finden. In Python kann dafür das re-Modul genutzt werden.

Primitives Beispiel:

Code: Alles auswählen

import re

strings = ["Hallo ente!", "Tschüß ente!", "bla bla ...guten MoRgEn bruder... bla bla"]

# Das angegebene pattern passt auf alle Kombinationen von "hallo", "guten tag", "guten morgen",
# "guten abend" und einem beliebigen Wort, das nur aus Buchstaben besteht.
pattern = r"(?:hallo|guten tag|guten morgen|guten abend) [a-zA-Z]+"

for string in strings:
    match_obj = re.search(pattern, string, re.I) # re.I <-> case-insensitive

    if match_obj:
        print("Der string '%s' enthält eine Begrüßung!" % string)
    else:
        print("Der string '%s' enthält keine bekannte Begrüßung!" % string)
Ausgabe:

Code: Alles auswählen

Der string 'Hallo ente!' enthält eine Begrüßung!
Der string 'Tschüß ente!' enthält keine bekannte Begrüßung!
Der string 'bla bla ...guten MoRgEn bruder... bla bla' enthält eine Begrüßung!
Anderes Beispiel, um ganz bestimmte Teile eines Musters zu extrahieren (hier geheime Nummern aus einem HTML-Code):

Code: Alles auswählen

import re

from pprint import pprint

html = """
<html>
<head>
<title>bla bla bla</title>
</head>

<body>
<span class='secret-number'>1337</span>
<div id='irgendein-super-dummer-html-code'>
    <span class='secret-number'>42</span>
    <span class='tja-das-wird-nicht-klappen secret-number'>73</span>
</div>
</body>
</html>
"""

# In Klammern stehendes kann vom regulären Ausdruck separat erfasst und später ausgelesen werden.
pattern = r"<span class='secret-number'>([0-9]+)</span>"

matches = re.findall(pattern, html, re.I)
pprint(matches)
Ausgabe:

Code: Alles auswählen

['1337', '42']
Die dritte secret-number wird nicht erfasst, weil das angegebene Pattern fordert, dass exakt "<span id='secret-number'>" am Anfang steht. Wenn auch nur irgendein Leerzeichen anders gesetzt ist oder andere Hochkommata benutzt werden oder, wie in diesem Fall, irgendein zusätzlicher Text drinsteckt, dann wird es nicht klappen. Reguläre Ausdrücke wissen nichts von HTML - es werden einfach nur exakte Übereinstimmungen mit dem angegebenen Muster gesucht.

Da kann man sich dann sehr komplizierte reguläre Ausdrücke ("pattern") überlegen, die all das beachten. Das ist aber relativ anspruchsvoll und erfordert häufig eine Menge Erfahrung mit regulären Ausdrücken; die Syntax ist für Anfänger erstmal relativ kompliziert. In deinem Fall reicht aber vllt. schon etwas ganz simples. (Das pattern in meinem Beispiel ist ja jetzt auch nicht so mörder-schwer, oder?)

Das wäre das erste, was ich versuchen würde. Wenn du so etwas häufiger machst, solltest du aber vielleicht doch mal einen HTML-Parser ausprobieren. Damit ist auf Dauer auch angenehmer zu arbeiten.

Viele Grüße

EDIT: id-Attribute durch class-Attribute ersetzt. Danke @BlackJack.
Zuletzt geändert von needsch am Dienstag 31. Januar 2012, 22:15, insgesamt 2-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@needsch: Musst Du den "neuen" denn gleich mit RegExps in Zusammenhang mit rekursivem Markup "verderben"? :twisted: Mal im Ernst, mit `lxml` geht das doch mindestens genaus so einfach:

Code: Alles auswählen

In [11]: import lxml.html                

In [12]: html = """                      
<html>
<head>
<title>bla bla bla</title>
</head>
<body>
<span id='secret-number'>1337</span>
<div id='irgendein-super-dummer-html-code'>
    <span id='secret-number'>42</span>
    <span id='tja-das-wird-nicht-klappen secret-number'>73</span>
</div>
</body>
</html>
"""

In [13]: doc = lxml.html.fromstring(html)

In [14]: [node.text for node in doc.xpath("//span[@id='secret-number']")]
Out[14]: ['1337', '42']
Natürlich kann man bei so einfachen Geschichten auch einen RegExp einsetzen; aber wenn man sich daran gewöhnt und nicht überblicken kann, wo die Grenzen dieser Technik liegen, dann gerät man schnell auf die "schiefe Bahn".
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6851
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

`lxml` kann übrigens auch direkt im XPath-Statement den Text rausfischen:

Code: Alles auswählen

doc.xpath("//span[@id='secret-number']/text()")
needsch
User
Beiträge: 15
Registriert: Donnerstag 22. Dezember 2011, 21:28

Hyperion hat geschrieben:@needsch: Musst Du den "neuen" denn gleich mit RegExps in Zusammenhang mit rekursivem Markup "verderben"? :twisted: Mal im Ernst, mit `lxml` geht das doch mindestens genaus so einfach:

Code: Alles auswählen

In [11]: import lxml.html                

In [12]: html = """                      
<html>
<head>
<title>bla bla bla</title>
</head>
<body>
<span id='secret-number'>1337</span>
<div id='irgendein-super-dummer-html-code'>
    <span id='secret-number'>42</span>
    <span id='tja-das-wird-nicht-klappen secret-number'>73</span>
</div>
</body>
</html>
"""

In [13]: doc = lxml.html.fromstring(html)

In [14]: [node.text for node in doc.xpath("//span[@id='secret-number']")]
Out[14]: ['1337', '42']
Stimmt, das ist deutlich schöner, danke für das Beispiel. Habe zu meinem Bedauern noch nie mit lxml oder allg. XPath gearbeitet. Ich muss das bei Gelegenheit unbedingt mal ausprobieren. Sonst Bildungslücke. :oops: Kommt auf die TODO. :)

Viele Grüße
lunar

@needsch: Wenn man mit HTTP arbeitet, muss man wissen, wie das Request-Response-Modell von HTTP funktioniert, und mithin auch, was eine TCP-Verbindung ist, wie sie zustande kommt, und wann sie wieder beendet wird. Es verlangt ja niemand, dass er die Headerdaten von TCP/IP auswendig lernt, aber eine grundlegende Vorstellung von der Funktionalität von TCP/IP ist mindestens hilfreich.
enteenteente
User
Beiträge: 13
Registriert: Samstag 28. Januar 2012, 17:07

Okay vielen Dank, ich probier einfach mal aus, was mir so am ehesten gelingt :D
Wieso eigentlich immer "er"? Ich bin kein Mann :mrgreen:
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

enteenteente hat geschrieben:Wieso eigentlich immer "er"? Ich bin kein Mann :mrgreen:
Wuff!
enteenteente
User
Beiträge: 13
Registriert: Samstag 28. Januar 2012, 17:07

Haha :mrgreen:
enteenteente
User
Beiträge: 13
Registriert: Samstag 28. Januar 2012, 17:07

Haha :)
Woher weißt du das?!
problembär

enteenteente hat geschrieben:Na das ist ja mal freundlich!
Mach' Dir nichts draus, die sind hier halt so.

Für einfache Fälle des Durchsuchens von Strings braucht man in Python nicht unbedingt RegEx einzusetzen. Das geht auch schon so:

Code: Alles auswählen

a = "Hallo"

if "lo" in a:
    print("'lo' ist in dem String 'a'.")
Einfach und schön. :P
enteenteente
User
Beiträge: 13
Registriert: Samstag 28. Januar 2012, 17:07

Gut zu wissen :)
Danke. Okay probiere ich aus :)
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Solange man sich richtig verhält sind alle nett zu einem :) So wie man es erwartet
BlackJack

@needsch: Ergänzend zu dem Beitrag von Hyperion mit `lxml.html`: Dein HTML ist ungültig, weil `id`\s a) eindeutig sein müssen, und b) keine Leerzeichen enthalten dürfen. Was Du da gemacht hast findet man aber üblicherweise so in `class`-Attributen. Und dann kann man mit der `cssselect()`-Methode ganz einfach alle drei Zahlen filtern:

Code: Alles auswählen

In [77]: html = """
   ....: <html>
   ....: <head>
   ....: <title>bla bla bla</title>
   ....: </head>
   ....: <body>
   ....:     <span class='secret-number'>1337</span>
   ....:     <div id='irgendein-super-dummer-html-code'>
   ....:         <span class='secret-number'>42</span>
   ....:         <span class='tja-das-wird-nicht-klappen secret-number'>73</span>
   ....:     </div>
   ....: </body>
   ....: </html>
   ....: """

In [78]: doc = lxml.html.fromstring(html)

In [79]: doc.cssselect('.secret-number')
Out[79]: 
[<Element span at 93bf9ec>,
 <Element span at 93bf86c>,
 <Element span at 93bf89c>]

In [80]: [node.text for node in doc.cssselect('.secret-number')]
Out[80]: ['1337', '42', '73']
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@BlackJack: Ja, ich hatte mich auch ein wenig gewundert, dass da ein Beispiel mit ``id``s daher kam. Ich hatte zuvor ja auch eher CSS-Selektoren vorgeschlagen. Aber schön, dass Du auch diesen Ansatz gezeugt hast.

@problembär: Dein Einwand ist durchaus sinnvoll, aber nur dann, wenn man einen Teilstring kennt und wissen will, ob der in einem enthalten ist. In diesem Falle kennt die OP den String ja nicht, sondern will ihn herausfinden ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten