4.9 KiB
4.9 KiB
Ahrefs Login & Scraping – funktionierender Ansatz
Problem
agent-browser(CLI) wird von Cloudflare Turnstile auf app.ahrefs.com nach dem Login blockiert- Login-Seite selbst geht manchmal, aber Dashboard/interne Seiten → Cloudflare Challenge
- Headless Browser ohne Anti-Detection werden erkannt
Lösung: Playwright + playwright-stealth
Installation (einmalig)
pip install --break-system-packages playwright playwright-stealth
playwright install chromium
# Xvfb für headless mit Display:
apt-get install -y xvfb
Login-Flow (state speichern)
import asyncio, json
from playwright.async_api import async_playwright
from playwright_stealth import Stealth
async def main():
stealth = Stealth()
async with stealth.use_async(async_playwright()) as p:
browser = await p.chromium.launch(headless=True, args=['--no-sandbox'])
ctx = await browser.new_context(
user_agent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
viewport={'width': 1280, 'height': 900}
)
page = await ctx.new_page()
await page.goto('https://app.ahrefs.com/user/login', wait_until='networkidle', timeout=30000)
await page.fill('input[name="email"]', 'mkiesewetter9@googlemail.com')
await page.fill('input[name="password"]', 'mkiesewetter9@googlemail.com')
await page.click('button[type="submit"]')
await page.wait_for_url('**/dashboard**', timeout=15000)
# State speichern für spätere Sessions
await ctx.storage_state(path='/tmp/ahrefs-state.json')
print('Logged in & state saved')
await browser.close()
asyncio.run(main())
Daten abrufen (mit gespeichertem State)
import asyncio, json
from playwright.async_api import async_playwright
from playwright_stealth import Stealth
async def get_table_data(page):
"""Scrollt und extrahiert Tabellen-Zeilen"""
await page.evaluate('window.scrollTo(0, 800)')
await page.wait_for_timeout(3000)
rows = await page.evaluate('''() => {
const rows = document.querySelectorAll('[class*="tableRow"], [class*="TableRow"], [role="row"], tr');
const data = [];
rows.forEach(r => {
const t = r.innerText.trim();
if (t && t.length > 5 && t.length < 500 && t.indexOf('Filter') === -1 && t.indexOf('Spalten') === -1) {
data.push(t);
}
});
return data;
}''')
return rows
async def main():
stealth = Stealth()
async with stealth.use_async(async_playwright()) as p:
browser = await p.chromium.launch(headless=True, args=['--no-sandbox'])
ctx = await browser.new_context(
user_agent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
viewport={'width': 1280, 'height': 900}
)
# Gespeicherten State laden
cookies = json.load(open('/tmp/ahrefs-state.json'))['cookies']
await ctx.add_cookies(cookies)
page = await ctx.new_page()
base = 'mode=subdomains&projectId=2032747&target=manonamission.de%2F&volume_type=monthly'
# Beispiel: Top Pages
await page.goto(f'https://app.ahrefs.com/site-explorer/top-pages?{base}', wait_until='networkidle', timeout=30000)
await page.wait_for_timeout(5000)
rows = await get_table_data(page)
for r in rows:
print(r)
await browser.close()
asyncio.run(main())
Wichtige URLs (mit Projekt-Parametern)
- Dashboard:
https://app.ahrefs.com/dashboard - Site Explorer Overview:
/site-explorer/overview?{base} - Organic Keywords:
/site-explorer/organic-keywords?{base} - Top Pages:
/site-explorer/top-pages?{base} - Backlinks:
/site-explorer/backlinks?{base} - Organic Competitors:
/site-explorer/organic-competitors?{base} - Opportunities:
/site-explorer/opportunities?{base} - Content Gap:
/site-explorer/content-gap?{base}
Wichtige Parameter
projectId=2032747– manonamission.de Projekt-IDtarget=manonamission.de%2F– Ziel-Domainmode=subdomains– inkl. Subdomainsvolume_type=monthly– monatliches Suchvolumen
Xvfb (falls nötig)
Xvfb :99 -screen 0 1280x1024x24 &
export DISPLAY=:99
Normalerweise nicht nötig – Playwright headless läuft ohne Display.
Was NICHT funktioniert
- ❌
agent-browserCLI → Cloudflare Block nach Login - ❌
web_fetch→ kein JavaScript, useless für SPA - ❌ Direkte URL-Konstruktion ohne
projectId→ "Bitte überprüfe deine Domain" - ❌
Stealth().use_async(browser.new_context(...))→ falsche Syntax - ✅
Stealth().use_async(async_playwright())→ korrekt!
State-Haltbarkeit
/tmp/ahrefs-state.jsonüberlebt Reboots NICHT (tmpfs)- Nach Server-Reboot muss neu eingeloggt werden
- Falls Session abgelaufen → Login-Flow wiederholen