snafu1
Anmeldungsdatum: 5. September 2007
Beiträge: 2123
Wohnort: Gelsenkirchen
|
Schlechter Stil allerdings ist das Verkürzen von Tracebacks zu relativ allgemeinen Fehlermeldungen. Wenn man den Traceback für den Benutzer zu kryptisch findet, dann sollte man das Abfangen besser in die main()-Funktion legen. So wie es jetzt ist, wird das Debugging auf jeden Fall erschwert. Denn jemand, der die betreffende Funktion zum Testen mal isoliert aufruft, erhält das gleiche Blabla wie der Endnutzer, hat dann also keinen zusätzlichen Erkenntnisgewinn. 😉 Und auch dass der CSV-Writer sozusagen im luftleeren Raum herumschwebt (nur am Ende auf Modulebene im if-Block definiert wird), in der Funktion zur Abarbeitung aber wie selbstverständlich erwartet wird, ist kein allzu guter Stil. Falls man den gerne durch den Aufrufer erstellen lassen möchte, dann wäre der richtige Weg, den als zusätzliches Funktionsargument entgegen zu nehmen. So ist es halt verwirrend und fehleranfällig. Allein schon wenn das if gar nicht durchlaufen wird (dann nämlich, wenn die Nutzung als Import und nicht als Skript erfolgt), kracht es, weil der Writer dann nicht definiert ist. Dies nur als zwei Anmerkungen, was mir halt aufgefallen ist. Ansonsten läuft der Code ja wohl ganz gut.
|
UlfZibis
(Themenstarter)
Anmeldungsdatum: 13. Juli 2011
Beiträge: 3035
Wohnort: Köln
|
Hallo seahawk1986, leider funktioniert Dein Programm nicht mehr. Deshalb habe ich es umgeschrieben: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 | #!/usr/bin/env python3
import html
import requests
import io, os
import sys
import time, random
from typing import Optional
from bs4 import BeautifulSoup
from urllib.parse import *
def load_url(url: str) -> Optional[BeautifulSoup]:
print(f'schema: {urlsplit(url).scheme}', file=sys.stderr)
print(f'GET {url}', file=sys.stderr)
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
r = requests.get(url, headers)
try:
r.raise_for_status()
except requests.exceptions.HTTPError as err:
print(f'request for {url} failed\n{err}', file=sys.stderr)
else:
file_name = urlsplit(url).path.replace('/', "./", 1) + ".html"
# ~ file_name = urlsplit(url).path.partition('/')[-1] + ".html"
# ~ dir_name = file_name.rpartition('/')[0]
# ~ print(f'file_name: {file_name}, dir_name: {dir_name}', file=sys.stderr)
os.makedirs(file_name.rpartition('/')[0], exist_ok=True)
with io.open(file_name, "wb") as file:
file.write(r.content)
return BeautifulSoup(r.content, "html.parser")
def process_page(url: str) -> Optional[str]:
if (soup := load_url(url)):
try:
entry_counter = soup.find("p", class_="mod-LoadMore--text")
start = int(entry_counter.find("span", attrs={"id": "loadMoreStartIndex"}).text)
end = int(entry_counter.find("span", attrs={"id": "loadMoreGezeigteAnzahl"}).text)
all = int(entry_counter.find("span", attrs={"id": "loadMoreGesamtzahl"}).text)
except:
print(f'Page contains unknown amount of entries.', file=sys.stderr)
else:
print(f'Page contains {start} - {end} of {all} entries.', file=sys.stderr)
time.sleep(2 + random.random() * 2) # simulate manual page request
if (next_page_element := soup.find("a", class_="gs_paginierung__sprungmarke--vor", attrs={"title": "Weiter"})):
# ~ print(f"next_page_element:\n{next_page_element}", file=sys.stderr)
return next_page_element.get("href")
try:
page_nr = int(url[(page_nr_index := url.rindex("/Seite-") + len("/Seite-"))])
if (start and end and ((end / (end - start + 1)) == page_nr)):
if (all and (end < all)):
print(f"next page_nr({url}): {page_nr + 1}", file=sys.stderr)
return url[:page_nr_index] + str(page_nr + 1)
else:
return None
else:
print(f"{url} does not really have content of page {page_nr}", file=sys.stderr)
return None
except ValueError:
print(f"next_page({url}) not found", file=sys.stderr)
if (LoadMore_element := soup.find("a", class_="mod-LoadMore--button", attrs={"title": "Mehr Anzeigen"})):
# ~ print(f"LoadMore_element:\n{LoadMore_element}", file=sys.stderr)
return LoadMore_element.get("href")
return None
if __name__ == "__main__":
for url in sys.argv[1:]:
while url:
url = process_page(url)
|
Es soll nun erst mal die Seiten nur speichern ohne den Inhalt zu extrahieren. Außerdem sollten nun 2 Aufrufvarianten möglich sein: | ./GelbeSeiten_laden.py https://www.gelbeseiten.de/Branchen/Arzt/Kiel
./GelbeSeiten_laden.py https://www.gelbeseiten.de/Branchen/Arzt/Kiel/Seite-1
|
Beide funktionieren leider nicht. Manuell im Browser funktionieren beide Varianten. Hat Jemand eine Idee, was ich noch versuchen kann? Es funktioniert nur noch der mühsame Weg, d.h. die Seiten (.../Seite-xy) einzeln mit dem Browser aufrufen und manuell abspeichern und mit folgendem Programm den Inhalt extrahieren: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 | #!/usr/bin/env python3
import csv
import html
import requests
import io, os
import sys
from typing import Optional
from bs4 import BeautifulSoup
# ~ from urllib.parse import *
def load_file(url: str) -> Optional[io.BufferedIOBase]:
try:
with io.open(url, 'rb') as file:
print(f'READ {url}', file=sys.stderr)
return file.read()
except FileNotFoundError:
print(f"file {url} not found", file=sys.stderr)
def get_title(article: BeautifulSoup) -> str:
try:
return article.find("h2", attrs={"data-wipe-name": "Titel"}).text
except AttributeError as err: ### ToDo propagate exception
print(f'{err} | get_title({article.get("data-teilnehmerid")})', file=sys.stderr) # returns None on fail
return article.get("data-teilnehmerid")
def get_web(article: BeautifulSoup) -> str:
try:
return article.find("a", class_="contains-icon-homepage").get("href") ### ToDo: mit , ""
except AttributeError as err: ### ToDo propagate exception
# ~ print(f'{err} | get_web({get_title(article)})', file=sys.stderr)
return None
def get_email(article: BeautifulSoup) -> str:
try:
email = article.find("a", class_="contains-icon-email").get("href")
return email.partition(':')[-1].partition('?')[0] if email and email.startswith("mailto:") else email
except AttributeError as err: ### ToDo propagate exception
# ~ print(f'{err} | get_email({get_title(article)})', file=sys.stderr)
return None
def process_page(soup: BeautifulSoup):
try:
entry_counter = soup.find("p", class_="mod-LoadMore--text")
start = int(entry_counter.find("span", attrs={"id": "loadMoreStartIndex"}).text)
end = int(entry_counter.find("span", attrs={"id": "loadMoreGezeigteAnzahl"}).text)
all = int(entry_counter.find("span", attrs={"id": "loadMoreGesamtzahl"}).text)
except:
print(f'Page contains unknown amount of entries.', file=sys.stderr)
else:
print(f'Page contains {start} - {end} of {all} entries.', file=sys.stderr)
for article in soup.select("div.mod-TrefferListe > article.mod-Treffer"):
try:
name = title if (title := get_title(article)) else ""
if ((email := get_email(article)) and '@' in email):
print(f"{name} <{email}>", file=sys.stdout)
else:
if (email and "#email-schreiben" in email):
print(f"{name} ––– Kontaktformular: {email}", file=sys.stdout)
print(f"No email({name}), but CONTACT FORM: {email}", file=sys.stderr)
if (web := get_web(article)):
dom = web.split("//")[-1].partition("/")[0].lstrip("w.")
# ~ dom = (h if (h := urlsplit(web, "http").hostname) else web.partition("/")[0]).lstrip("w.")
print(f"{name} <info@{dom}>", file=sys.stdout)
# ~ print(f"{name} <mail@{dom}>", file=sys.stdout)
# ~ print(f"{name} <post@{dom}>", file=sys.stdout)
# ~ print(f"{name} <kontakt@{dom}>", file=sys.stdout)
# ~ print(f"{name} <praxis@{dom}>", file=sys.stdout)
# ~ print(f"No email({name}), but domain GUESSED from: {web} -> {dom}", file=sys.stderr)
# ~ elif (not(email and "#email-schreiben" in email)):
# ~ print(f"No email({name}), BUT: {email} and {web}", file=sys.stderr)
except Exception as err:
print(f"{err} | process_page({get_title(article)})", file=sys.stderr)
if __name__ == "__main__":
for url in sys.argv[1:]:
while (file := load_file(url)):
process_page(BeautifulSoup(file, "html.parser"))
try:
page_nr = url.rindex("/Seite-") + len("/Seite-")
extension = url.rindex(".")
next_page_nr = int(url[page_nr:extension]) + 1
# ~ print(f"next_page_nr({url}): {next_page_nr}", file=sys.stderr)
url = url[:page_nr] + str(next_page_nr) + url[extension:]
except ValueError:
print(f"next_page after {url} not estimable", file=sys.stderr)
break
|
Bei der Gelegenheit würde ich mich auch freuen über Feedback zum Stil und evtle. Verbesserungsvorschläge.
|