Seite 1 von 1
Websites besuchen
Verfasst: Samstag 17. August 2013, 10:56
von MarcelF6
Hallo miteinander
Ich stehe vor folgendem Problem: Mein Python-Programm muss eine Reihe Websites nacheinander besuchen, die sich jeweils in der URL nur in Ziffern unterscheiden. Der Start liegt bei:
http://www.test.xyz/0000?action=source und die letzte zu besuchende Seite ist (beispielsweise)
http://www.test.xyz/9999?action=source.
Ursprünglich wollte ich das Problem via Integers lösen, nur: 0000 wird zu einer "simplen" 0, d.h. so funktioniert das ganze nicht.
Hat jemand eine Idee, wie man das hinbekommen könnte?
Besten Dank für jeden Input.
Marcel
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 11:02
von mcdwerner
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 12:26
von Dami123
Code: Alles auswählen
if __name__=="__main__":
url = ("http://www.test.xyz/", "?action=source")
for i in range(9999):
if len(str(i)) == 1:
i = "000"+str(i)
elif len(str(i)) == 2:
i = "00"+str(i)
elif len(str(i)) == 3:
i = "0"+str(i)
elif len(str(i)) == 4:
i = str(i)
name = "%s%s%s" % (url[0], i, url[1])
print name
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 12:37
von BlackJack
@Dami123: Das ist wohl so das komplizierteste was machen machen kann (bevor es absurd wird). mcdwerner hat doch schon Zeichenkettenformatierung vorgeschlagen.
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 12:47
von MarcelF6
mcdwerner, danke vielmals für den Tipp!
Ich habe eine einfache Funktion erstellen können, die genau nun genau das macht, was ich wollte
Dami123, danke für das Beispiel. In der Zwischenzeit habe ich halt schon ein eigenes erstellt, aber es ist immer schön zu wissen, dass einem hier geholfen wird
Eine andere Frage hätte ich noch, sie betrifft BeautifulSoup:
BS4 ordnet die Attribute im XML automatisch alphabetisch. Gibt es eine Möglichkeit, das zu unterdrücken? Zudem fügt BS4 Endknoten (</table>) automatisch an vorherige Elemente an, obwohl ich eigentlich lieber einen Zeilenumbruch hätte.
Klar, das sind alles optische Details, die python selbst nicht stören. Aber trotzdem wolle ich die Frage hier kurz stellen

Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 13:01
von Dami123
@BlackJack
Ja das stimmt

Habs aus nem alten Script kopiert.
Das funktioniert um einiges besser.
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 13:28
von Hyperion
Dami123 hat geschrieben:@BlackJack
Ja das stimmt

Habs aus nem alten Script kopiert.
Hui... das hättest Du Dir überlegen sollen... das ist glatt etwas für
The Daily WTF
Bitte benutze doch in Zukunft für Python-Code die Python-Code-Tags [ python ] Code [ /python ] oder allgemein (für viele andere Sprachen) [ code=python ] Code [ /code ] (Ohne die Leerzeichen).
MarcelF6 hat geschrieben:
BS4 ordnet die Attribute im XML automatisch alphabetisch. Gibt es eine Möglichkeit, das zu unterdrücken?
Da die Reihenfolge von Attributen in XML keiner Semantik unterliegt, wage ich das zu bezweifeln. Intern wird BS das auch sicher nicht ordnen, sondern erst bei der Ausgabe. Wenn BS API da einen Hook anbietet, bei dem man sich in die Formatierung einhängen kann, dann kannst Du das sicher ändern, wenn nein, dann nicht, außer Du schreibst Deine eigene Serialisierungs-Engine.
Wobei dann die Frage ist, in welcher Reihenfolge Du sie haben willst? Ich könnte mir vorstellen, dass BS intern ein Dictionary für die Attribute verwendet; dann ist die ursprüngliche Reihenfolge eh futsch

Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 13:59
von MarcelF6
Ok, besten Dank für die Infos!
Das hab' ich mir gedacht - da sich der Aufwand in diesem Fall nicht lohnen würde, lass ich es, wie es ist

Danke euch für die Inputs

Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 16:56
von Dami123
@Hyperion
So schlimm schien mir die Lösung nicht, als ich sie programmiert hab

Obs ein ein Artikel wert ist..
Mach ich.
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 19:12
von MarcelF6
Ich habe doch noch eine Frage: Wie bekommt man (im HTML-File) inhaltsleere Tags gelöscht?
Beispiel: " <b></b> " soll einfach gelöscht werden.
Ich habe versucht, das html-File zu öffnen und dann nach "<b></b>" zu suchen und bei einem Fund es via re.sub() zu ignorieren.
Allerdings ohne Erfolg. Hätte jemand einen Vorschlag?
Re: Websites besuchen
Verfasst: Samstag 17. August 2013, 19:57
von BlackJack
@MarcelF6: Du benutzt doch schon BeautifulSoup4 — also einfach die entsprechenden Elemente suchen und mit der `extract()`-Methode entfernen. Wobei man aufpassen muss was man entfernt, denn ein leeres `<a>` mit einem `id`-Attribut sollte man beispielsweise besser nicht entfernen.
Re: Websites besuchen
Verfasst: Sonntag 18. August 2013, 19:51
von MarcelF6
Danke für den Hinweis.
Ich habe momentan diesen Code, und bin eigentlich der Meinung, dass es so klappen müsste. Allerdings habe ich im output-File immernoch die inhaltsleeren Tags <b></b>. Woran könnte das liegen bzw. was ist wie zu ändern?
Danke für alle Inputs
Code: Alles auswählen
output = codecs.open("test.html", "a", "utf-8")
for i in range(0, 10):
nr = add_nulls(i, 4)
f = urllib2.urlopen('http://blubb.xyz')
html = f.read()
f.close()
soup = BeautifulSoup(html)
txt = ""
for text in soup.find_all("table", {'class': 'main'}):
txt += str(text)
txt = str(txt)
text = "\n".join(re.sub(r'\[:[\/]?T.*?:\]', '', el) for el in txt.splitlines())
bs = BeautifulSoup(text)
empty_tags = bs.find_all(lambda tag: tag.name == 'b' and tag.find(True) is None and (tag.string is None or tag.string.strip()==""))
[empty_tag.extract() for empty_tag in empty_tags]
output.write(text.decode("utf-8"))
Re: Websites besuchen
Verfasst: Sonntag 18. August 2013, 21:41
von BlackJack
@MarcelF6: Argh, ist das eine gruselige Mischung aus ordentlicher Verarbeitung eines Objektbaums und Zeichenkettenmurks. Und daran liegt es dann letztendlich auch. Du veränderst den Objektbaum, speicherst dann aber die unveränderte Zeichenkette aus welcher der Objektbaum erzeugt wurde.
Und „list comprehensions” sind zum Erzeugen von Listen da die man auch benutzen möchte, und nicht um sinnfreie Listen zu erzeugen die nicht verwendet werden. Das ist keine schicke Syntax um eine ``for``-Schleife in eine Zeile zu schreiben. Wobei man *das* auch ohne „list comprehension” machen könnte, aber aus Gründen der Lesbarkeit nicht sollte.
Re: Websites besuchen
Verfasst: Montag 19. August 2013, 00:54
von MarcelF6
Hm ok, ich sehe was du meinst.
Und genau bei der Speicherung der modifizierten Struktur habe ich Mühe: Wie kann man die modifizierte Struktur speichern?
Würdest du eine zusätzliche Variable einführen (=die modifizierte Struktur), und diese via output.write in das File speichern?
Danke für die Tipps!
Re: Websites besuchen
Verfasst: Montag 19. August 2013, 01:11
von BlackJack
@MarcelF6: Du hast die Struktur doch schon an einen Namen gebunden. Sonst hättest Du sie ja nicht verändern können.
Edit: Was soll denn eigentlich ``txt = str(txt)`` bewirken? Und wieso benutzt Du `codec.open()` wenn Du `str`-Werte speichern willst, die Du erst mit der gleichen Kodierung dekodierst, die das Dateiobjekt zum schreiben verwendet?
Re: Websites besuchen
Verfasst: Montag 19. August 2013, 01:32
von MarcelF6
Ah dumm; klar. Hab den Fehler entdeckt.
txt = str(txt) verwende ich, damit ich nachher die splitlines()-Funktion anwenden kann.
Den Punkt zur Codierung verstehe ich nicht ganz...
Ich habs nun so:
Code: Alles auswählen
text = BeautifulSoup(text)
empty_tags = text.find_all(lambda tag: tag.name == 'b' and tag.find(True) is None and (tag.string is None or tag.string.strip()==""))
[empty_tag.extract() for empty_tag in empty_tags]
output.write(text.decode("utf-8"))
Was mich noch wunder nimmt: Jetzt wird die Ausgabe so gespeichert, dass sie "schön" zu lesen ist, d.h. mit Einzügen, sodass verschiedene Tags leicht auseinander gehalten werden können. Gibt es eine Möglichkeit, die Ausgabe ohne diese Einzüge zu speichern?
Re: Websites besuchen
Verfasst: Montag 19. August 2013, 07:42
von BlackJack
@MarcelF6: Wieso solltest Du ohne ``txt = str(txt)`` die `splitlines()`-Methode denn *nicht* anwenden können? Und warum wendest Du die überhaupt an? Das ist völlig unnötig die Zeichenkette an Zeilenenden zu zerlegen, nur um sie nach dem ersetzen in den einzelnen Zeilen wieder mit Zeilenenden zusammen zu setzen.
Deine Lösung bindet jetzt den Namen `text` mal an Zeichenketten und mal an einen Objektbaum. Das ist verwirrend. Schon für erfahrene Programmierer, aber speziell auch für Dich, wo Du anscheinend sowieso schon unsicher bist was die Typen von Werten angeht.
Die falsche Verwendung von einer „list comprehension” hast Du immer noch.
Das Du Kodierungen nicht verstehst, sieht man am Quelltext. Du machst das unnötig umständlich und verwirrend. Du willst anscheinend UTF-8 als Zielkodierung. `str()` auf die `bs4`-Objekte ergibt UTF-8 kodierte Zeichenketten. Also genau das was Du haben willst. Aber Du dekodierst die mit UTF-8 in `unicode`-Objekte um sie einem `codecs`-Dateiobjekt zu übergeben, was die `unicode`-Objekte gleich wieder mit UTF-8 in Bytes umwandelt. Also dass was Du gerade vorher schon mal hattest. Der Schritt ist also völlig unnötig.
Genau wie Du Dir klar machen solltest welcher (Teil)ausdruck welchen Datentyp erzeugt, und damit welche Operationen möglich sind, solltest Du insbesondere bei `str` und `unicode` wissen welches davon vorliegt und bei `str` in welcher Kodierung.
Das die Ausgabe „schön” ist, liegt daran, dass die Eingabe schon „schön” ist. Wenn es kompakter sein soll, müsstest Du Textelemente die nur „whitespace” enthalten und direkt vor oder nach „block level”-Elementen (ausser <pre>) stehen, entfernen.