Seite 2 von 2

Re: python im Internet & HTML

Verfasst: Montag 6. Oktober 2014, 21:35
von BlackJack
@evd: Na da steht doch ziemlich deutlich warum pip das nicht installiert und was man machen könnte/sollte bevor man es erneut versucht.

Re: python im Internet & HTML

Verfasst: Sonntag 12. Oktober 2014, 15:05
von evd
Danke XD

nach einem Neustart hat es mir die Fehlermeldung auch nimmer angezeigt und ich konnte es ohne Probleme Installieren XD
das ist ja schon fast auf dem gleichen lvl wie "ist auch der Stecker eingesteckt" XD

naja...

also ich habe es jetzt soweit

Code: Alles auswählen

import lxml.html
import requests
r=requests.get("http://www.amazon.de/...")
test=lxml.html.fromstring(r.text)
link = test.cssselect('html body div div div div div div div div h3.newaps div a')
for i in range(0,len(link)):
    print (lxml.html.tostring(link[i]))
das Resultat ist jetzt

Code: Alles auswählen

b'<a href="http://www.amazon.de/Greatest-Hits-So-Far-Explicit/dp/artist-redirect/B00F4122W4">P!nk</a>'
wie kann ich da jetzt den Namen (hier P!nk) extrahieren ...
Die URL bekomme ich ja mit

Code: Alles auswählen

link[i].get("href")
also ich könnte natürlich den String bearbeiten ...
aber das ist halt keine so schöne Lösung ...

Re: python im Internet & HTML

Verfasst: Sonntag 12. Oktober 2014, 17:21
von BlackJack
@evd: Du musst halt in die Dokumentation schauen wie man an den Text heran kommt. Ein Attribut oder eine Methode gibt's dafür.

Die Schleife mit dem `i` ist ein „anti pattern” in Python. Du kannst da *direkt* über die Elemente iterieren, ohne einen Umweg über einen Index.

Beim CSS ist ein klein bisschen IMHO zu viel angegeben. Das findet die Daten ja nur wenn das Dokument *exakt* diesen Pfad dort hin enthält. Der Witz bei solchen Selektoren ist ja gerade dass man die genau genug macht um die Daten zu finden, aber nicht so genau das man sie nicht mehr finden kann wenn auch nur eine Kleinigkeit an der Seitenstruktur geändert wird. 'html' und 'body' kann man schon mal weg lassen weil es nichts ausserhalb von 'html' gibt, und wenn die Informtionen innerhalb der Websseite angezeigt werden, dann ist 'body' auch irgendwo selbstverständlich. Ausserhalb von Body wird es keines der anderen Tags geben.

Re: python im Internet & HTML

Verfasst: Montag 13. Oktober 2014, 17:24
von evd
danke... habe jetzt soweit alles.... nur jetzt habe ich ein anderes Problem ...

... wenn ich einen Namen mit einem ä,ö,ü,ß auslese bekomme ich (natürlich) die Aussage, das ASCII damit wenig anfangen kann... ich dachte mir UTF-8 ftw

Code: Alles auswählen

lxml.html.tostring(link[i], method="text", encoding="utf-8")
nun gibt er mir immer noch nur Müll aus, nur jetzt ohne meldung, der knallt mit einfach die "F\xc3\" und "\xc3\xa4" in mein Text, das es nimmer feierlich ist.

was für ein encoder soll ich denn verwenden?

Re: python im Internet & HTML

Verfasst: Montag 13. Oktober 2014, 18:04
von BlackJack
@evd: Das kann nicht sein. Wenn Du da UTF-8 angibst, dann werden in den Text keine Escape-Sequenzen eingefügt. Die kommen da erst rein wenn Du die `repr()`-Umwandlung direkt oder indirekt machst und das dann anschaust. Das ist ja auch gut so, denn wenn man das macht möchte man ja wissen welche Bytewerte sich tatsächlich in einer Zeichen-/Bytekette befinden, unabhängig davon was das ”Ausgabemedium” als Kodierung erwartet.

Falls Du `html.tostring()` jetzt tatsächlich zum auslesen des Attributs mit dem Text von dem Link-Tag verwendest, würde ich das als Missbrauch der Funktion ansehen.

Re: python im Internet & HTML

Verfasst: Montag 13. Oktober 2014, 18:32
von evd
ich verstehe jetzt nicht wo da jetzt der Missbrauch der Funktion "tostring()" ist, ich will doch was in ein string umwandeln ...

ach wenn es dir an glauben fehlt das mit uft-8 diese Meldungen rein donnert bekomme ich bei dem:

Code: Alles auswählen

print(link[23])
print(lxml.html.tostring(link[23], method="text", encoding="utf-8"))
print((link[23].get("href")))
print(lxml.html.tostring(link[23], encoding="utf-8"))
print(lxml.html.tostring(link[23], method="text"))
(Programmcode siehe oben)

bekomme ich als Ergebnis dieses hier:

Code: Alles auswählen

<Element a at 0x7ff8bef618b8>
b'F\xc3\xbcnf Freunde'
b'<a href="http://www.amazon.de/108-die-Entf%C3%BChrung-im-Skigebiet/dp/artist-redirect/B00MBJ4K5Y">F\xc3\xbcnf Freunde</a>'
http://www.amazon.de/108-die-Entf%C3%BChrung-im-Skigebiet/dp/artist-redirect/B00MBJ4K5Y
Traceback (most recent call last):
  File "/home/evd/Schreibtisch/python/Amazon/a.py", line 21, in <module>
    print(lxml.html.tostring(link[23], method="text"))
  File "/usr/lib/python3/dist-packages/lxml/html/__init__.py", line 1621, in tostring
    doctype=doctype)
  File "lxml.etree.pyx", line 3157, in lxml.etree.tostring (src/lxml/lxml.etree.c:69331)
  File "serializer.pxi", line 99, in lxml.etree._tostring (src/lxml/lxml.etree.c:114033)
  File "serializer.pxi", line 71, in lxml.etree._textToString (src/lxml/lxml.etree.c:113825)
UnicodeEncodeError: 'ascii' codec can't encode character '\xfc' in position 1: ordinal not in range(128)
ergo UTF-8 habe ich "\xc3\xbc" an stelle von einem "ü"
und ich bekomme das was ich will (dafür ja ' method="text" ')
ich habe sonst keinen Ahnung wie ich aus "<Element a at 0x7ff8bef618b8>" einen string machen soll also "lxml.html.tostring()

Re: python im Internet & HTML

Verfasst: Montag 13. Oktober 2014, 19:05
von BlackJack
@evd: Du willst den Text eines Elements haben, dafür haben die ein Attribut und eine Methode um diesen Text *direkt* zu bekommen. Stattdessen verwendest Du eine Funktion die deutlich mehr macht, und in diesem Sonderfall halt zufällig das gleiche liefert. Das würde ich Missbrauch nennen.

Das was Du da ausgegeben bekommst ist die Darstellung eines `bytes`-Objekts als Zeichenkette. Also die Zeichenkette die `repr()` auf diesem Wert liefert. Und Bytes ausserhalb von ASCII werden halt als Escapesequenzen dargestellt. Das ist sehr praktisch weil man dann sehen kann welche Bytewerte enthalten sind, ohne das das von einem Terminal noch mal als irgend eine andere Kodierung interpretiert wird.

In Bytes gibt es auch kein 'ü' sondern höchstens eine irgendwie geartete Kodierung eines 'ü'. In UTF-8 sind das die beiden Bytes mit den Werten 195 und 188, beziehungsweise hexadezimal ausgedrückt c3 und bc.

Einen String, also eine *Zeichen*kette, machst Du übrigens auch gar nicht aus dem Element, die Funktion heisst nur aus historischen Gründen so und liefert nur eine *Zeichen*kette wenn man als `encoding` den Wert `unicode` angibt. Aber wie gesagt, um an den Text im <a>-Tag zu kommen ist die Funktion sowieso nicht wirklich das richtige.

Re: python im Internet & HTML

Verfasst: Mittwoch 15. Oktober 2014, 21:35
von evd
So, ich habe es soweit...

nur noch ein Problem stellt sich mir noch im punkto Internet...

wenn ich eine Seite herunterlade

z.b.:

Code: Alles auswählen

self.r=requests.get("http://www.amazon.de")
am Anfang geht es, doch am ende bekomme ich einen Fehler.
Es kann die Verbindung nicht zu amazon aufbauen...

Code: Alles auswählen

requests.exceptions.ConnectionError: HTTPConnectionPool(host='www.amazon.de', port=80): Max retries exceeded with url: "....." (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)

Habe ich da zu viele aufrufe pro sec. gemacht?
wurde ich da von dem Server gesperrt oder wie?
oder warum kann ich da keine Verbindung aufbauen?

Re: python im Internet & HTML

Verfasst: Donnerstag 16. Oktober 2014, 16:09
von evd
ok, sorry für den Doppel post ... habe aber verstanden warum die Fehlermeldung gekommen ist... wurde wahrscheinlich einfach von Amazon server gebannt für kurze zeit XD

jetz habe ich habe ein anderes problem...

dieses ganze hin und her habe ich für ein kleines Programm gemacht, welches bei Amazon die Seiten auslesen und analysieren soll... ich habe den code für diesen teil jetzt geschrieben... aber es will nicht so wie ich es will

Code: Alles auswählen

import threading, queue, lxml.html, requests

#Thread welches die Seiten in Amazon herunterlädt (queue1=1-400 welches den Link vervollständigt, queue2=die Seite)
class suchen():
    def __init__(self, queue1, queue2):
        self.queue1=queue1
        self.queue2=queue2
        self.sucher()
        
    def sucher(self):
        while  True:
            self.i = self.queue1.get()
            if self.i is None:
                self.queue1.task_done()
                break
            else:
                try:
                    self.r=requests.get("http://www.amazon.de/s/ref=sr_pg_"+str(self.i)+"?rh=n%3A77195031%2Cp_36%3A200-499%2Cp_n_format_browse-bin%3A180848031&page="+str(self.i)+"&bbn=77195031&ie=UTF8&qid=1395167727", timeout=60)
                    self.queue2.put(self.r)
                    print(self.i)
                except:
                    print("-")
                self.queue1.task_done()
            

queue1=queue.Queue(500)
queue2=queue.Queue(500)
knuenztlerliste=[]
albumnamenliste=[]
linkalbumliste=[]
bildalbumliste=[]
preisalbumliste=[]
anzahlderrunden=400        #wie viele Seiten ich durchsuchen will
anzahlderthreads=5          #wie viele threads ich dafür starten will (5 weil ich da hoffe nicht so schnell gesperrt zu werden
for n in range (1,anzahlderrunden + anzahlderthreads+1):
    if n > anzahlderrunden:
        queue1.put(None)
    else:
        queue1.put(n)
for s in range (anzahlderthreads):
    threading.Thread(target=suchen, args=(queue1,queue2)).start()
queue1.join()

#hier werden die Seiten durchsucht, nach den Werten die ich haben will
for anzahl in range (queue2.qsize()):
    print(anzahl)
    r=queue2.get()
    test=lxml.html.fromstring(r.text)
    link = test.cssselect('h3.newaps div a')
    n = 0
    for element in link:
#weil in 'schauen1' bei zu langen namen "..." am ende steht
        schauen1=len((element.text))
        try:
            schauen2=len((link[n].get("title")))
        except:
            schauen2=0
        if schauen2>schauen1:
            knuenztlerliste.append((link[n].get("title")))
        else:
            knuenztlerliste.append(element.text)
        n=n+1
    link = test.cssselect('div div h3.newaps a')
    n=0
    for element in link:
        Fehlerbehebung1=n%2          #weil 2 "href" hintereinander sind (ich will nur den ersten)
        if Fehlerbehebung1==0:
            linkalbumliste.append(link[n].get("href"))
        n=n+1
    link = test.cssselect('div h3.newaps a span.lrg.bold')
    n=0
    for element in link:
        schauen1=len((element.text))
        try:
            schauen2=len((link[n].get("title")))
        except:
            schauen2=0
        if schauen2>schauen1:
            albumnamenliste.append(link[n].get("title"))
        else:
            albumnamenliste.append((element.text)) 
        n=n+1
    link = test.cssselect('a div.imageBox img.productImage.cfMarker')
    n=0
    for element in link:
            
        bildalbumliste.append(link[n].get("src"))
        n=n+1
    link = test.cssselect('span.a-button.a-button-primary.MusicCartBuyButton span.a-button-inner a.a-button-text')
    n=0
    for element in link:   
        a=(element.text)    
        preisalbumliste.append(a[21:len(a)])
        n=n+1

#Ausgabe der Werte (im Hauptprogramm wird dies dann anders realisiert)       
print(len(preisalbumliste))
print(len(bildalbumliste))
print(len(linkalbumliste))
print(len(albumnamenliste))
print(len(knuenztlerliste))
print("Es sollten",anzahlderrunden*24,"sein")

Hier habe ich das Problem das es mir fast immer einen anderen wert zurück gibt, als würde es mal mehr mal weniger finden ... aber das kann doch nicht sein ...

ich verstehe die Welt nimmer

Re: python im Internet & HTML

Verfasst: Donnerstag 16. Oktober 2014, 18:06
von Sirius3
@evd: ich versteh auch nicht, was der ganze Code macht, er ist einfach zu lang. Du solltest den Spaghetti-Code auch unbedingt in etliche Funktionen aufteilen.
Was willst Du erreichen? Was kommt raus, was erwartest Du?

Re: python im Internet & HTML

Verfasst: Donnerstag 16. Oktober 2014, 22:00
von BlackJack
@evd: Also wenn diese Listen alle gleich lang sein sollen dann legt das irgendwie den Verdacht nahe das die Informationen am gleichen Index jeweils zusammengehören sollen. In dem Fall sollte man die Daten nicht auf mehrere ”parallele” Listen verteilen sondern jeweils zu einem Objekt zusammenfassen. Im einfachsten Fall reicht dafür vielleicht ein Typ den man sich mit `collections.namedtuple()` erstellt.

Dann müsste man die Informationen zu einem Produkt (nehme ich mal an) auch auf einmal zusammen sammeln und nicht jeden Teil einzeln.

Dieses `n` in den Schleifen ist eigenartig und verwirrend. Du iterierst über `link` und zählst gleichzeitig manuell `n` hoch um ab und zu mit diesem `n` als Index auf `link` zuzugreifen, wobei eigentlich immer nur noch mal das Objekt heraus kommen kann was Du in der Schleife sowieso schon mal an den Namen `element` gebunden hast. Was soll dieser Unsinn? `link` steht nicht für einen Link sondern für *viele*, sollte also eher `links` heissen.

Dann sind da ``except``\s ohne konkrete Ausnahmen drin. Das sollte man nicht machen denn das kann dazu führen dass man Ausnahmen behandelt die man nicht erwartet hat, und die *so* gar nicht sinnvoll behandelbar sind.

Die Klasse `suchen` ist unsinnig. Warum ist das eine Klasse und keine Funktion? Die `__init__()` erledigt die komplette Aufgabe. Ausser der `__init__()` gibt es nur eine weitere Methode. Klassenname und Methodenname sind genau falsch herum, Klassen stellen ”Dinge” dar und Methoden tun etwas.

An eine Klasse gehören nur Attribute die den Zustand des Objekts ausmachen und nicht einfach *alles* was man irgendwo mal in einer Methode an einen Namen binden möchte. Ausserhalb der `__init__()` sollte man auch keine weiteren Attribute einführen.

`queue1` und `queue2` sind schlechte Namen. Namen sollen dem Leser die *Bedeutung* vermitteln, nicht einfach den Datentypen mit einer nichtssagenden Nummer angehängt.

`knuenztlerliste`? ;-) Der Datentyp sollte nicht im Namen stecken. Wenn man den mal ändert, muss man auch überall den Namen ändern, oder man hat falsche, irreführende Namen im Programm. Containerobjekten kann man zum Beispiel einfach die Mehrzahl von dem Namen geben dem man einem Element geben würde. Wobei dann englische Namen praktischer sind, weil es dort sehr selten vorkommt das Einzahl und Mehrzahl gleich benannt sind (artist/artists vs. kuenstler/kuenstler).

Statt das herunterladen und das verarbeiten durch ein `join()` auf der Queue zu trennen, wo der Hauptthread also eine ganze Weile nichts macht, könnte man im Hauptthread auch schon die Verarbeitung machen. Oder sogar in den Threads parallel und in die `queue2` dann schon fertige Ergebnisse stecken.

Re: python im Internet & HTML

Verfasst: Donnerstag 30. Oktober 2014, 00:15
von evd
so, und da bin ich auch wieder...

ich habe nun versucht die von euch kritisierten Sachen entweder zu beheben oder durch eine Erklärung darunter verständlich zu machen.

Meine Erwartung von diesem Programm ist das ich dadurch von der Internetseite amazon jegliche Seiten herunterlade um sie dann auszuwerten.
hinein gebe ich den "Start" Befehl, heraus soll eine Liste von Künstlern, Alben, preisen usw (siehe Beschreibung) kommen, welche ich dann in meinem weiteren Programm verwenden will.

1)Hier habe ich die Frage, warum kann ich nicht das Programm ohne "productImage cfMarker" auf die Suche schicken? es wird dann immer gesagt das es nicht enthalten sei... verstehe ich nicht... ich meine wenn ich eine Ebene weiter oben bin müssten doch immer noch die Nachfahren enthalten sein

2)Das Problem das sich mir hier stellt (was neu ist... zeit dem ich das alles in eine Klasse ein gehauen habe...) ist das es am Anfang die werte aus dem queue heraus liest, aber diese nicht verwendet, und dann mehrmals versucht NONE in die URL ein zu setzen, obwohl ich das eigentlich vorher durch eine if abfrage abfangen müsste ...
so ergibt sich aus 5 Seiten 2 Threads:

Code: Alles auswählen

wert: 1
wert: 2
benutze wert: 2
wert: 3
benutze wert: 3
wert: 4
benutze wert: 4
wert: 5
benutze wert: 5
wert: None
Ende
benutze wert: None
wert: None
Ende
Warum benutzt er noch ein mal wert "None", und wo bleibt das benutzen von wert 1? :K

3) Ich lade die Seiten herunter, und sie sind einfach nicht vollständig ... ka warum ... wenn ich die selbe Seite noch ein mal herunterlade dann ist wieder alles in Butter... ist das einfach der eine unter Hundert ... (hier dann doch ein wenig mehr) ... oder habe ich das was Falsch gemacht?

Code: Alles auswählen

"""
in den 3 Dreidimensionalen Feld ist die erste ebene die Seite (1,2,3,...). 
die Zweite Ebene die Unterteilung (kuenztler,albumname,link,bild,preis)
die Dritte Ebene ist für die exakten Daten freigegeben
"""


import threading, queue, lxml.html, requests
class sucher():
    """
    Diese Klasse sucht auf den Seiten von Amazon nach den Künstlern, Preisen, Alben ... und gibt dieser in
    gegebener Reihenfolge in einem Feld "Scanresultat" wieder.
    """
    def __init__(self):
        self.threadinput=queue.Queue(500)
        self.threadoutput=queue.Queue(500)
        self.zulange=0
        self.n = 0
        self.Scanresultat=[]
        self.Fehler=[]
        self.r=[]
        self.banzahl1=0
        self.banzahl2=0
        self.banzahl3=0
        self.banzahl4=0
        self.banzahl5=0
        for self.i in range (0,400):
            self.Scanresultat.append([])
            for self.n in range (5):
                self.Scanresultat[self.i].append([])
    
    #Dies sind die Threads die gestartet werden sollen, und welche dann die Seite herunter laden
    # 2)
    # 3)
    def suchen(self, threadinput, threadoutput):
        self.athreadinput=threadinput
        self.athreadoutput=threadoutput
        while  True:
            self.r=[]
            self.i = self.athreadinput.get()
            print("wert:",self.i)
            if self.i == None:
                self.athreadinput.task_done()
                print("Ende")
                break
            else:
                try:
                    #als erstes kommt die Seite, und dann die Seiten Nr. um es bei Buggs besser zu unterscheiden und um die Ordnung aufrecht zu erhalten
                    self.r.append(requests.get("http://www.amazon.de/s/ref=sr_pg_"+str(self.i)+"?rh=n%3A77195031%2Cp_36%3A200-499%2Cp_n_format_browse-bin%3A180848031&page="+str(self.i)+"&bbn=77195031&ie=UTF8&qid=1395167727", timeout=60))
                    self.r.append(self.i)
                    self.athreadoutput.put(self.r)
                    print("benutze wert:",self.i)
                except:
                    #wenn die Seite nicht heruntergeladen werden kann 
                    print("-",self.i)
                    self.r.append("-")
                    self.r.append(self.i)
                    self.athreadoutput.put(self.r)
                    
                self.athreadinput.task_done()
    
    #Ruft die Threads auf und setzt die werte für die queue
    def aufrufen (self,anzahl,threads):
        self.anzahlderrunden=anzahl
        self.anzahlderthreads=threads
        for self.n in range (1,self.anzahlderrunden + self.anzahlderthreads+1):
            if self.n > self.anzahlderrunden:
                self.threadinput.put(None)
            else:
                self.threadinput.put(self.n)
        for self.s in range (self.anzahlderthreads):
            threading.Thread(target=self.suchen, args=(self.threadinput,self.threadoutput)).start()
        self.threadinput.join()
        self.auswerten()
        
    #Liest die werte aus, und Speichert die Ergebnisse in ein Feld, Sortierung siehe anfangs-Kommentar     
    def auswerten(self):
        for self.anzahl in range (self.anzahlderrunden):
            self.r=self.threadoutput.get()
            self.test=lxml.html.fromstring(self.r[0].text)
            self.links = self.test.cssselect('h3.newaps div a')
            for element in self.links:
                self.schauen1=len(element.text)
                #wenn der Name zu lang ist wird er durch ein "..." am ende ersetzt, hier wird geschaut ob das der Fall ist
                try:
                    self.schauen2=len((element.get("title")))
                except:
                    self.schauen2=0
                if self.schauen2>self.schauen1:
                    self.Scanresultat[self.r[1]][0].append(element.get("title"))
                else:
                    self.Scanresultat[self.r[1]][0].append(element.text)
            self.links = self.test.cssselect('div div h3.newaps a')
            self.n=0
            for element in self.links:
                #Hier muss ich n benutzen, denn ich brauche nur jedes 2. Suchergebnis... und dies erschien mir als die einfachste und schlichteste Möglichkeit
                self.Fehlerbehebung1=self.n%2
                if self.Fehlerbehebung1==0:
                    self.Scanresultat[self.r[1]][2].append(element.get("href"))
                self.n=self.n+1
            self.links = self.test.cssselect('div h3.newaps a span.lrg.bold')
            for element in self.links:
                #wenn der Name zu lang ist wird er durch ein "..." am ende ersetzt, hier wird geschaut ob das der Fall ist
                self.schauen1=len(element.text)
                try:
                    self.schauen2=len(element.get("title"))
                except:
                    self.schauen2=0
                if self.schauen2>self.schauen1:
                    self.Scanresultat[self.r[1]][1].append(element.get("title"))
                else:
                    self.Scanresultat[self.r[1]][1].append(element.text)
            self.links = self.test.cssselect('div.imageBox img.productImage.cfMarker') # 1)
            for element in self.links:
                self.Scanresultat[self.r[1]][3].append(element.get("src"))
            self.links = self.test.cssselect('a.a-button-text')
            self.n=0
            for element in self.links:
                #Ich benötige den "n" Zähler, denn es gibt auch noch Ergebnisse die mich nicht interessieren (elemente > als 24)
                if self.n<24:
                    self.a=(element.text)    
                    self.Scanresultat[self.r[1]][4].append(self.a[21:len(self.a)])
                    self.n=self.n+1
        print(self.Scanresultat)

asucher=sucher()
asucher.aufrufen(5,2)
Ich hoffe das ich eure Nerven nicht über strapaziere...
und ihr mit weiterhelft (vor allem bei dem Punkt 2 und 1)

Mit freundlichen Grüßen

EvD

Re: python im Internet & HTML

Verfasst: Donnerstag 30. Oktober 2014, 01:19
von BlackJack
@evd: Das ist mir ehrlich gesagt immer noch viel zu konfus zum lesen. Fast sogar noch schlimmer als vorher. Die Klasse ist keine, das ist doch eigentlich nur modulglobales Zeug in eine Klasse verschoben die viel zu viele Attribute hat und viel zu viel weiss und kann. Die ”Methoden” sind auch nicht sinnvoll aufgeteilt und schrecklich benannt, und diese grosse, vorerstellte Ergebnisstruktur ist auch unschön.

Und dann bindest Du anscheinend ausnahmslos alle Namen an das eine Objekt. Was soll das? Irgendein lokales `i` trägt sicher nicht zum Zustand des `sucher`-Objekts bei, im Gegenteil, dieser Unsinn ist wahrscheinlich eine der Problemquellen wenn das von mehr als einem Thread benutzt wird.

Ich würde das alles wegwerfen und anfangen einfache Funktionen zu schreiben die man leicht einzeln Testen kann. Und daraus dann nach und nach ein grösseres Programm zusammen zu bauen.

Zum Beispiel könnte man eine Funktion schreiben die genau eine Webseite auswertet. Nur auswertet — nicht herunter lädt! Und zwar in dem sie die einzelnen Elemente ermittelt die jeweils ein Produkt enthalten. Die Daten aus so einem Element kann man mit einer weiteren Funktion extrahieren die dann für jedes Produkt aufgerufen wird.

Die Funktion zum Auswerten einer Seite kann man dann für jede Seite aufrufen. Jede Funktion sollte dabei ihr Teilergebnis zurück geben und ggf. aus dem von aufgerufenen Unterfunktionen zusammen setzen. Also nicht irgendwo eine grosse Struktur vorinitialisieren, sondern Stück für Stück die Teilergebnisse zu einem Gesamtergebnis zusammen setzen.

Re: python im Internet & HTML

Verfasst: Donnerstag 30. Oktober 2014, 08:06
von Sirius3
@evd: warum sind r, n und i Klassenattribute? Das sind zum einen Laufvariablen zum Initialisieren von Listen, zum anderen Elemente aus der Queue. Laufvariablen sind nie Klassenattribute, weil sie sich nur innerhalb einer Methode sogar nur innerhalb einer Schleife sinnvoll sind. Zum zweiten handelst Du Dir damit bei Deinen Threads Probleme ein, weil sie alle die selben Attribute verwenden, sich also gegenseitig überschreiben, daher das None. In einer threaded Methode dürfen also im Normalfall keine Attribute überschrieben werden! Dann nummerierst Du Attribute durch, was ein deutliches Zeichen dafür ist, dass Du eigentlich eine Liste verwenden willst.
Das vorinitialisieren von Listen ist in Python unüblich, weil man alles dynamisch aufbauen kann. Du führst weitere Attribute außerhalb der __init__-Methode ein. Methoden sollten nicht irgendwie wild irgendwelche Listen verändern. Du weißt doch später nicht mehr, wo was mit welcher Abhängigkeit gemacht wird. Schreib Funktionen, mit definierten Aufgaben, Inputparametern und Rückgabewerten.

Re: python im Internet & HTML

Verfasst: Samstag 1. November 2014, 01:09
von BlackJack
Mal ein etwas übersichtlicherer Ansatz:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import json
import logging

import requests
from concurrent.futures import ThreadPoolExecutor
from lxml import html

logging.basicConfig()
LOG = logging.getLogger('main')
LOG.setLevel(logging.INFO)

RESULT_URL_TEMPLATE = (
    'http://www.amazon.de/s/ref=sr_pg_{0}'
        '?rh=n%3A77195031%2Cp_36%3A200-499%2Cp_n_format_browse-bin%3A180848031'
        '&page={0}'
        '&bbn=77195031'
        '&ie=UTF8'
        '&qid=1395167727'
)


def parse_product(node):
    title_node, artist_node = node.cssselect('h3 a')
    title_span = title_node.find('span')
    buy_button_nodes = node.cssselect('.MusicCartBuyButton a')
    product_image_nodes = node.cssselect('img.productImage')
    if not product_image_nodes:
        product_image_nodes = node.cssselect('img.placeholder')
    return {
        'image_url': product_image_nodes[0].get('src'),
        'url': title_node.get('href'),
        'title': title_span.get('title') or title_span.text,
        'artist': artist_node.text,
        'price': float(
            buy_button_nodes[0].text.rpartition(' ')[2] .replace(',', '.')
        ) if buy_button_nodes else None,
    }


def load_products(url):
    result = {'source': url, 'error': None, 'products': list()}
    response = requests.get(url)
    if response.ok:
        result['products'] = map(
            parse_product,
            html.fromstring(response.content)
                .get_element_by_id('resultsCol')
                .cssselect('div.prod')
        )
    else:
        result['error'] = {
            'status_code': response.status_code,
            'reason': response.reason,
        }
    return result


def load_page(number):
    LOG.info('loading page %d', number)
    result = load_products(RESULT_URL_TEMPLATE.format(number))
    result['page'] = number
    return result


def load_pages(max_workers, max_pages):
    executor = ThreadPoolExecutor(max_workers)
    futures = [
        (i, executor.submit(load_page, i)) for i in xrange(1, max_pages + 1)
    ]
    pages = list()
    for i, future in futures:
        try:
            page = future.result()
        except Exception as error:
            page = {
                'error': str(error),
                'page': i,
            }
        pages.append(page)
    return {
        'pages': pages,
    }


def main():
    pages = load_pages(5, 20)
    print(json.dumps(pages, indent=2))


if __name__ == '__main__':
    main()
Edit: Produktverarbeitung um die Möglichkeit erweitert, dass statt einem Produkbild auch ein Platzhalter vorhanden sein könnte.

Re: python im Internet & HTML

Verfasst: Samstag 1. November 2014, 01:26
von evd
Hallo zusammen

Ich habe es jetzt neu geschrieben, und um einiges übersichtlicher gemacht... (wenn ihr es noch ein mal sehen wollt, gerne, doch wollte ich es nicht machen da es nicht mein größtes Problem ist, und Platzverschwendung wehre und euch vielleicht verkrault XD)

jetzt stehe ich vor 2 neuen Problemen... immer in Bewegung bleiben XD


1) und zwar habe ich bei den Bildern, bei denen ich die URL haben will 2 verschiedene Möglichkeiten...
1.div.imageBox img.productImage.cfMarker - ein bestimmtes Bild
2. div.imageBox img.placeholder.cfMarker - unbekanntes Bild
kann ich da irgendwie nur bei div.imageBox bei seinen Nachfahren per "element.get("src") den wert herausbekommen?
bei mir bekomme ich da immer None

Code: Alles auswählen

        self.links = self.seite.cssselect('div.imageBox img.productImage.cfMarker')
        for element in self.links:
            self.r[4].append(element.get("src")
2)es gibt Alben die man Kaufen kann, und welche die man vorbestellen kann. Beide haben den Preis unter dem Button eingebunden. als a.a-button-text
aber wenn ich danach suche bekommen ich immer nur die, welche man kaufen kann, und solche bei denen es nicht möglich ist, dort bekomme ich gar keinen wert... verstehe ich nicht, ist doch unter dem gleichen tag (oder so)...

Code: Alles auswählen

        self.links = self.seite.cssselect('a.a-button-text')
        self.n=0
        for element in self.links:
            if self.n<24:    
                self.r[2].append(element.text[21:len(element.text)])
                self.n=self.n+1
# Es gibt auch noch mehr als die 24 preise, die restlichen will ich aber nicht, deswegen alsse ich n hoch zählen

Re: python im Internet & HTML

Verfasst: Samstag 1. November 2014, 11:02
von BlackJack
@evd: Für mich sieht das so aus als wenn die Aufteilung immer noch nicht stimmt, weder beim Code noch bei den Daten.

Du durchsuchst die *Seite* nach Bildern und Preisen — das ist falsch. Du solltest die *Seite* nur nach *Produkten* durchsuchen. Und dann jedes einzelne Produkt nach dem *einen* Bild und dem *einen* Preis. Dann bekommst Du nicht mehr Preise als Produkte und läufst auch nicht Gefahr das sich irgendwas verschiebt und dadurch falsche Daten gruppiert werden. Stell Dir mal vor die Packen irgendwann mal ein Sonderangebot in der Webseite *vor* die Produkte und das hat so einen Preis-Button. Das kannst Du mit Deinem Ansatz gar nicht erkennen und dadurch würden sich alle Preise bei Dir verschieben und die Daten stimmen nicht mehr.

Zusätzliche habe ich den Eindruck das Du die Daten auch immer noch nicht ordentlich zusammenfasst wenn ich dieses `self.r` mit den magischen Indexwerten und dem `append()` sehe. Das sieht so aus als wenn Du die Einzeldaten zu einem Produkt immer noch auf mehrere parallele Listen verteilst.

Edit: Habe meinen Code weiter oben mal um die Möglichkeit von fehlenden Produktbildern erweitert.