Files
autoreg-skills-max/skills/cloudflare-bypass-scraping/templates/email_scraper_cf.py

172 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Email scraper with CF bypass — two backends:
1. curl_cffi (lightweight, no browser, works now) ← DEFAULT
2. CF Bypass Server (full browser, for JS-challenge sites)
Usage:
python email_scraper_cf.py https://target.com
python email_scraper_cf.py https://target.com --backend server
python email_scraper_cf.py https://target.com --proxy socks5://user:pass@host:port
"""
import re
import sys
import time
import json
from urllib.parse import urljoin, urlparse
from typing import Optional
# ── Backend 1: curl_cffi (lightweight, TLS fingerprint impersonation) ──
try:
from curl_cffi import requests as cf_requests
HAS_CURL_CFFI = True
except ImportError:
HAS_CURL_CFFI = False
# ── Backend 2: CF Bypass Server (full browser) ──
import requests as std_requests
CF_BYPASS_URL = "http://localhost:8000"
# ── Config ──────────────────────────────────────────────────
MAX_PAGES = 50
REQUEST_TIMEOUT = 30
EMAIL_RE = re.compile(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}')
LINK_RE = re.compile(r'href=["\']([^"\']+)["\']')
# ────────────────────────────────────────────────────────────
def fetch_curl_cffi(url: str, proxy: Optional[str] = None) -> str:
"""Fetch using curl_cffi with Chrome 124 TLS fingerprint impersonation."""
if not HAS_CURL_CFFI:
raise RuntimeError("curl_cffi not installed. Run: pip install curl_cffi")
proxies = {"http": proxy, "https": proxy} if proxy else None
resp = cf_requests.get(
url,
impersonate="chrome124",
proxies=proxies,
timeout=REQUEST_TIMEOUT,
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/[REDACTED-IP] Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
}
)
return resp.text
def fetch_cf_server(url: str, proxy: Optional[str] = None) -> str:
"""Fetch through local CF Bypass Server (full browser JS challenge solve)."""
headers = {"x-hostname": urlparse(url).netloc}
if proxy:
headers["x-proxy"] = proxy
resp = std_requests.get(
f"{CF_BYPASS_URL}/html",
params={"url": url},
headers=headers,
timeout=REQUEST_TIMEOUT + 30, # browser solve takes longer
)
resp.raise_for_status()
return resp.text
def extract_emails(html: str) -> set[str]:
return set(EMAIL_RE.findall(html))
def extract_links(html: str, base_url: str) -> list[str]:
base = f"{urlparse(base_url).scheme}://{urlparse(base_url).netloc}"
links = []
for href in LINK_RE.findall(html):
full = urljoin(base_url, href)
if full.startswith(base) and not full.endswith(
(".jpg", ".png", ".pdf", ".zip", ".css", ".js", ".ico", ".svg", ".woff", ".woff2")
):
links.append(full)
return links
def crawl(start_url: str, proxy: Optional[str] = None, backend: str = "curl_cffi") -> dict[str, set[str]]:
fetch = fetch_curl_cffi if backend == "curl_cffi" else fetch_cf_server
seen: set[str] = set()
queue: list[str] = [start_url]
results: dict[str, set[str]] = {}
while queue and len(seen) < MAX_PAGES:
url = queue.pop(0)
if url in seen:
continue
seen.add(url)
try:
print(f"[{len(seen)}/{MAX_PAGES}] {url}")
html = fetch(url, proxy)
except Exception as e:
print(f" ⨯ {type(e).__name__}: {e}")
continue
emails = extract_emails(html)
if emails:
results[url] = emails
for e in emails:
print(f" ✉ {e}")
for link in extract_links(html, url):
if link not in seen:
queue.append(link)
time.sleep(0.3)
return results
def quick_scan(url: str, proxy: Optional[str] = None, backend: str = "curl_cffi") -> set[str]:
fetch = fetch_curl_cffi if backend == "curl_cffi" else fetch_cf_server
html = fetch(url, proxy)
return extract_emails(html)
# ── CLI ─────────────────────────────────────────────────────
if __name__ == "__main__":
if len(sys.argv) < 2:
print(__doc__)
sys.exit(1)
target = sys.argv[1]
backend = "curl_cffi"
proxy = None
quick = False
i = 2
while i < len(sys.argv):
if sys.argv[i] == "--backend" and i + 1 < len(sys.argv):
backend = sys.argv[i + 1]; i += 1
elif sys.argv[i] == "--proxy" and i + 1 < len(sys.argv):
proxy = sys.argv[i + 1]; i += 1
elif sys.argv[i] == "--quick":
quick = True
i += 1
if backend == "curl_cffi" and not HAS_CURL_CFFI:
print("curl_cffi not installed. Install: pip install curl_cffi")
print("Falling back to 'server' backend. Make sure CF Bypass Server is running on port 8000.")
backend = "server"
if quick:
emails = quick_scan(target, proxy, backend)
print(f"\n{len(emails)} emails on {target}:")
for e in sorted(emails):
print(f" {e}")
else:
results = crawl(target, proxy, backend)
total = sum(len(v) for v in results.values())
print(f"\n✓ {total} emails across {len(results)} pages")
out = {url: sorted(emails) for url, emails in results.items()}
with open("emails_output.json", "w", encoding="utf-8") as f:
json.dump(out, f, indent=2, ensure_ascii=False)
print(f"✓ Saved to emails_output.json")