# ───────────────────────────────────────────────────────────────
# app.py ── SEO Tool (robuste Version – 2025/26 Style)
# ───────────────────────────────────────────────────────────────
from flask import Flask, request, jsonify, render_template_string
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from bs4 import BeautifulSoup
import re
import json
import traceback
app = Flask(__name__)
# ── Session mit Retry und Timeout ─────────────────────────────────
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504])
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))
def fetch_page(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "de-DE,de;q=0.9,en;q=0.8",
}
try:
r = session.get(
url,
headers=headers,
timeout=18,
verify=False, # ← nur zum Testen – in Prod certifi nutzen!
allow_redirects=True
)
r.raise_for_status()
return r.text
except Exception as e:
print(f"[FETCH ERROR] {url} → {type(e).__name__}: {str(e)}")
print(traceback.format_exc())
return None
def extract_keywords(text):
if not text:
return []
words = re.findall(r'\w{3,}', text.lower())
from collections import Counter
cnt = Counter(words)
return [w for w, c in cnt.most_common(12)]
def generate_seo( content_text: str = "", url_title: str = "", url_h1: str = "" ):
if not content_text.strip():
content_text = "Keine Inhalte verfügbar. Bitte manuelle Beschreibung eingeben."
kw = extract_keywords(content_text)
main = kw[0].capitalize() if kw else "Thema"
title = f"{main} – {', '.join(kw[:2]).title()}"[:60].strip(" –")
desc = (content_text[:158] + "...").replace("\n", " ").strip()
h1 = url_h1 or f"{main}"
schema = {
"@context": "https://schema.org",
"@type": "WebPage",
"name": title,
"description": desc,
"keywords": ", ".join(kw[:8])
}
return {
"seo_title": title or "Seitentitel optimieren",
"seo_desc": desc or "Beschreibung für Suchmaschinen erstellen …",
"h1": h1,
"keywords": kw[:8],
"schema_json": json.dumps(schema, ensure_ascii=False, indent=2)
}
def meta_code(seo):
return f'''{seo["seo_title"]}
'''
def popup_code(seo):
return f'''
'''
# ── Single-File-Version ── alles in einer Route ────────────────────────
HTML = """
SEO Meta & Popup Generator
"""
@app.route('/')
def index():
return render_template_string(HTML)
@app.route('/api', methods=['POST'])
def api():
try:
d = request.get_json() or {}
manual = d.get('manual', '').strip()
url = d.get('url', '').strip()
if manual:
seo = generate_seo(manual)
elif url:
html = fetch_page(url)
if not html:
return jsonify({
"error": "Seite konnte nicht abgerufen werden (Timeout, Blockade, ungültige URL, kein Internet?)"
}), 400
soup = BeautifulSoup(html, 'html.parser')
title = (soup.title.string or '').strip()
h1 = (soup.find('h1').get_text(strip=True) if soup.find('h1') else '')
text = ' '.join(soup.stripped_strings)[:12000]
seo = generate_seo(text, title, h1)
else:
return jsonify({"error": "Weder URL noch manueller Text angegeben"}), 400
return jsonify({
"seo": seo,
"meta": meta_code(seo),
"popup": popup_code(seo)
})
except Exception as e:
print("[API ERROR]", str(e))
print(traceback.format_exc())
return jsonify({"error": "Interner Serverfehler – siehe Terminal"}), 500
if __name__ == '__main__':
print("→ Starte http://127.0.0.1:5000")
app.run(debug=True, port=5000, use_reloader=False)
Kommentare
Kommentar veröffentlichen