Hallo zusammen,
ich suche nach einer Möglichkeit, wie ich den Download von sehr vielen + ständig neu hinzukommenden Dateien, effektiv bewerkstelligen kann. Derzeit habe ich es so implementiert, dass eine Linkliste erstellt wird und danach dann beim abarbeiten geprüft wird, ob es den Pfad schon gibt -> wenn nicht, downloaden. Mir wäre es aber lieber, wenn ich nicht immer wieder alle links holen müsste.
Konkret geht es um diese Webseitdaten: https://gentool.net/data/zh/
Hat jemand einen Lösungsvorschlag/Hinweis/Framework wie ich das angehen könnte?
LG Leex
Effektiv viele Dateien von Webseite herunterladen
Ein klassischer Ansatz dafür (unter Unix/Linux) ist wget mit den richtigen Parametern + cronjob/systemd-timer. Unter Windows kann man sich evtl. mal https://www.httrack.com/ oder vergleichbare Tools anschauen. Da braucht man kein Python oder sonst irgendeine Programmiersprache für. Geht natürlich schon, ist aber größerer Aufwand. Interessant wird das vor allem dann, wenn man irgendeine spezielle "Nachverarbeitungs-Logik" braucht.
Danke für deine Antwort. Läuft alles unter Linux und wird auch danach noch mit python-skripten weiter verarbeitet und in elastic indexiert.
wget kenne ich natürlich, mir ist aber nicht klar wie ich hier die Anforderung umsetzten kann, dass er eben nicht alle Seiten nochmal durchgeht, sondern das er sich merkt wo er aufgehört hat. Das ist ja mein Problem, nicht das downloaden allgemein (das hab ich ja bereits).
Hast du evtl. ein Beispiel?
wget kenne ich natürlich, mir ist aber nicht klar wie ich hier die Anforderung umsetzten kann, dass er eben nicht alle Seiten nochmal durchgeht, sondern das er sich merkt wo er aufgehört hat. Das ist ja mein Problem, nicht das downloaden allgemein (das hab ich ja bereits).
Hast du evtl. ein Beispiel?
Hier mal noch mein aktueller Code, der noch eine Einschränkung auf den Monat hat, sodass ich zumindest nur immer den aktuellen Monat neu crawle:
Code: Alles auswählen
import os
import pathlib
import re
import time
import urllib.request
from datetime import datetime
from bs4 import BeautifulSoup
from pysitemap import crawler
start = f'https://www.gentool.net/data/zh/'
download_path = "./downloads"
def getLinks(start_url):
print(f"Start-URL: {start_url}")
path = pathlib.PurePath(start_url)
print(path.parts[(len(path.parts) - 1)])
str_path = path.parts[(len(path.parts) - 1)]
html_page = urllib.request.urlopen(start_url)
soup = BeautifulSoup(html_page, "lxml")
links = []
for link in soup.findAll('a'):
regex = re.compile(r'\?|data')
if not regex.search(link.get('href')):
print(f"Link: {link.get('href')}")
if not str_path in "zh":
create_path = f"{download_path}/{str_path}/{link.get('href')}"
print(f"Create Path: {create_path}")
else:
create_path = f"{download_path}/{link.get('href')}"
print("no path")
links.append(link.get('href'))
if not os.path.exists(create_path):
os.makedirs(create_path)
return links
def cleanup_links(filename):
with open(filename, "r+") as f:
d = f.readlines()
f.seek(0)
for idx, i in enumerate(d):
if "txt" in i:
print(idx, i)
f.write(i)
f.truncate()
if os.stat(filename).st_size == 0:
print(" Removing ", filename)
os.remove(filename)
if __name__ == '__main__':
while True:
months = getLinks(start)
for month in months:
if month == "2022_11_November/":
filename = f'{month.replace("/", "")}.txt'
print(start + month)
# getLinks(start + month)
crawler(start + month, out_file=filename, exclude_urls=[".rep", ".jpg", "?"], out_format="txt")
cleanup_links("2022_11_November.txt")
print(f"Sleeping 30min {datetime.now()}")
time.sleep(900)
So ganz ist mir nicht klar, was du dann noch benötigst und was dein Skript (von dem für mich aus dem Eingangspost nicht klar war, dass es existiert; das klang eher manuell) im Detail tut. Wenn es darum geht, HTTP Requests einzusparen und aus der Struktur, wie die heruntergeladenen Dateien lokal abgelegt werden der ursprüngliche Remote-Pfad/Link nicht mehr hervorgeht, kannst du dir diesen doch einfach nach dem erfolgreichen Herunterladen einer Datei in z.B. einem set merken. Das serialisierst du bei Programmende als z.B. JSON, initialisierst damit das set beim nächsten Durchlauf erneut und überspringst die bereits besuchten Links. Zumindest die Indices musst du aber stets neu abfragen. Falls sich auch an bereits heruntergeladenen Dateien etwas ändern kann, wird es etwas komplizierter und geht nicht ohne zumindest einen HEAD-Request.
EDIT: Das zwischenzeitlich gepostete Skript habe ich noch nicht angesehen.
EDIT: Das zwischenzeitlich gepostete Skript habe ich noch nicht angesehen.
Zuletzt geändert von nezzcarth am Freitag 2. Dezember 2022, 22:40, insgesamt 1-mal geändert.
Danke, werde das mit dem "set" mal versuchen/recherchieren.
Das Skript liest eigentlich nur alle Links aus und speichert sie in einer Textdatei (2022_11_November.txt). Mit einem zweiten Skript gehe ich die Links dann durch und lade alles herunter, wenn es nicht schon auf der Festplatte (Pfad) vorhanden ist.
Bestehende Links ändern sich nicht mehr.
Das Skript liest eigentlich nur alle Links aus und speichert sie in einer Textdatei (2022_11_November.txt). Mit einem zweiten Skript gehe ich die Links dann durch und lade alles herunter, wenn es nicht schon auf der Festplatte (Pfad) vorhanden ist.
Bestehende Links ändern sich nicht mehr.
Du hast eine seltsame Verwendung von pathlib. Für URLs ist es nicht gedacht, aber dort, wo es sinnvoll wäre, benutzt Du Format-Strings um Pfade zusammenzufummeln, und os.path um Verzeichnisse zu erzeugen.
In `cleanup_links` benutzt Du fast ausschließlich einbuchstabige nichtssagende Variablennamen, um das Lesen besonders schwierig zu machen. Der Filemode r+ wird auch fast nie gebraucht, wie hier, wo es viel klarer und einfacher wäre, einfach eine neue Datei zu erzeugen. Der in-Vergleich ist etwas zu optimistisch.
In `cleanup_links` benutzt Du fast ausschließlich einbuchstabige nichtssagende Variablennamen, um das Lesen besonders schwierig zu machen. Der Filemode r+ wird auch fast nie gebraucht, wie hier, wo es viel klarer und einfacher wäre, einfach eine neue Datei zu erzeugen. Der in-Vergleich ist etwas zu optimistisch.
Code: Alles auswählen
def cleanup_links(filename):
with open(filename, encoding="ascii") as links:
cleaned_links = [
link for link in links
if "txt" in link
]
if cleaned_links:
with open(filename, "w", encoding="ascii") as links:
links.writelines(cleaned_links)
else:
os.remove(filename)
Danke für das Feedback. Ist ein Freizeitprojekt und habe auch lange daran nichts gemacht und bin gerade jetzt dabei das wieder anzugehen und zu optimieren / weiter zu lernen, weshalb ich auch auf das Forum gestoßen bin. Werde versuchen das umsetzten / ändern ). Bin über jeden Tipp/Hinweis/Lösungsvorschläge/Denkanstöße dankbar. Erwarte keine fertigen Lösungen.