minidom Ergebnis filtern

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.
Antworten
sveni_lee
User
Beiträge: 92
Registriert: Montag 14. März 2016, 09:50

Ich habe eiene xml-Abrage die eine große Anzahl von Ergebnissen liefert.

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from xml.dom import minidom
import urllib

staffel = 1
episode = 10

def get_detail_thetvdb():
    url_str="http://thetvdb.com/api/DECE3B6B5464C552/series/72108/all/de.xml"
    xml_str = urllib.urlopen(url_str).read()
    xmldoc = minidom.parseString(xml_str)

    episodes_detail = xmldoc.getElementsByTagName("Episode")

    for Episode in episodes_detail:
        epiid_tvdb = Episode.getElementsByTagName("id")[0]
        epino_tvdb = Episode.getElementsByTagName("EpisodeNumber")[0]
        seano_tvdb = Episode.getElementsByTagName("SeasonNumber")[0]
        epidesc_tvdb = Episode.getElementsByTagName("Overview")

        print("epiid_tvdb:%s, pino_tvdb:%s, seano_tvdb:%s" %
          (epiid_tvdb.firstChild.data, epino_tvdb.firstChild.data, seano_tvdb.firstChild.data))

get_detail_thetvdb()
Ergebis (Auszug):

Code: Alles auswählen

epiid_tvdb:74098, pino_tvdb:1, seano_tvdb:1
epiid_tvdb:74099, pino_tvdb:2, seano_tvdb:1
epiid_tvdb:74100, pino_tvdb:3, seano_tvdb:1
epiid_tvdb:74101, pino_tvdb:4, seano_tvdb:1
epiid_tvdb:74102, pino_tvdb:5, seano_tvdb:1
epiid_tvdb:74103, pino_tvdb:6, seano_tvdb:1
epiid_tvdb:74104, pino_tvdb:7, seano_tvdb:1
epiid_tvdb:74105, pino_tvdb:8, seano_tvdb:1
epiid_tvdb:74106, pino_tvdb:9, seano_tvdb:1
epiid_tvdb:74107, pino_tvdb:10, seano_tvdb:1
epiid_tvdb:74108, pino_tvdb:11, seano_tvdb:1
epiid_tvdb:74109, pino_tvdb:12, seano_tvdb:1
epiid_tvdb:74110, pino_tvdb:13, seano_tvdb:1
epiid_tvdb:74111, pino_tvdb:14, seano_tvdb:1
epiid_tvdb:74112, pino_tvdb:15, seano_tvdb:1
epiid_tvdb:74113, pino_tvdb:16, seano_tvdb:1
epiid_tvdb:74114, pino_tvdb:17, seano_tvdb:1
epiid_tvdb:74115, pino_tvdb:18, seano_tvdb:1
epiid_tvdb:74116, pino_tvdb:19, seano_tvdb:1
epiid_tvdb:74117, pino_tvdb:20, seano_tvdb:1
epiid_tvdb:74118, pino_tvdb:21, seano_tvdb:1
epiid_tvdb:74119, pino_tvdb:22, seano_tvdb:1
epiid_tvdb:74120, pino_tvdb:23, seano_tvdb:1
epiid_tvdb:74121, pino_tvdb:1, seano_tvdb:2
epiid_tvdb:74122, pino_tvdb:2, seano_tvdb:2
epiid_tvdb:74123, pino_tvdb:3, seano_tvdb:2
epiid_tvdb:74124, pino_tvdb:4, seano_tvdb:2
epiid_tvdb:74125, pino_tvdb:5, seano_tvdb:2
epiid_tvdb:74126, pino_tvdb:6, seano_tvdb:2
epiid_tvdb:74127, pino_tvdb:7, seano_tvdb:2
epiid_tvdb:74128, pino_tvdb:8, seano_tvdb:2
epiid_tvdb:74129, pino_tvdb:9, seano_tvdb:2
Ich möchte aber beispielweise nur die Eintrag haben, bei dem bspw. seano_tvdb=1 und pino_tvdb=10 ist
bekomme ich aber nicht hin...
da ich seano_tvdb.firstChild.data irgendwie nicht in eine if / else Fuktion hineinbekomme..
BlackJack

@sveni_lee: Ich würde Minidom durch die ElementTree-API austauschen und da dann am besten auch gleich `lxml.etree` statt des Moduls aus der Standardbibliothek. Dann kann man XPath verwenden.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sveni_lee: wo ist das Problem? if solltest Du ja schon kennen?

Code: Alles auswählen

def get_detail_thetvdb():
    url_str="http://thetvdb.com/api/DECE3B6B5464C552/series/72108/all/de.xml"
    episodes = ET.parse(urllib.urlopen(url_str))
    for episode in episodes.iterfind('.//Episode'):
        id = int(episode.findtext('id'))
        episode_number = int(episode.findtext('EpisodeNumber'))
        season_number = int(episode.findtext('SeasonNumber'))
        overview = episode.findtext('Overview')
        if staffel == season_number and episode == episode_number:
            print(overview)
sveni_lee
User
Beiträge: 92
Registriert: Montag 14. März 2016, 09:50

I hab's jetzt mit viel googeln hinbekommen...

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from xml.dom import minidom
import urllib

staffel = "13"
episode ="7"

def get_detail_thetvdb():
    url_str="http://thetvdb.com/api/DECE3B6B5464C552/series/72108/all/de.xml"
    xml_str = urllib.urlopen(url_str).read()
    xmldoc = minidom.parseString(xml_str)

    episodes_detail = xmldoc.getElementsByTagName("Episode")

    for Episode in episodes_detail:
        if Episode.getElementsByTagName('SeasonNumber')[0].firstChild.nodeValue == staffel and Episode.getElementsByTagName('EpisodeNumber')[0].firstChild.nodeValue == episode:  
            epiid_tvdb = Episode.getElementsByTagName("id")[0].firstChild.nodeValue
            epidesc_tvdb = Episode.getElementsByTagName("Overview")[0].firstChild.nodeValue.encode('utf-8')
            print epiid_tvdb
            print epidesc_tvdb
            break

get_detail_thetvdb()
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sveni_lee: ich frage mich, was es da zu googeln gibt? Dass ein String nicht gleich einer Zahl ist, sollte doch klar sein. Du solltest unbedingt lernen, was Funktionsargumente sind, url_str, staffel und episode sollten alle Argumente von get_detail_thetvdb sein. Zudem fehlt noch ein sinnvoller Rückgabewert. Ich hoffe Du siehst anhand meines Beispiels, dass ElementTree die deutlich schönere API hat als minidom.
sveni_lee
User
Beiträge: 92
Registriert: Montag 14. März 2016, 09:50

ich habe es jetzt so gelöst:

Code: Alles auswählen

def get_detail_thetvdb(imdbnumber, staffel, episode):
	url_str="http://thetvdb.com/api/DECE3B6B5464C552/series/"+imdbnumber+"/all/de.xml"
	xml_str = urllib.urlopen(url_str).read()
	xmldoc = minidom.parseString(xml_str)

	episodes_detail = xmldoc.getElementsByTagName("Episode")

	for Episode in episodes_detail:
		try:
			if Episode.getElementsByTagName('SeasonNumber')[0].firstChild.nodeValue == staffel and Episode.getElementsByTagName('EpisodeNumber')[0].firstChild.nodeValue == episode:  
				epiid = Episode.getElementsByTagName("id")[0].firstChild.nodeValue
				epidesc = Episode.getElementsByTagName("Overview")[0].firstChild.nodeValue
				rating = Episode.getElementsByTagName("Rating")[0].firstChild.nodeValue
				firstaired = Episode.getElementsByTagName("FirstAired")[0].firstChild.nodeValue
				return {'epiid':epiid, 'epidesc':epidesc, 'rating':rating, 'firstaired':firstaired}
				break
		except:
			return 0

Code: Alles auswählen

			details = get_detail_thetvdb(imdbnumber, staffel, episode)
			if (details ==0):
				debug("Episode nicht in TheTVDB")
				details = get_SerienDetails_Wunschliste(detailurl)
				epidesc = details['desc']
				rating = details['rating']
				firstaired = details['oirg_erst']
				thumbUrl = details['pic_path']
			else:
				epiid = details['epiid']
				epidesc = details['epidesc']
				rating = details['rating']
				firstaired = details['firstaired']
				thumbUrl = "http://www.thetvdb.com/banners/episodes/"+imdbnumber+"/"+epiid+".jpg"
liefert mir das gewünschte Ergebnis
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sveni_lee: was soll denn das try-except bewirken? Ein nacktes except ist (fast) nie sinnvoll, weil damit alle Fehler (auch manche Programmierfehler) verdeckt werden, so dass die Fehlersuche quasi unmöglich wird. Was soll das return 0? Eine Funktion sollte praktischer Weise nur einen Typ (oder None) als Rückgabewert haben, damit man sinnvoll mit dem Ergebnis weiterarbeiten kann. Hier wäre es besser überhaupt nichts zurückzugeben, sondern die Exception einfach nach oben durchzureichen, dann weiß der Aufrufer genauso, dass ein Fehler aufgetreten ist und hat zusätzlich noch die Möglichkeit darauf individuell zu reagieren. Das break nach return ist überflüssig. Was passiert, wenn Episode oder Season gar nicht gefunden werden?

Die Einrückung ist falsch, es wird immer mit 4 Leerzeichen pro Ebene eingerückt. Im übrigen bin ich immer noch der Meinung, dass ElementTree die klarere API hat. Lerne lieber gleich den eleganteren Weg, Du willst danach minidom nie wieder anfassen.

Im zweiten Teil sind die Klammern um die if-Bedingung überflüssig. Das würde man auch besser mit einem exception-Handling machen.
sveni_lee
User
Beiträge: 92
Registriert: Montag 14. März 2016, 09:50

Sirius3 hat geschrieben:was soll denn das try-except bewirken? Ein nacktes except ist (fast) nie sinnvoll, weil damit alle Fehler (auch manche Programmierfehler) verdeckt werden, so dass die Fehlersuche quasi unmöglich wird. Was soll das return 0? Eine Funktion sollte praktischer Weise nur einen Typ (oder None) als Rückgabewert haben, damit man sinnvoll mit dem Ergebnis weiterarbeiten kann.
Ich hatte folgende Überlegung: es ist ja durchaus möglich, dass keine Details auf TheTVDB gefunden werden, dann wird eine Null zurück gegeben. Wenn der wert == 0 ist werden die details woanders hergeholt... ich könnte an der Stelle sicher auch ein None verwenden...
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sveni_lee: dass keine Details da sind, ist eine Ausnahme und daher solltest Du Exceptions verwenden.
sveni_lee
User
Beiträge: 92
Registriert: Montag 14. März 2016, 09:50

okay... danke für den Hinweiß...

so ganz habe ich das noch nicht verstanden, meinst Du das in der Form?

Code: Alles auswählen

def get_detail_thetvdb(imdbnumber, staffel, episode):
   url_str="http://thetvdb.com/api/DECE3B6B5464C552/series/"+imdbnumber+"/all/de.xml"
   xml_str = urllib.urlopen(url_str).read()
   xmldoc = minidom.parseString(xml_str)

   episodes_detail = xmldoc.getElementsByTagName("Episode")

   for Episode in episodes_detail:
      try:
         if Episode.getElementsByTagName('SeasonNumber')[0].firstChild.nodeValue == staffel and Episode.getElementsByTagName('EpisodeNumber')[0].firstChild.nodeValue == episode: 
            epiid = Episode.getElementsByTagName("id")[0].firstChild.nodeValue
            epidesc = Episode.getElementsByTagName("Overview")[0].firstChild.nodeValue
            rating = Episode.getElementsByTagName("Rating")[0].firstChild.nodeValue
            firstaired = Episode.getElementsByTagName("FirstAired")[0].firstChild.nodeValue
            return {'epiid':epiid, 'epidesc':epidesc, 'rating':rating, 'firstaired':firstaired}
            break
      except ValueError:
         return False
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sveni_lee: nein, ich meine das so:

Code: Alles auswählen

def get_detail_thetvdb(imdbnumber, staffel, episode):
    url_str="http://thetvdb.com/api/DECE3B6B5464C552/series/%s/all/de.xml" % imdbnumber
    episodes = ET.parse(urllib.urlopen(url_str))
    for episode in episodes.iterfind('.//Episode'):
        episode_number = episode.findtext('EpisodeNumber')
        season_number = episode.findtext('SeasonNumber')
        if staffel == season_number and episode == episode_number:
            id = int(episode.findtext('id'))
            overview = episode.findtext('Overview')
            rating = episode.findtext("Rating")
            firstaired = episode.findtext("FirstAired")
            return {
                'epiid':id,
                'epidesc':overview,
                'rating':rating,
                'firstaired':firstaired,
                'thumb_url': "http://www.thetvdb.com/banners/episodes/%s/%s.jpg" % (imdbnumber, id)
            }
    raise KeyError('not found')
    
def get_details(imdbnumber, staffel, episode):
    try:
        details = get_detail_thetvdb(imdbnumber, staffel, episode)
    except KeyError:
        debug("Episode nicht in TheTVDB")
        details = get_SerienDetails_Wunschliste(detailurl)
    return details
get_SerienDetails_Wunschliste sollte natürlich ein gleich strukturiertes Wörterbuch zurückgeben wie get_detail_thetvdb, denn es ist doch unnötiger Mehraufwand, erst ein Wörterbuch zu erstellen, um es danach noch einmal umkopieren zu müssen.
Antworten