Seite 1 von 1

Klasse zum Songtext suchen

Verfasst: Dienstag 12. Dezember 2006, 17:50
von dodo47
Hallo,
ich hab eine Klasse geschrieben die Songtexte bei http://www.leoslyrics.com/ sucht und diese dann ausgibt.

Code: Alles auswählen

import urllib
import re

class Lyrics:
    def __init__(self):

        self.list_reg   = re.compile(r"<td>[.|\s]*<font .*>[.|\s]*<a href=\".*\">(.*)</a>[.|\s]*</font>[.|\s]*</td>[.|\s]*<td>[.|\s]*<font .*>[.|\s]*<a href=\"(.*)\"><b>(.*)</b></a>[.|\s]*</font>[.|\s]*</td>")
        self.result_reg = re.compile(r"<p>[.|\s]*Found <b>(\d*)</b> results\.[.|\s]*</p>")
        self.sid_reg    = re.compile(";jsessionid=.*\\?")
    
    def search(self, artist = "", song = "", album = ""):

        return_list = []
        self.url_list = []

        artist = urllib.quote(artist)  
        song   = urllib.quote(song)  
        album  = urllib.quote(album)
        url    = "http://www.leoslyrics.com/advanced.php?artistmode=0&artist="+artist+"&albummode=0&album="+album+"&songmode=0&song="+song+"&mode=0"
        page   = urllib.urlopen(url)
        page   = page.read()

        results = int(re.findall(self.result_reg, page)[0])

        if results%40 == 0:
            pages = results/40
        else:
            pages = results/40+1

        self.big_list = re.findall(self.list_reg, page)

        n = 2
        while n < pages:
                page = urllib.urlopen(url+"&page="+str(n))
                page = page.read()
                self.big_list.append(re.findall(self.list_reg, page))
                n = n+1

        for n in self.big_list:
            return_list.append((n[0], n[2]))
            self.url_list.append("http://www.leoslyrics.com"+re.sub(self.sid_reg, "?", n[1]))
        return_list = tuple(return_list)
        self.url_list = tuple(self.url_list)

        return return_list

    def get_text(self, number):
        page = urllib.urlopen(self.url_list[number]).read()

        page = page.replace('\r\n', '\r')
        page = page.replace('\r\n', '\r')
        new = []
        for zeile in page.split("\r"):
            zeile = zeile.strip()
            if not zeile == "":
                new.append(zeile.strip())

        lyric = []
        first = True
        for n in range(0, len(new)):
            if new[n].startswith("<br />"):
                if first:
                    lyric.append(self.__finish__(new[n-1]))
                    lyric.append(self.__finish__(new[n]))
                    first = False
                else:
                    lyric.append(self.__finish__(new[n]))
        return lyric

    def __finish__(self, string):
        string = string.replace("\r", "")
        string = string.replace("'", "'")
        string = string.replace(""", "\"")
        string = string.replace("<br />", "")
        return string
Benutzt wir das ganze wie folgt:

Code: Alles auswählen

suche = Lyrics()
ergebnis = suche.search(artist = "irgendwas")
songtext = suche.get_text(index_zahl_von_ergebnis)
Findet ihr das nützlich?
Über Verbesserungsvorschläge würde ich mich freuen.
Gruß
dodo47

Verfasst: Freitag 15. Dezember 2006, 12:42
von birkenfeld
Mir ist nur aufgefallen: __finish__ finde ich nicht gerade einen tollen Methodennamen. Es gibt keine Grund für die Unterstriche, sie verwirren nur.

Verfasst: Freitag 15. Dezember 2006, 16:29
von mitsuhiko
Habs nur schnell überflogen. Verbesserungsvorschläge: kein __finish__, das sollte man nur für interne python Funktionen verwenden, _finish ist da besser. Und ein maximales Zeilenlimit von 80 Zeichen ist grunsätzlich eine gute Idee.

Verfasst: Freitag 15. Dezember 2006, 17:29
von SigMA

Code: Alles auswählen

n = n+1
schöner:

Code: Alles auswählen

n += 1
Hab auch nur kurz drüber geschaut. Aber ich bin mir sicher, dass ich nochmal auf den Quellcode zugreifen werde =)

SigMA

Verfasst: Freitag 15. Dezember 2006, 20:37
von sape
@dodo47:
Willkommen im Forum.

Erstmal Coole Sache. Kann man gebrauchen.

Kritik:
Zeile 8-10 ist über EOL80.


Zeile 15: `self.url_list = []`. Warum wird das Klassenattribut nicht schon im Konstruktor bekannt gemacht? Also alles mit `self.` am Anfang ist Global in der Klasse ansprechbar. Da finde ich, das man Attribute nicht verstreut einführen sollte sondern Zentral und das am besten im Konstruktor. Daher würde ich `self.url_list = []` unter dem Atribut `self.sid_reg` in der `__init__`-Methode schrieben.

Zeile 31: Siehe Zeile 15.

Zeile 20: Über EOL80 und sonst auch nicht PEP8 Konform.

Ich würde dir empfehlen PEP8 zu lesen.
Z.B:

Code: Alles auswählen

 page = urllib.urlopen(url+"&page="+str(n))  
gehört

Code: Alles auswählen

 page = urllib.urlopen(url + "&page=" + str(n))

Code: Alles auswählen

 if results%40 == 0:
            pages = results/40
        else:
            pages = results/40+1
gehört

Code: Alles auswählen

 if results % 40 == 0:
            pages = results / 40
        else:
            pages = results / 40 + 1
etc.


PEP8: http://www.python.org/dev/peps/pep-0008/

Verfasst: Freitag 15. Dezember 2006, 20:39
von sape
SigMA hat geschrieben:

Code: Alles auswählen

n = n+1
schöner:

Code: Alles auswählen

n +=1
[...]
Leerzeichen nicht vergessen.

Code: Alles auswählen

n += 1

Verfasst: Montag 18. Dezember 2006, 14:59
von dodo47
Danke für die Antworten.
Hab mal das zu beantstandene verbessert und die Leerzeichen eingefügt, nur wie bekomme ich diese langen Zeilen mit den regexp denn unter 80 Zeichen?

Will das ganze jetzt so erweitern das einmal gesuchte Songtexte in einer sqlite Datenbank gespeichert werden, nur da hänge ich ein wenig bei der Kodierung der Querys, da mann ja oft die gleichen Lieder hört und so sich und der Songtextseite Traffic erspart.

BTW:
Kennt ihr andere Seiten wo man Songtexte bekommt OHNE sich dafür anmelden zu müßen?

Verfasst: Montag 18. Dezember 2006, 16:38
von Python 47
Hallo Dodo 47,

die langen Zeilen bekommst du so weg:
[wiki]Lange Zeilen im Sourcecode[/wiki]
und ne Seite wo man Songtexte ohne Anmeldung bekommt hab ich auch:
http://lyrics.songtext.name/

Verfasst: Dienstag 19. Dezember 2006, 00:54
von Y0Gi
Die Zeilen 17-22 sind ebenfalls nicht PEP-konform, weil diese Tabulator-Fakes bei Änderungen irgendwann nicht mehr gepflegt und dann ein unschönes Hindernis werden.

Für reguläre Ausdrücke gibt es auch eine Verbose-Syntax, mit der man sie mehrzeilig gestalten und Kommentare einfügen kann.


Insgesamt mal wieder bemerkenswert, dass hier generell viel über Aussehen und Struktur des Codes nachgedacht wird und weniger um die eigentliche Funktion (wobei letztere aber in aller Regel bei diesen Codesnippet-Threads in Ordnung und nicht weiter diskutierbar ist). Aber das gefällt mir irgendwie an der Python-Gemeinde und grenzt *sehr stark* gegenüber vielen Java- und PHP-Schmieden ab.