Seite 1 von 2

findall für Anfänger

Verfasst: Montag 23. Februar 2009, 06:27
von shadow07
Hallo,

ich versuche seit Tagen, aus einer Website einzelne Infos auszulesen.
Es gibt zum Beispiel 5 mal eine solche Zeile:
<td class="odd preis_his">48,85 €</td>

ich versuche es (try and error) zum Beispiel so (habe extra die Sonderzeichen <>"& erst mal rausgelassen):

Code: Alles auswählen

import os, sys
from twisted.web.client import getPage
from twisted.internet import reactor
from re import sub, split, search, match, findall
from string import find, atoi, strip
import urllib, os, sys, tempfile

website = urllib.urlopen("http://www.test.php")
Zeilen = website.readlines()
res = findall(r'odd([^euro]*)', Zeilen)
res2 = = "%s %s %s %s %s %s" % (x[0],x[1],x[2],x[3],x[4],x[5])
print res2
ich vermute, da ist wohl mehr als nur ein Fehler drin?

sowas funktioniert in einem fremden script:

Code: Alles auswählen

x = findall(r'/bilder/zahlen/.*/(?P<zahlen>\d.*)\.gif',output
)



ja, ich habe die Suche benutzt (bin jetzt eher verwirrter als vorher)
nein, google hat moch nicht schlauer gemacht
sorry, bin absoluter Python-Anfänger und durch bisheriges arbeiten mit VB und ähnlichem tue ich mich sehr schwer

Verfasst: Montag 23. Februar 2009, 08:07
von BlackJack
@shadow07: Ja da ist mehr als ein Fehler drin. Mindestens ein Syntaxfehler und ein `NamenError` in Zeile 11. Man kann nicht einfach zwei Gleicheitszeichen hintereinander schreiben, oder auf Namen zugreifen, die vorher nicht definiert wurden.

Bitte demnächst lauffähiges und möglichst minimales als Beispiel zeigen. Du hast da nämlich auch eine Menge Importe, die gar nicht verwendet werden.

Die Importe aus `string` sollte man auch nicht verwenden. `find()` und `strip()` sind als Methoden auf Zeichenketten vorhanden und statt `atoi()` kann man `int()` verwenden.

Der reguläre Ausdruch passt auf 'odd' gefolgt von beliebig vielen Zeichen, die nicht 'e', 'u', 'r', oder 'o' sind. Damit kommst Du in dem Beispiel genau bis zu dem 'p' von 'preis_his', weil danach eben ein 'r' kommt.

HTML mit regulären Ausdrücken zu vearbeiten ist aber auch keine so gute Idee. Benutze dafür lieber eine Bibliothek, die HTML versteht und genau für solche Aufgaben gedacht ist, wie `BeautifulSoup` oder `lxml.html`.

Verfasst: Montag 23. Februar 2009, 08:07
von Hyperion
Hallo,

beim Parsen von Webseiten nicht mit RegExps arebeiten! Wir haben das Thema gefühlte 3x die Woche :-D

Such einfach mal per SuFu hier. Du machst das am besten mit lxml oder html5lib. Das wird in vielen Threads ausführlich erklärt!

Wollte zu dem Thema nicht mal irgend wer einen Beitrag im wiki schreiben oder in der FAQ?

Verfasst: Montag 23. Februar 2009, 08:08
von Panke
Mit Beautifulsoup:

Code: Alles auswählen

soup = BeautifulSoup(seiten_text)
tds = soup.findAll('td', class="odd_preis_his")
Mit der Übergabe des class-Attributes bin ich mir nicht sicher, schau mal in der Doku nach.

Verfasst: Montag 23. Februar 2009, 09:19
von Leonidas
Hyperion hat geschrieben:Wollte zu dem Thema nicht mal irgend wer einen Beitrag im wiki schreiben oder in der FAQ?
In der FAQ ist doch ein Abschnitt. Ich kann ja nichts dafür das die niemand liest.

Verfasst: Montag 23. Februar 2009, 13:13
von Hyperion
Leonidas hat geschrieben:
Hyperion hat geschrieben:Wollte zu dem Thema nicht mal irgend wer einen Beitrag im wiki schreiben oder in der FAQ?
In der FAQ ist doch ein Abschnitt. Ich kann ja nichts dafür das die niemand liest.
Ah ... da isser ja :-)
[wiki]FAQ#WieVerarbeiteIchWebseiten[/wiki]

Verfasst: Montag 23. Februar 2009, 13:33
von shadow07
zuerst mal vielen Dank dafür, das ihr immer wieder durchgekaute Themen jedesmal neu zu erklären versucht.
1. xml-Parser fallen glaube ich aus, da die Seite dynamisch erstellt wird

2. ich habe kein lauffähiges script, ich habe ein script erstellt:
#!/bin/sh

wget -q "http://www.esyoil.com/heiz%C3%B6lpreise ... tal_e3.php" -O /tmp/heizoel3.txt

sed '{s/<[^>]*>//g;s/&euro;//g;s/&nbsp;//g;s/Heute//g;s/^[ \t]*//;1,134d;194,$d;137d;138d}' /tmp/heizoel3.txt >/tmp/datei01.txt

sed '{/^\s*$/d;s/^[ \t]*//;s/+/%2B/g;s/-/%2D/g}' /tmp/datei01.txt >/tmp/datei09.txt

a=$(sed -n '1p' datei09.txt)",%20%20"$(sed -n '2p' datei09.txt)
b="2000=%20%20%20"$(sed -n '3p' /tmp/datei09.txt)"%20%20%2F%20%20"$(sed -n '4p' /tmp/datei09.txt)"%20%20"$(sed -n '5p' datei09.txt)
c="2500=%20%20%20"$(sed -n '6p' /tmp/datei09.txt)"%20%20%2F%20%20"$(sed -n '7p' /tmp/datei09.txt)"%20%20"$(sed -n '8p' datei09.txt)
d="3000=%20%20%20"$(sed -n '9p' /tmp/datei09.txt)"%20%20%2F%20%20"$(sed -n '10p' /tmp/datei09.txt)"%20%20"$(sed -n '11p' datei09.txt)
e="3500=%20%20%20"$(sed -n '12p' /tmp/datei09.txt)"%20%20%2F%20%20"$(sed -n '13p' /tmp/datei09.txt)"%20%20"$(sed -n '14p' datei09.txt)
f="4000=%20%20%20"$(sed -n '15p' /tmp/datei09.txt)"%20%20%2F%20%20"$(sed -n '16p' /tmp/datei09.txt)"%20%20"$(sed -n '17p' datei09.txt)

wget "http://127.0.0.1/web/message?text=$c%0a ... &timeout=0" 2>/dev/null

dieses script benötige ich aber in Python, von welchem ich bis vor kurzem nicht mal was gehört habe
also habe ich versucht, aus anderen py-scripten zu erkennen, wie die von mir gewünschten Funktionen umgesetzt werden können, habe dann in den leider fast ausschließlich englischen Dokus endlos gesucht, ein paar hundert mal 'try and error' gespielt und mich nun entschlossen, euch um Hilfe zu bitten (Script-Sprachen nach Buch zu lernen ist mir noch nie gelungen, ich habe mir Beispiele gesucht, geändert und aus den Fehlern gelernt, aber hier stehe ich diesmal komplett auf dem Schlauch weil ich absolut keinen Plan hab und keinen Anfang finde)

Verfasst: Montag 23. Februar 2009, 15:51
von cofi
shadow07 hat geschrieben:1. xml-Parser fallen glaube ich aus, da die Seite dynamisch erstellt wird
Und wo ist das Problem? Ob die Seite dynamisch erzeugt wird ist komplett egal, das solltest du aber auch bemerkt haben, denn dein Shell Skript bearbeitet auch eine statische Seite ;) Nebenbei ist Beautiful Soup ein HTML Parser.

Verfasst: Montag 23. Februar 2009, 16:14
von Leonidas
Der FAQ-Eintrag sagt schon eigentlich alles was du brauchst: einen Parser (ich rate zu html5lib oder lxml.html) und du musst wissen was du aus dieser Seite auslesen willst (mit lxml ist es dann sehr einfach, da man einen CSS-Selektor nutzen kann oder wenn man etwas aufwändigeres haben will auch XPath einsetzen kann um einen bestimmten Knoten aus einer Seite auszulesen. Ist aber mit etwas spielerei in der Konsole (Interpreter nutzen!) durchaus machbar und simpel.

Verfasst: Montag 23. Februar 2009, 16:34
von Hyperion
Leonidas hat geschrieben:... oder wenn man etwas aufwändigeres haben will auch XPath einsetzen kann um einen bestimmten Knoten aus einer Seite auszulesen. Ist aber mit etwas spielerei in der Konsole (Interpreter nutzen!) durchaus machbar und simpel.
Es gibt da ja auch einige nützliche Firefox-Plugins, mit denen man die XPath Ausdrücke an der Seite testen kann - die finde ich in dem Zusammenhang durchaus nützlich. Aber klar, rein in einer Konsole geht's natürlich auch.

Verfasst: Montag 23. Februar 2009, 17:01
von Leonidas
Ich für meinen Teil nutze wo es geht die CSS-Selektoren in der Konsole. Das hat den Vorteil dass es simpler ist (man braucht selten die vollen Möglichkeiten von XPath, da kann man zur Not auch mit Python das Ergebnis nochmal filtern) und dass ich genau das als Rausbekomme was das Skript dann auch rausbekommen sollte. Das spart Probleme bei Inkompatibilitäten (ich weiß nicht wie gut der Support von XPath in Firefox und lxml jeweils ist). Das es da Firefox-Plugins gibt wusste ich aber noch gar nicht. Wenn ich sowas genutzt habe, dann höchstens via jQuery + Firebug :)

Verfasst: Montag 23. Februar 2009, 18:11
von shadow07
@BlackJack
vielen Dank für die konstruktive Hilfe, ich habe etwas aufgräumt, string-import entfernt und weiterprobiert und gelesen, ich komm auf keinen Zweig, ich kapiere den Aufbau der findall-Anweisung nicht

Code: Alles auswählen

#!/usr/bin/python
 
from twisted.web.client import getPage
from re import sub, split, search, findall, IGNORECASE
 
seite=getPage('http://www.esyoil.com/heiz%C3%B6lpreise/heiz%C3%B6l_Obermarchtal_e3.php')
x = findall(r'preis_his(?)',seite)
print x
das wichtigste, was ich im Moment brauche, ist die Syntax erklärt für doofe, ungefähr
x= findall(r'ab hier suchen(nicht suchen)das hier suchen', hier drin suchen)

@alle anderen
es ist zwar schön das man mir helfen will, aber bitte nicht nach dem Motto 'wie a funktioniert sagen wir nicht, benutze b'

Verfasst: Montag 23. Februar 2009, 18:39
von derdon
shadow07 hat geschrieben:es ist zwar schön das man mir helfen will, aber bitte nicht nach dem Motto 'wie a funktioniert sagen wir nicht, benutze b'
Warum nicht? Kennst du Module wie lxml überhaupt? Bei Python lauet das Motto: "Batteries included". Natürlich kannst du weiterhin versuchen, die Seite mit dem re-Modul zu parsen. Ob dir viele Leute dabei helfen wollen, weiß ich allerdings nicht. Aufgeschlossenheit und Flexibilität sind für eine gute Lösung (ist nicht unbedingt das gleiche wie funktionierende) notwendig.

Verfasst: Montag 23. Februar 2009, 19:21
von DasIch
shadow07 hat geschrieben:@alle anderen
es ist zwar schön das man mir helfen will, aber bitte nicht nach dem Motto 'wie a funktioniert sagen wir nicht, benutze b'
"a" funktioniert nicht.

Verfasst: Montag 23. Februar 2009, 19:43
von Leonidas
Und keinen Parser verwenden wollen, dafür aber getPage aus Twisted nehmen, obwohl Python sowohl ``urllib`` als auch ``urllib2`` hat ist auch irgendwie inkonsequent :roll: Aber vielleicht hat der OP ja irgendwelche sinnvollen Gründe dafür. Vielleicht mag er die uns sogar nennen.

Verfasst: Montag 23. Februar 2009, 20:47
von shadow07
Aber vielleicht hat der OP ja irgendwelche sinnvollen Gründe dafür. Vielleicht mag er die uns sogar nennen
er nennt: ich habe in den letzten Tagen ein paar 100 Zeilen Code ausprobiert (ja, totales rumgestümper), darunter auch urllib wie in meinem ersten Post zu sehen war. Ich kann zur Zeit weder die Unterschiede noch die Wirksamkeiten beurteilen. Außerdem handelt es sich nicht um einen PC, eventuell soll die Lösung später auch anderen zugänglich gemacht werden, deshalb möchte ich nichts zusätzliches installieren müssen für die Lösung
"a" funktioniert nicht.
die Beispielzeile aus meinem ersten Post ist einem laufenden Script entnommen, also das es nicht funktioniert entspricht schlicht nicht der Wahrheit


ansonsten kann ich nur erstaunt feststellen: es wurde hier sehr oft auf den Button 'Antworten' geklickt und einiges an Text eingegeben, geantwortet hat mir außer dem ersten jedoch niemand. Schade um die Zeit der Poster (hilft weder mir noch ihnen).
Ich habe viele Stunden im Internet gesucht und eine Menge erklärender Seiten gefunden, leider alles englisch und somit für mich schlecht bis gar nicht verständlich (und solange ich keinen Zugang zur Funktionsweise Linux/Python finde kann ich mir da auch nichts zusammenreimen wie es mir bei php, VB und anderem bisher immer gelungen ist)

ich habe hier nicht nach einer fertigen Lösung gefragt, kein komplettes Script erbeten - da könnt ich die Reaktionen verstehen
Es kann allerdings auch sein, das entgegen älteren Beiträgen in diesem Board inzwischen nur noch Leuten geholfen wird, welche Python beherrschen (das sollte man mir aber mitteilen, dann melde ich mich hier eben wieder ab da im falschen Board)

Verfasst: Montag 23. Februar 2009, 20:53
von BlackVivi
shadow07 hat geschrieben:
Aber vielleicht hat der OP ja irgendwelche sinnvollen Gründe dafür. Vielleicht mag er die uns sogar nennen
er nennt: ich habe in den letzten Tagen ein paar 100 Zeilen Code ausprobiert (ja, totales rumgestümper), darunter auch urllib wie in meinem ersten Post zu sehen war. Ich kann zur Zeit weder die Unterschiede noch die Wirksamkeiten beurteilen. Außerdem handelt es sich nicht um einen PC, eventuell soll die Lösung später auch anderen zugänglich gemacht werden, deshalb möchte ich nichts zusätzliches installieren müssen für die Lösung
urllib2 ist Teil der Standardbibliothek, schon... seit ewigkeiten. Gibt keinen Grund dagegen... Es ist sogar kompatibel mit Python 3.0

Verfasst: Montag 23. Februar 2009, 21:07
von shadow07
och menno

Code: Alles auswählen

#!/usr/bin/python
 
#from twisted.web.client import getPage
from re import sub, split, search, findall, IGNORECASE
 
seite = urllib.urlopen("http://www.test.php")
x = findall('\d+\d+[,.]\d+|\d+',seite)
print x
gibt: File "/usr/lib/python2.5/re.py", line 167, in findall
return _compile(pattern, flags).findall(string)
TypeError: expected string or buffer

der Such-String ist direkt abgeschrieben, an vielen Stellen ähnlich gesehen, der kann doch einfach nicht fehlerhaft sein[/quote]

Verfasst: Montag 23. Februar 2009, 21:13
von Leonidas
``seite`` ist nun mal kein String. Den Inhalt der Seite gibt es mit ``seite.read()``. Siehe Dokumentation.

Verfasst: Montag 23. Februar 2009, 22:45
von shadow07
soweit bin ich nun:

Code: Alles auswählen

#!/usr/bin/python

from re import sub, split, search, findall, IGNORECASE
import urllib
 
seite = urllib.urlopen("http://www.esyoil.com/heiz%C3%B6lpreise/heiz%C3%B6l_Obermarchtal_e3.php")
seite2 = seite.read()
seite.close()

such = "odd preis_his"
anfpos = seite2.find(such)

nextpos = anfpos + 15


x = findall('\d{2}\,\d{2}',seite2)

print "2000 Liter, neuer Preis: " + x[0] + ",alter Preis: " + x[1] + " gesamt: " + str(float(x[0].replace(',','.'))*20) + "0"
print "2500 Liter, neuer Preis: " + x[2] + ",alter Preis: " + x[3] + " gesamt: " + str(float(x[2].replace(',','.'))*25) + "0"
print "3000 Liter, neuer Preis: " + x[4] + ",alter Preis: " + x[5] + " gesamt: " + str(float(x[4].replace(',','.'))*30) + "0"
print "3500 Liter, neuer Preis: " + x[6] + ",alter Preis: " + x[7] + " gesamt: " + str(float(x[6].replace(',','.'))*35) + "0"
print "4000 Liter, neuer Preis: " + x[8] + ",alter Preis: " + x[9] + " gesamt: " + str(float(x[8].replace(',','.'))*40) + "0"
der code macht was er soll, obwohl mit Sicherheit Verrenkungen drin sind die Profis besser wissen (?)

interessant für mich wäre: wie kann ich das komma ersetzten durch einen Punkt (zum berechnen) und anschließend wieder mit Komma austausche ohne ellenlange Code?
wie bekomme ich zwei Stellen nach dem Komma ohne selbst eine '0' hinzuschreiben?