@Strawk: Ich würde den
Style Guide for Python Code ans Herz legen. Die Namensschreibweise(n) hatte ich ja schon einmal angesprochen. Die Importe nocht nicht: die sollten nicht alle in einer Anweisung zusammengefasst sein und sind üblicherweise nach Standardbibliothek und Modulen/Paketen von Drittanbietern getrennt.
Die Kommentare hatte ich auch schon erwähnt. Weg mit den nutzlosen, redundanten. Die bringen dem Leser keinen Mehrwert, bergen aber die Gefahr das entweder jetzt oder wenn der Code mal geändert wird, Kommentar und Code nicht mehr zusammen passen und der Leser dann nicht weiss wer recht hat, Kommentar oder Code.
Vom Sprachgefühl würde ich sagen bei `# gain all html-code` ist das `gain` falsch und zwischen html und code gehört kein Bindestrich.
Die einzigen Kommentarzeilen die ein bisschen Sinn machen sind die beim `i` — aber auch nur weil man da erklären muss wofür `i` überhaupt steht. Wenn man hier einen erklärenden Namen verwendet, können auch hier die Kommentare weg.
Daten und Code sollten sich nicht wiederholen. Wenn man etwas Ändern will, zum Beispiel das Verzeichnis in dem die Beiträge gespeichert werden, die Basis-URL des Forums, oder der Parser der für das HTML verwendet werden soll, muss man das an jeder Stelle im Code ändern, mit der Gefahr das man etwas übersieht, oder nicht jede Änderung äquivalent macht. Bei Daten kann man Konstanten definieren, und bei Code Schleifen oder Funktionen schreiben um Wiederholungen zu vermeiden.
Wegwerfen des ersten Zeichens der Links und formatieren in eine Zeichenkette ist fragiler als `urlparse.urljoin()` zu verwenden.
`os.path.join()` ist dazu da plattformunabhängig Pfadteile zusammenzusetzen — das klappt aber nicht wenn man dann doch wieder plattformunabhängige Pfadtrenner hart in die Daten schreibt.
Dateien öffnet man am besten zusammen mit der ``with``-Anweisung um sicherzustellen das die Datei beim verlassen des ``with``-Blocks geschlossen wird, egal warum der verlassen wird.
Wenn man die Datei nicht im Binärmodus öffnet, braucht man sich nicht in einem Extraschritt selbst um die Kodierung der Daten zu kümmern.
Die erzeugten Dateinamen sind ungünstig wenn man sie alphabetisch sortiert, was viele Werkzeuge machen, denn dann sind sie nicht in der richtigen numerischen Reihenfolge. Das kann man umgehen, in dem man die Zahlen links mit 0en auffüllt. Besser wäre IMHO aber wie schon in einem vorherigen Beitrag geschrieben, die Beitrags-ID aus dem Forum zu verwenden, denn die ist Eindeutig und kann nicht mehr geändert werden, oder zumindest ist das wesentlich unwahrscheinlicher als die laufende Nummer (wenn Beiträge gelöscht werden) oder der Beitragstitel der a) nicht eindeutig ist und b) geändert werden kann.
Last but not least: Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steckt üblicherweise in einer Funktion die `main()` heisst. Das verringert die Gefahr das Funktionen undurchsichtig über globalen Zustand zusammenhängen, und man kann das ganze so schreiben, das man das Modul importieren kann, ohne das gleich das Programm abläuft. So das man einzelne Funktionen manuell, zum Beispiel in einer Python-Shell, oder automatisiert testen kann, wiederverwenden kann. Ausserdem erwarten diverse Werkzeuge, zum Beispiel Sphinx, das man Module ohne Seiteneffekte importieren kann.
Ungetestet:
Code: Alles auswählen
import os
from urlparse import urljoin
import bs4
import requests
FORUM_BASE_URL = 'https://www.phpbb.de/community/'
MESSAGES_PATH = 'forum_messages'
def get_soup(url):
return bs4.BeautifulSoup(requests.get(url).content, 'html.parser')
def main():
os.makedirs(MESSAGES_PATH, exist_ok=True)
message_count = 0
soup = get_soup(urljoin(FORUM_BASE_URL, 'viewforum.php?f=145'))
for topic in soup.select('a.topictitle'):
soup = get_soup(urljoin(FORUM_BASE_URL, topic['href']))
for message in soup.select('div.content'):
message_count += 1
#
# TODO Use post id in or as filename for a consistent
# mapping between filename and forum post.
#
filename = os.path.join(
MESSAGES_PATH, '{:06d}.html'.format(message_count)
)
with open(filename, 'w', encoding='utf-8') as message_file:
message_file.write(str(message))
if __name__ == '__main__':
main()