← back to Ga Allsites

_ga4_audit.py

54 lines

import json
import pathlib
import re
import ssl
import urllib.request
from concurrent.futures import ThreadPoolExecutor


def slug(s):
    x=s.lower().replace(" - ga4","").replace("&","and"); return "".join(c for c in x if c.isalnum())
def dslug(d): return "".join(c for c in d.rsplit(".",1)[0].lower() if c.isalnum())
data=json.loads(pathlib.Path("cache/data.json").read_text())
ga4={slug(r["property"]) for r in data["rows"]}
port=json.loads(pathlib.Path("cache/_portfolio_domains.json").read_text())["union"]
missing=[d for d in port if not any(dslug(d)==g or dslug(d) in g or g in dslug(d) for g in ga4 if g)]
ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
PARK=re.compile(r"(domain (is )?for sale|buy this domain|parked|godaddy\.com/domainsearch|afternic|sedoparking|this domain may be for sale|hugedomains|dan\.com|is coming soon|website coming soon|under construction|default web page|welcome to nginx|apache2 ubuntu default)",re.IGNORECASE)
GA4=re.compile(r"(G-[A-Z0-9]{6,}|googletagmanager\.com/gtag/js|gtag\('config'|UA-\d{4,})")
def probe(d):
    url=f"https://{d}/"
    try:
        req=urllib.request.Request(url,headers={"User-Agent":"Mozilla/5.0 (audit)"})
        r=urllib.request.urlopen(req,timeout=12,context=ctx)
        final=r.geturl(); html=r.read(200000).decode("utf-8","ignore"); code=r.getcode()
    except Exception as e:
        return (d,"DEAD",str(e)[:40],False,"")
    off = dslug(d) not in dslug(final.split("//")[-1].split("/")[0])
    has_ga4=bool(GA4.search(html))
    if PARK.search(html) or len(html)<400:
        cls="PARKED"
    elif off:
        cls="REDIRECT"
    else:
        cls="LIVE"
    return (d,cls,f"{code}",has_ga4,final if off else "")
with ThreadPoolExecutor(max_workers=20) as ex:
    res=list(ex.map(probe,missing))
from collections import defaultdict

buckets=defaultdict(list)
for d,cls,info,ga,final in res:
    key = "LIVE_HAS_GA4" if (cls=="LIVE" and ga) else cls
    buckets[key].append((d,info,final))
print("=== GA4 AUDIT of the 162 no-match domains ===")
for k in ["LIVE","LIVE_HAS_GA4","REDIRECT","PARKED","DEAD"]:
    print(f"  {k:14} {len(buckets.get(k,[]))}")
install=[d for d,_,_ in buckets.get("LIVE",[])]
pathlib.Path("cache/_ga4_install_list.json").write_text(json.dumps(sorted(install)))
print(f"\n>>> INSTALL LIST (live site, genuinely no GA4): {len(install)}")
for d in sorted(install): print("  ",d)
if buckets.get("LIVE_HAS_GA4"):
    print(f"\n(already has a tag, just name-mismatched — no action: {len(buckets['LIVE_HAS_GA4'])})")
    for d,_,_ in sorted(buckets["LIVE_HAS_GA4"])[:20]: print("   ~",d)