Sportski objekti: API + Leaflet map page + address enrichment
DB: pgz_sport.sportski_objekti (103 objekti, 103 s geo, 60 s adresom, 31 tip) API: - /api/v2/sportski-objekti (filter: tip, grad, sport, q) - /api/v2/sportski-objekti/meta (tipovi, gradovi, sportovi, ukupno) Frontend: - /static/objekti.html — Leaflet (OpenStreetMap) interactive map - 3 dropdown filter (tip, grad, sport) + search - Side panel s listom + map markers s ikonama (🏟️⚽🏊⛵🎿🎳⛸️🎯🥌🏃) - Popup: naziv, tip, kapacitet, adresa, upravitelj, izgradeno, sportovi, web link, Google Maps link - /objekti, /sport/objekti, /sport/api/v2/sportski-objekti routes Sidebar app.html: +Sportski objekti link Background: scripts/objekti_enrich_address.py (Nominatim reverse-geocode 60 objekata bez adrese)
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""UNIRI akademski repozitorij + znanstveni radovi."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
ACADEMIC = {
|
||||
"uniri_repozitorij": ["https://repozitorij.uniri.hr/"],
|
||||
"portal_znanstveni": ["https://portal.uniri.hr/"],
|
||||
"hrčak_uniri": ["https://hrcak.srce.hr/"],
|
||||
"pfri_radovi": ["https://repository.pfri.uniri.hr/"],
|
||||
"medri_radovi": ["https://medri.uniri.hr/znanstveni-radovi/"],
|
||||
"tfr_radovi": ["https://www.riteh.uniri.hr/"],
|
||||
"ffri_radovi": ["https://www.ffri.uniri.hr/znanstveni-radovi/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=15):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=20)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 300: continue
|
||||
ff = []
|
||||
if title and len(title) > 15:
|
||||
ff.append({"fact": f"[Academic] {name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 900):
|
||||
if len(c) > 150:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="akademski_pgz", confidence=0.90)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 40:
|
||||
queue.append(link)
|
||||
time.sleep(0.7)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in ACADEMIC.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=12)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"academic_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr%bin/env python3
|
||||
"""Lokalne firme i obrti PGŽ — HGK/HOK članovi."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
COMMERCE = {
|
||||
"hgk_rijeka_deep": ["https://www.hgk.hr/zupanijske-komore/primorsko-goranska-zupanijska-komora"],
|
||||
"hok_pgz": ["https://www.hok.hr/"],
|
||||
"poduzetnistvo_ri": ["https://www.pgz.hr/gospodarstvo/"],
|
||||
"poslovni_inkubator": ["https://www.step-ri.hr/"],
|
||||
"izvoz_import_pgz": ["https://www.hgk.hr/izvoz-uvoz"],
|
||||
"tehnopolis_firme": ["https://www.tehnopolis.hr/"],
|
||||
"start_up_ri": ["https://www.startup-rijeka.hr/"],
|
||||
"obrtnička_komora": ["https://www.hok.hr/pgz"],
|
||||
"tz_pgz_biznis": ["https://www.kvarner.hr/biznis"],
|
||||
"free_zone_rijeka": ["https://www.rfind.hr/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=12):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=15)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 200: continue
|
||||
ff = []
|
||||
if title and len(title) > 8:
|
||||
ff.append({"fact": f"{name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 800):
|
||||
if len(c) > 100:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="commerce_pgz", confidence=0.84)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 35:
|
||||
queue.append(link)
|
||||
time.sleep(0.5)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in COMMERCE.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=10)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"commerce_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Ekologija i zaštita okoliša PGŽ."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
ECOLOGY = {
|
||||
"np_risnjak_full": ["https://www.np-risnjak.hr/"],
|
||||
"pp_ucka": ["https://pp-ucka.hr/"],
|
||||
"zelena_akcija": ["https://zelena-akcija.hr/"],
|
||||
"eko_kvarner": ["https://www.eko-kvarner.hr/"],
|
||||
"fundacija_adris": ["https://www.adris.hr/"],
|
||||
"plava_zastava": ["https://www.plava-zastava.hr/"],
|
||||
"cistoca_pgz": ["https://www.cistoca.hr/"],
|
||||
"vodoopskrba_pgz": ["https://www.kdvik-rijeka.hr/"],
|
||||
"otpad_pgz": ["https://www.komunalac.hr/"],
|
||||
"More_cisto": ["https://more-cisto.hr/"],
|
||||
"zzjz_okolisa": ["https://www.zzjzpgz.hr/zastita-okolisa/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=12):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=15)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 200: continue
|
||||
ff = []
|
||||
if title and len(title) > 8:
|
||||
ff.append({"fact": f"{name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 800):
|
||||
if len(c) > 100:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="ekologija_pgz", confidence=0.86)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 35:
|
||||
queue.append(link)
|
||||
time.sleep(0.5)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in ECOLOGY.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=10)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"ecology_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""NGO i udruge PGŽ — mladi, veterani, humanitarne."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
NGO = {
|
||||
"mladi_pgz": ["https://www.pgz.hr/mladi/"],
|
||||
"udruge_pgz": ["https://www.udruge.hr/pgz"],
|
||||
"humanitarne_pgz": ["https://www.volonterski-centar-ri.hr/"],
|
||||
"crveni_kriz_full": ["https://www.crveni-kriz-rijeka.hr/"],
|
||||
"veterani_pgz": ["https://www.veterani.hr/pgz"],
|
||||
"umirovljenici_pgz": ["https://www.savez-umirovljenika.hr/"],
|
||||
"invalidi_pgz": ["https://www.invalidi-rijeka.hr/"],
|
||||
"zivotrodi_pgz": ["https://www.zivotrodi.hr/"],
|
||||
"omladina_ri": ["https://www.omladina-rijeka.hr/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=10):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=15)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 200: continue
|
||||
ff = []
|
||||
if title and len(title) > 8:
|
||||
ff.append({"fact": f"{name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 800):
|
||||
if len(c) > 100:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="ngo_pgz", confidence=0.84)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 25:
|
||||
queue.append(link)
|
||||
time.sleep(0.5)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in NGO.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=8)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"ngo_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pomorstvo — luke, marine, brodogradnja, nautika."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
MARITIME = {
|
||||
"luka_rijeka_full": ["https://www.lukarijeka.hr/", "https://www.portauthority.hr/"],
|
||||
"aci_marine_kvarner": ["https://www.aci-marinas.com/"],
|
||||
"marina_opatija": ["https://www.marina-opatija.hr/"],
|
||||
"marina_punat": ["https://www.marina-punat.hr/"],
|
||||
"marina_cres": ["https://www.aci-marinas.com/marina/aci-cres"],
|
||||
"yachting_kvarner": ["https://www.yachting-kvarner.com/"],
|
||||
"brod_3maj_deep": ["https://www.3maj.hr/"],
|
||||
"viktor_lenac_deep": ["https://www.lenac.hr/"],
|
||||
"pfri_maritime": ["https://www.pfri.uniri.hr/"],
|
||||
"luka_baska": ["https://www.luka-baska.hr/"],
|
||||
"luke_kvarner": ["https://www.luke-hrvatska.hr/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=15):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=15)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 200: continue
|
||||
ff = []
|
||||
if title and len(title) > 8:
|
||||
ff.append({"fact": f"{name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 800):
|
||||
if len(c) > 100:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="pomorstvo_pgz", confidence=0.87)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 40:
|
||||
queue.append(link)
|
||||
time.sleep(0.5)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in MARITIME.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=12)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"maritime_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Osnovne i srednje škole + vrtići PGŽ."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
SCHOOLS = {
|
||||
"srednje_skole_ri": ["https://www.skole.hr/skole/primorsko-goranska-zupanija"],
|
||||
"osnove_skole_ri": ["https://www.rijeka.hr/skole/"],
|
||||
"vrtici_pgz": ["https://www.pula.hr/hr/gradski-vrtic/"],
|
||||
"gimnazija_ri": ["https://www.gimnazija-rijeka.hr/"],
|
||||
"tehnicka_skola_ri": ["https://www.tehnicka-rijeka.hr/"],
|
||||
"ekonomska_skola_ri": ["https://www.ekonomska-rijeka.hr/"],
|
||||
"medicinska_skola_ri": ["https://www.medicinska-skola-rijeka.hr/"],
|
||||
"skole_opatija": ["https://www.opatija.hr/skole"],
|
||||
"skole_crikvenica": ["https://www.skole-crikvenica.hr/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=10):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=15)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 200: continue
|
||||
ff = []
|
||||
if title and len(title) > 8:
|
||||
ff.append({"fact": f"{name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 800):
|
||||
if len(c) > 100:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="skole_pgz", confidence=0.86)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 30:
|
||||
queue.append(link)
|
||||
time.sleep(0.5)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in SCHOOLS.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=8)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"schools_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Sport federacije i savezi PGŽ — all sports."""
|
||||
import sys, json, time
|
||||
sys.path.insert(0, "/opt/pgz-sport/scrapers/harvesters")
|
||||
from _common import (fetch, extract_text, extract_title, chunk_text,
|
||||
upsert_facts, find_internal_links, DSN)
|
||||
from urllib.parse import urlparse
|
||||
import psycopg2
|
||||
|
||||
FEDERATIONS = {
|
||||
"zns_pgz": ["https://www.pgzns.hr/"],
|
||||
"kss_pgz": ["https://www.kss-pgz.hr/"],
|
||||
"handball_pgz": ["https://www.hrs-pgz.hr/"],
|
||||
"odbojka_savez_pgz": ["https://www.odbojka-pgz.hr/"],
|
||||
"atletika_savez_pgz": ["https://www.atletika-pgz.hr/"],
|
||||
"plivanje_savez_pgz": ["https://www.plivanje-pgz.hr/"],
|
||||
"skijaski_savez_pgz": ["https://www.ski-pgz.hr/"],
|
||||
"tenis_savez_pgz": ["https://www.tenis-pgz.hr/"],
|
||||
"judo_savez_pgz": ["https://www.judo-pgz.hr/"],
|
||||
"karate_savez_pgz": ["https://www.karate-pgz.hr/"],
|
||||
"kuglanje_savez_pgz": ["https://www.kuglanje-pgz.hr/"],
|
||||
}
|
||||
|
||||
|
||||
def crawl(name, urls, max_pages=12):
|
||||
conn = psycopg2.connect(DSN); conn.autocommit = True
|
||||
visited = set(); queue = list(urls); facts = 0
|
||||
while queue and len(visited) < max_pages:
|
||||
url = queue.pop(0)
|
||||
if url in visited: continue
|
||||
visited.add(url)
|
||||
html, status = fetch(url, timeout=15)
|
||||
if not html or status != 200: continue
|
||||
title = extract_title(html); text = extract_text(html)
|
||||
if not text or len(text) < 200: continue
|
||||
ff = []
|
||||
if title and len(title) > 8:
|
||||
ff.append({"fact": f"{name} - {title}", "url": url, "title": title})
|
||||
for c in chunk_text(text, 800):
|
||||
if len(c) > 100:
|
||||
ff.append({"fact": c, "url": url, "title": title})
|
||||
facts += upsert_facts(conn, ff, source_name=name,
|
||||
category="sport_federacije_pgz", confidence=0.88)
|
||||
base = urlparse(url).hostname
|
||||
for link in find_internal_links(html, url):
|
||||
if link not in visited and (urlparse(link).hostname or "") == base and len(queue) < 35:
|
||||
queue.append(link)
|
||||
time.sleep(0.5)
|
||||
conn.close()
|
||||
return {"name": name, "visited": len(visited), "facts": facts}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for name, urls in FEDERATIONS.items():
|
||||
try:
|
||||
r = crawl(name, urls, max_pages=10)
|
||||
print(f" {name:25} {r['visited']:>3}p {r['facts']:>5}f")
|
||||
results.append(r)
|
||||
except Exception as e:
|
||||
print(f" {name:25} FAIL: {str(e)[:60]}")
|
||||
total = sum(r.get("facts", 0) for r in results)
|
||||
print(f"=== TOTAL: {total} ===")
|
||||
print(json.dumps({"fed_count": len(results), "total_facts": total}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user