python im Internet & HTML
-
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.
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
das Resultat ist jetzt
wie kann ich da jetzt den Namen (hier P!nk) extrahieren ...
Die URL bekomme ich ja mit
also ich könnte natürlich den String bearbeiten ...
aber das ist halt keine so schöne Lösung ...
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]))Code: Alles auswählen
b'<a href="http://www.amazon.de/Greatest-Hits-So-Far-Explicit/dp/artist-redirect/B00F4122W4">P!nk</a>'Die URL bekomme ich ja mit
Code: Alles auswählen
link[i].get("href")aber das ist halt keine so schöne Lösung ...
-
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.
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.
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
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?
... 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")was für ein encoder soll ich denn verwenden?
-
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.
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.
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:
(Programmcode siehe oben)
bekomme ich als Ergebnis dieses hier:
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()
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"))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)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()
-
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.
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.
So, ich habe es soweit...
nur noch ein Problem stellt sich mir noch im punkto Internet...
wenn ich eine Seite herunterlade
z.b.:
am Anfang geht es, doch am ende bekomme ich einen Fehler.
Es kann die Verbindung nicht zu amazon aufbauen...
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?
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")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?
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
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
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
@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?
Was willst Du erreichen? Was kommt raus, was erwartest Du?
-
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.
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`?
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.
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:
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?
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
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
Ende3) 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)und ihr mit weiterhelft (vor allem bei dem Punkt 2 und 1)
Mit freundlichen Grüßen
EvD
-
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.
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.
@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.
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.
-
BlackJack
Mal ein etwas übersichtlicherer Ansatz:
Edit: Produktverarbeitung um die Möglichkeit erweitert, dass statt einem Produkbild auch ein Platzhalter vorhanden sein könnte.
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()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
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)...
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")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-
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.
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.
