BeautifulSoup Tabelle auslesen (SIS-Handball)

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
jeff84
User
Beiträge: 6
Registriert: Montag 26. Oktober 2009, 17:36

Hallo Leute,

ich versuche mit Python und BeautifulSoup eine Tabelle automatisch auszulesen.
Ich bin soweit, dass ich die Tabelle ausgewählt habe, die ich suche:

Code: Alles auswählen

import urllib2
from BeautifulSoup import BeautifulSoup

soup = BeautifulSoup(urllib2.urlopen(' URL ').read())
tables = soup.findAll("table", { TABEIG })
print tables
Nun suche ich nach einer Möglichkeit statt des letzten print tables die Tabelle in ihren Einzelheiten auszulesen. Allerdings finde ich keine wirkliche Möglichkeit einzelne Teile der Tabelle direkt zu identifizieren, da diese keine id oder Unterscheidungsmerkmale haben. Welche Möglichkeiten habe ich da?

Gruß

EDIT: Der lebarkeit halber URL und TABEIG ersetzt. Im Code weiter unten wieder richtig zu finden...
Zuletzt geändert von jeff84 am Donnerstag 12. November 2009, 10:27, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du müßtest dann eben über die Elemente iterieren (alle <td>s z.B.) und die gewünschten Daten extrahieren.
jeff84
User
Beiträge: 6
Registriert: Montag 26. Oktober 2009, 17:36

Wahrscheinlich ist der Code unsauber wie ein Wildschwein im Wald, aber ich denke ich habe eine Lösung gefunden...

Code: Alles auswählen

import urllib2
from BeautifulSoup import BeautifulSoup

soup = BeautifulSoup(urllib2.urlopen(' URL ').read())
tables = soup.findAll("table", { TABEIG })
table = tables[1]
#f = open('/home/jochen/sistest', 'w')
#f.write(table.read())
#f.close()
for row in table.findAll('tr')[1:]:		
	col = row.findAll('td')    	
	Team = row.findAll('a')	
	try:
		col[1]
	except:
		continue
	Platz = col[1].string
	Mannschaft = Team[0].string
	Spiele = col[3].string
	Siege = col[4].string
	Unentschieden = col[5].string
	Niederlagen = col[6].string
	Tore = col[7].string
	Tordiff = col[8].string
	Punkte = col[9].string
	Zeile = (Platz, Mannschaft, Spiele, Siege, Unentschieden, Niederlagen, Tore, Tordiff, Punkte)
	print Zeile
Gefällt mir an sich ganz gut. Kann man da noch was verbessern :-)?
Dann werde ich mich mal daran machen, das irgendwie in ne Datenbank zu bekommen...

EDIT: Der lebarkeit halber URL und TABEIG ersetzt. Im Code weiter unten wieder richtig zu finden...
Zuletzt geändert von jeff84 am Donnerstag 12. November 2009, 10:28, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

- bei except niemals alle Exceptions abfangen!
- wozu willst Du jedes einzelne Attribut benennen? Du verwendest die Namen ja quasi gar nicht. Wenn doch, würde ich statt eines Tupels ein dict nehmen.
- Zeilenlänge kürzen! PEP8 erlaubt max. 80 Zeichen.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Hyperion hat geschrieben:PEP8 erlaubt max. 80 Zeichen.
79 Zeichen.
MfG
HWK
jeff84
User
Beiträge: 6
Registriert: Montag 26. Oktober 2009, 17:36

Hyperion hat geschrieben:- bei except niemals alle Exceptions abfangen!
In diesem Fall dachte ich, kann nicht viel passieren. Werde vielleicht auch einfach per if bei den col's mit nur einem Element ein continue machen
Hyperion hat geschrieben: - wozu willst Du jedes einzelne Attribut benennen? Du verwendest die Namen ja quasi gar nicht. Wenn doch, würde ich statt eines Tupels ein dict nehmen.
Die Namen sind vegeben, dass ich das ganze mal sehr sauber dastehen habe um später in ne DB zu übergeben.
Hyperion hat geschrieben: - Zeilenlänge kürzen! PEP8 erlaubt max. 80 Zeichen.
Wat? :-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

jeff84 hat geschrieben:
Hyperion hat geschrieben: - wozu willst Du jedes einzelne Attribut benennen? Du verwendest die Namen ja quasi gar nicht. Wenn doch, würde ich statt eines Tupels ein dict nehmen.
Die Namen sind vegeben, dass ich das ganze mal sehr sauber dastehen habe um später in ne DB zu übergeben.
Hm... das Einfügen passiert doch meist eh über ein Tupel. Zudem fände ich ein dict dann immer noch übersichtlicher. Zumal man den Code mit einer Liste oder einem dict wesentich kompakter schreiben könnte.
jeff84 hat geschrieben:
Hyperion hat geschrieben: - Zeilenlänge kürzen! PEP8 erlaubt max. 80 Zeichen.
Wat? :-)
PEP8
@HWK: Ooops ;-)
jeff84
User
Beiträge: 6
Registriert: Montag 26. Oktober 2009, 17:36

Hyperion hat geschrieben: Hm... das Einfügen passiert doch meist eh über ein Tupel. Zudem fände ich ein dict dann immer noch übersichtlicher. Zumal man den Code mit einer Liste oder einem dict wesentich kompakter schreiben könnte.
Ok, dazu hab ich mir noch keine Gedanken gemacht, wie ich das einfüge/eingefügt bekomme... Wollte es halt etwas übersichtlich haben, damit ich gleich weiß, welches Feld was ist, ohne mir das nochmal genauer anschauen zu müssen.
Hyperion hat geschrieben: PEP8
@HWK: Ooops ;-)
Ok, gut zu wissen. Aber wie bekomme ich solche Zeilen, die zu lange sind, möglichst schön gekürzt? Alleine der Link ist doch schon 101 Zeichen lang...

Auf jeden Fall schonmal danke für alle Kritiken. Bin noch am Lernen und da hilft das...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

jeff84 hat geschrieben:Ok, gut zu wissen. Aber wie bekomme ich solche Zeilen, die zu lange sind, möglichst schön gekürzt? Alleine der Link ist doch schon 101 Zeichen lang...
Du kannst die Url an einen Namen binden

Code: Alles auswählen

url = "http://sis-handball.de/foobar"
ob es darueber hinaus noch sinnvoll ist die URL zu zerlegen und dann wieder zusammenzusetzen bezweifel ich, aber alleine durch das auslagern ist dir schon geholfen.
jeff84
User
Beiträge: 6
Registriert: Montag 26. Oktober 2009, 17:36

Gut, hab das Ganze nach euren Tipps weiter angepasst. Die Link-Zeile ist trotzdem noch zu lang. Genauso wie bei den tabeig die style-Zeile...

Code: Alles auswählen

import mechanize
from BeautifulSoup import BeautifulSoup

br = mechanize.Browser()
br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2')]
url = 'http://www.sis-handball.de/web/Default.aspx?view=Tabelle&Liga=001510504503503000000000000000000003000'
soup = BeautifulSoup(br.open(url).read())
tabeig = {
	"cellpadding" : "0",
	"cellspacing" : "0",
	"style" : STYLE
	}
tables = soup.findAll("table", tabeig)
table = tables[1]
for row in table.findAll('tr')[1:]:		
	col = row.findAll('td')
	Team = row.findAll('a')	
	try:
		col[1]
	except IndexError:
		continue
	Zeile = {	
		'Platz' : col[1].string,
		'Mannschaft' : Team[0].string,
		'Spiele' : col[3].string,
		'Siege' : col[4].string,
		'Unentschieden' : col[5].string,
		'Niederlagen' : col[6].string,
		'Tore' : col[7].string,
		'Tordiff' : col[8].string,
		'Punkte' : col[9].string
		}	
	print Zeile

EDIT: Der lebarkeit halber STYLE ersetzt. Im Code weiter unten wieder richtig zu finden...
Zuletzt geändert von jeff84 am Donnerstag 12. November 2009, 10:28, insgesamt 1-mal geändert.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Code: Alles auswählen

"style" : "font-family:Lucida Sans, Verdana, Arial;color: #272829; "
                   "font-size: 14px; text-align:center; margin-left: auto; "
                   "margin-right: auto; width: 95%; margin-top: 5px; "
                   "margin-bottom: 5px;" }
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Evtl. könnte man die Zuordnung der Daten noch ein wenig kompakter schreiben:

Code: Alles auswählen

In [1]: keys = ("Platz", "Mannschaft", "Spiele")

In [3]: col = [1, "b", 42]

In [4]: zip(keys, col)
Out[4]: [('Platz', 1), ('Mannschaft', 'b'), ('Spiele', 42)]

In [5]: dict(zip(keys, col))
Out[5]: {'Mannschaft': 'b', 'Platz': 1, 'Spiele': 42}
Da in Deiner col-Liste wohl aber Objekte stehen, bei denen Du auf ein "string"-Attribut zugreifst, müßte man mal gucken, ob das auch per str() Funktion klappt. Zur Not würde man das dann auch mit einer wrapper-Funktion lösen können - wobei sich dann die Frage stellt, ob das noch sinnvoll ist :-)

Noch was zur Codierung: Nach PEP8 team statt Team und zeile statt Zeile.

Wobei man sich dann noch streiten kann, ob man nicht ganz auf Deutsche Bezeichner verzichtet ;-)
jeff84
User
Beiträge: 6
Registriert: Montag 26. Oktober 2009, 17:36

Hyperion hat geschrieben:Evtl. könnte man die Zuordnung der Daten noch ein wenig kompakter schreiben:

Code: Alles auswählen

In [1]: keys = ("Platz", "Mannschaft", "Spiele")

In [3]: col = [1, "b", 42]

In [4]: zip(keys, col)
Out[4]: [('Platz', 1), ('Mannschaft', 'b'), ('Spiele', 42)]

In [5]: dict(zip(keys, col))
Out[5]: {'Mannschaft': 'b', 'Platz': 1, 'Spiele': 42}
Da in Deiner col-Liste wohl aber Objekte stehen, bei denen Du auf ein "string"-Attribut zugreifst, müßte man mal gucken, ob das auch per str() Funktion klappt. Zur Not würde man das dann auch mit einer wrapper-Funktion lösen können - wobei sich dann die Frage stellt, ob das noch sinnvoll ist :-)

Noch was zur Codierung: Nach PEP8 team statt Team und zeile statt Zeile.

Wobei man sich dann noch streiten kann, ob man nicht ganz auf Deutsche Bezeichner verzichtet ;-)
Das ist ne deutsche Webseite und ich verwende das Ding und ich kann deutsch :-). Also werde ich dabei bleiben :-).

Das mit der Zuordnung verstehe ist, allerdings ist noch das Problem, dass Mannschaft nicht in col[1] steht, sondern in team[0].
Außerdem hab ich nun mal noch die Strings mit reinen Zahlen in ints umgewandelt, da ich nicht weiß, ob ich das irgendwie noch brauchen kann. Außerdem ist das ganze nicht als was wichtiges produktives gedacht, sondern aus Spaß an der Freude zum Lernen.

Code: Alles auswählen

import mechanize
from BeautifulSoup import BeautifulSoup

br = mechanize.Browser()
br.addheaders = [('User-agent', 'Mozilla/5.0 '
    '(X11; U; Linux i686; de; rv:1.9.1.2) '
    'Gecko/20090729 Firefox/3.5.2')]
url = 'http://www.sis-handball.de/web/Default.aspx?view=Tabelle&Liga=001510504503503000000000000000000003000'
soup = BeautifulSoup(br.open(url).read())
tabeig = {
    "cellpadding" : "0",
    "cellspacing" : "0",
    "style" : "font-family:Lucida Sans, Verdana, Arial;color: #272829; "
        "font-size: 14px; text-align:center; margin-left: auto; "
        "margin-right: auto; width: 95%; margin-top: 5px; "
        "margin-bottom: 5px;"
    }
tables = soup.findAll("table", tabeig)
table = tables[1]
for row in table.findAll('tr')[1:]:		
    col = row.findAll('td')
    team = row.findAll('a')	
    try:
        col[1]
    except IndexError:
        continue
    zeile = {	
        'Platz' : int(col[1].string),
        'Mannschaft' : team[0].string,
        'Spiele' : col[3].string,
        'Siege' : int(col[4].string),
        'Unentschieden' : int(col[5].string),
        'Niederlagen' : int(col[6].string),
        'Tore' : col[7].string,
        'Tordiff' : int(col[8].string),
        'Punkte' : col[9].string
    }
    print zeile
Danke auf jeden Fall für eure Hilfen. Ich freue mich über alle Anregungen...
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

jeff84 hat geschrieben: Das mit der Zuordnung verstehe ist, allerdings ist noch das Problem, dass Mannschaft nicht in col[1] steht, sondern in team[0].
Na gut, das könnte man ja hinter immer noch ins dict adden! Bei einem dict kommt es ja eben nicht auf die Reihenfolge an ;-)
hans.mueller1206
User
Beiträge: 15
Registriert: Donnerstag 22. März 2012, 02:31

wenn hier jmd. noch aktiv ist und mir helfen kann eine Tabelle auszulesen soll der jenige sich doch bitte kurz melden! Ich suche eine Möglichkeit ein Plugin zu schreiben und würde gerne die 1. BL Tabelle auslesen, danke sehr!!!

Euer

Hans
BlackJack

@hans.mueller1206: Wo liegt denn das Problem? Funktioniert der Code hier nicht mehr? Denn die Tabellen scheinen gleich aufgebaut zu sein. Die Webseiten unterscheiden sich nur durch die Liga-ID in der URL.
deets

Dafuer darfst du ein neues Thema aufmachen. Und uns erstmal zeigen, was du schon probiert hast.
hans.mueller1206
User
Beiträge: 15
Registriert: Donnerstag 22. März 2012, 02:31

Ich muss gestehen ich kenne mich nicht unbedingt gut aus mit Python, daher habe ich selbst noch nicht viel versucht bzw. gar nichts :-( !
Aber folgende Plugin hat ein mir jmd. zu gesand:

Code: Alles auswählen

import re
import sys
import urllib2, urllib
import json
from plugin import *

try:
   from imdb import IMDb
   import imdb.helpers
except ImportError:
   raise NecessaryModuleNotFound("Oops! Unable to locate the IMDb library. Please install IMDbPy. e.g. (sudo easy_install IMDbPy) or (sudo apt-get install python-imdbpy)")

class nurf_imdb(Plugin):

    @register("de-DE", "(Film)* ([\w ]+)") 
    def get_director(self, speech, language,  regex):
        if language == "de-DE":
            MovieTitle = regex.group(regex.lastindex).strip()
            ia = IMDb()
            search_result = ia.search_movie(MovieTitle)
            if not search_result:
                self.say("Leider keinen Film gefunden mit: " + MovieTitle)
                self.complete_request()
                
            else:
                movie_info = search_result[0]
                ia.update(movie_info)    
                MovieRating = movie_info['rating']
		
		try:
		    mpaalala = movie_info['mpaa']
		    mpaalala = re.match("Rated ([\w ]+) for", mpaalala, re.IGNORECASE)
		    mpaalala = mpaalala.group(1).strip()
		    if mpaalala == 'R':
			mpaalala = 'ab 16, '
		    if mpaalala == 'PG':
			mpaalala = 'ab 6, '
		    if mpaalala == 'PG-13, ':
			mpaalala = 'ab 12'
		    if mpaalala == 'NC-17, ':
			mpaalala = 'ab 18, '
		    if mpaalala == 'G':
			mpaalala = 'ab 0, '
		except:
		    mpaalala = ''
		self.say(movie_info['title'] + " (" + str(movie_info['year']) + ", " + mpaalala + "Wertung: "+  str(MovieRating) +") ")
                self.complete_request()

und so ähndlich müsste das mit dem Bundesliga Plugin ja auch gehen... ich hoffe auf Hilfe :-) !

Gruß

Hans
Zuletzt geändert von Anonymous am Donnerstag 22. März 2012, 15:30, insgesamt 1-mal geändert.
Grund: Code-Tags
deets

Bitte:

- eigenen thread aufmachen, nicht einen 3 jahre alten hi-jacken
- python-code-tags benutzen. so kann man nix lesen!!!
Antworten