mirror of
https://github.com/gbessoni/seobuild-onpage.git
synced 2026-06-23 11:58:37 +02:00
seo-agi: The GEO framework skill for Claude Code + OpenClaw
GEO framework that writes pages ranking on Google AND getting cited by LLMs. 500-token chunk architecture, Reddit Test quality gates, verification tags, Not For You blocks, information gain enforcement. Data layer: DataForSEO, GSC, Ahrefs MCP, SEMRush MCP. 21 files, all tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SEO-AGI Google Search Console data puller.
|
||||
Retrieves query performance data and detects cannibalization.
|
||||
|
||||
Usage:
|
||||
python3 gsc_pull.py "<site_url>" [options]
|
||||
|
||||
Options:
|
||||
--keyword=KEYWORD Filter queries containing this keyword
|
||||
--days=N Lookback period (default: 90)
|
||||
--min-impressions=N Minimum impressions threshold (default: 10)
|
||||
--output=FORMAT Output: json|compact (default: compact)
|
||||
--cannibalization Run cannibalization detection for the keyword
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from lib.env import get_credentials
|
||||
from lib.gsc_client import GSCClient
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="SEO-AGI GSC Pull")
|
||||
parser.add_argument("site_url", help="GSC site URL (e.g., https://example.com)")
|
||||
parser.add_argument("--keyword", default=None, help="Keyword filter")
|
||||
parser.add_argument("--days", type=int, default=90, help="Lookback days")
|
||||
parser.add_argument("--min-impressions", type=int, default=10, help="Min impressions")
|
||||
parser.add_argument("--output", choices=["json", "compact"], default="compact")
|
||||
parser.add_argument("--cannibalization", action="store_true", help="Detect cannibalization")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def format_compact(data: list[dict], mode: str = "performance") -> str:
|
||||
lines = []
|
||||
|
||||
if mode == "cannibalization":
|
||||
lines.append("# Cannibalization Report")
|
||||
for item in data:
|
||||
lines.append(f"\nQuery: {item['query']} ({item['page_count']} pages, {item['total_impressions']} impressions)")
|
||||
for page in item["pages"]:
|
||||
lines.append(f" pos {page['position']}: {page['page']} ({page['clicks']} clicks, {page['ctr']}% CTR)")
|
||||
else:
|
||||
lines.append("# Query Performance")
|
||||
lines.append(f"{'Query':<40} {'Clicks':>7} {'Impr':>7} {'CTR':>7} {'Pos':>5} Page")
|
||||
lines.append("-" * 110)
|
||||
for row in data[:50]:
|
||||
lines.append(
|
||||
f"{row['query'][:39]:<40} {row['clicks']:>7} {row['impressions']:>7} "
|
||||
f"{row['ctr']:>6.1f}% {row['position']:>5.1f} {row['page'][:50]}"
|
||||
)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
creds = get_credentials()
|
||||
|
||||
if not creds["has_gsc"]:
|
||||
print("ERROR: Google Search Console credentials not found.", file=sys.stderr)
|
||||
print("Add GSC_SERVICE_ACCOUNT_PATH to ~/.config/seo-agi/.env", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
client = GSCClient(credentials_path=creds["gsc_service_account_path"])
|
||||
|
||||
if args.cannibalization and args.keyword:
|
||||
data = client.detect_cannibalization(
|
||||
site_url=args.site_url,
|
||||
keyword=args.keyword,
|
||||
days=args.days,
|
||||
)
|
||||
if args.output == "json":
|
||||
print(json.dumps(data, indent=2))
|
||||
else:
|
||||
print(format_compact(data, mode="cannibalization"))
|
||||
else:
|
||||
data = client.query_performance(
|
||||
site_url=args.site_url,
|
||||
keyword=args.keyword,
|
||||
days=args.days,
|
||||
min_impressions=args.min_impressions,
|
||||
)
|
||||
if args.output == "json":
|
||||
print(json.dumps(data, indent=2))
|
||||
else:
|
||||
print(format_compact(data))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user