#!/usr/bin/env python3
"""StudioSoft: artikel harian 13 Okt 2026 (pilar B AI) - riset kompetitor SEO dari halaman peraih trafik.
Pola mengikuti ss_artikel_kata_kunci_lokal.py. Tahap: draf dulu (--apply), baru dijadwalkan (--jadwalkan TANGGAL).
"""
import base64, json, re, sys, time, urllib.error, urllib.request

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
DOM = "studiosoft.id"
AUTH = base64.b64encode(b"bambangbot:q26r RePo BVy6 pwU2 F3z7 ouyl").decode()

JUDUL = "Riset Kompetitor SEO: Melihat Halaman yang Menghasilkan Trafik Mereka"
SLUG = "riset-kompetitor-seo"
FOKUS = "riset kompetitor seo"
META_JUDUL = "Riset Kompetitor SEO: Baca Halaman Peraih Trafik"
META_DESC = ("Riset kompetitor SEO dimulai dari halaman yang mendatangkan pengunjung, bukan daftar kata "
             "kunci. Ini cara membacanya lalu mencari celah yang bisa diisi.")

KAT = [330]  # SEO

WA = "https://wa.me/6281935000624?text=Halo%20StudioSoft%2C%20saya%20ingin%20konsultasi%20digital%20marketing"
TOMBOL = ('<p style="text-align:center;margin:32px 0 8px"><a href="' + WA +
          '" target="_blank" rel="noopener" style="display:inline-block;background-color:#0f2557;'
          'color:#ffffff;padding:15px 34px;font-size:18px;font-weight:bold;text-decoration:none;'
          'border-radius:6px;">Konsultasi Gratis</a></p>')

L1 = "https://studiosoft.id/tools-analisis-kompetitor-media-sosial/"
L2 = "https://studiosoft.id/7-cara-menggunakan-ai-untuk-riset-kata-kunci-yang-lebih-cepat-dan-akurat/"
L3 = "https://studiosoft.id/jasa-seo-surabaya-paket-harga/"

FAQ = [
    ("Apakah riset kompetitor butuh alat berbayar?",
     "Tidak selalu. Search Console sudah memberi data kueri yang nyata memunculkan situs Anda, dan "
     "pemeriksaan hasil pencarian secara manual cukup untuk melihat halaman siapa yang menang. Alat "
     "berbayar berguna saat Anda perlu membandingkan banyak kueri."),
    ("Berapa banyak pesaing yang perlu diperiksa?",
     "Tiga sampai lima halaman teratas untuk setiap kueri prioritas sudah memadai. Menambah jumlah "
     "pesaing biasanya tidak menambah temuan baru."),
    ("Bagaimana kalau semua halaman teratas adalah artikel daftar?",
     "Itu tanda peluang, bukan hambatan. Artikel daftar menjawab pertanyaan umum dan tidak bisa mendalam "
     "untuk setiap pilihan. Halaman yang fokus pada satu layanan, satu wilayah, dan satu kebutuhan "
     "spesifik masih punya ruang."),
    ("Seberapa sering riset ini diulang?",
     "Setiap tiga bulan cukup untuk sebagian besar bisnis. Yang berubah biasanya komposisi halaman di "
     "posisi atas, bukan daftar kueri intinya."),
]

ISI = """
<p>Banyak riset kompetitor berhenti pada satu kesimpulan: mereka punya konten lebih banyak. Kesimpulan
itu tidak bisa dipakai untuk mengambil keputusan. Yang berguna adalah mengetahui halaman mana dari
ratusan konten mereka yang benar-benar mendatangkan pengunjung, dan apa yang membuat halaman itu bekerja.</p>

<p>Artikel ini membahas cara membaca halaman peraih trafik kompetitor dengan bahan yang bisa Anda
kumpulkan sendiri: hasil pencarian Google dan laporan Search Console Anda. Tujuannya bukan menyalin,
melainkan menemukan bagian yang belum tergarap.</p>

<h2>Kenapa daftar kata kunci kompetitor tidak cukup</h2>
<p>Alat riset kompetitor umumnya menghasilkan keluaran yang serupa: ribuan kata kunci, perkiraan volume,
dan tingkat persaingan. Daftar itu menggambarkan permintaan pasar, tetapi tidak menjelaskan siapa yang
menang dan mengapa.</p>

<p>Dua bisnis bisa membidik kata kunci yang sama dengan hasil yang jauh berbeda. Yang satu punya halaman
khusus yang menjawab kebutuhan pembeli. Yang lain hanya punya beranda berisi beberapa paragraf umum. Dari
daftar kata kunci, keduanya terlihat sama saja.</p>

<p>Karena itu mulailah dari halaman, bukan dari kata kunci. Pertanyaan yang perlu dijawab: halaman mana
yang muncul, untuk kueri apa, dan bagian mana dari halaman itu yang membuat orang memilih mereka.</p>

<h2>Mulai dari kueri yang benar-benar Anda bidik</h2>
<p>Ambil sepuluh sampai dua puluh kueri yang paling dekat dengan penjualan Anda. Buka Search Console,
lihat kueri dengan tayangan terbanyak, lalu pilih yang memuat nama layanan atau nama wilayah. Kueri
seperti itu sudah terbukti dicari orang, bukan hasil perkiraan alat.</p>

<p>Untuk setiap kueri, buka hasil pencariannya dan catat lima halaman teratas. Isi tabel sederhana:
kueri, alamat halaman yang menang, jenis halaman, dan hal utama yang ditonjolkan. Cukup empat kolom,
satu jam selesai.</p>

<p>Perhatikan jenis halamannya, karena itu menentukan strategi Anda. Halaman layanan, artikel daftar,
direktori, dan marketplace bersaing dengan aturan yang tidak sama. Kalau sebuah kueri didominasi artikel
daftar, menulis halaman layanan biasa biasanya belum cukup.</p>

<h2>Cara membaca halaman yang mendatangkan pengunjung</h2>
<p>Setelah daftarnya jadi, buka tiga halaman yang paling sering muncul di posisi atas. Bacalah sebagai
calon pembeli, bukan sebagai pesaing. Ajukan pertanyaan yang sama seperti pertanyaan pelanggan Anda:
berapa biayanya, apa saja yang dikerjakan, siapa yang pernah memakai, dan bagaimana cara menghubungi.</p>

<p>Catat jenis bukti yang mereka pakai: foto pekerjaan sendiri, kisaran harga, atau ulasan pelanggan.
Bukti seperti itu sulit ditiru karena harus dimiliki lebih dulu, dan di situlah keunggulan Anda bisa
dibangun.</p>

<p>Catat juga bagian yang tidak ada di halaman mereka. Yang hilang biasanya lebih menarik daripada yang
sudah rapi: pertanyaan yang tidak dijawab, wilayah yang tidak disebut, dan langkah berikutnya yang tidak
dijelaskan.</p>

<h2>Memisahkan halaman ramai dari halaman yang menghasilkan</h2>
<p>Halaman dengan trafik besar belum tentu mendatangkan pembeli. Artikel yang menjelaskan pengertian
sesuatu menarik banyak pengunjung, tetapi jarang menghasilkan kontak karena orang yang membacanya masih
mencari pemahaman.</p>

<p>Untuk memilahnya, baca kueri yang membawa trafik ke halaman itu. Kueri dengan kata seperti harga,
biaya, atau nama layanan menunjukkan niat yang lebih dekat ke pembelian. Kueri dengan kata seperti contoh,
pengertian, atau jenis biasanya berada di tahap awal.</p>

<p>Meniru artikel edukasi kompetitor menambah trafik, tetapi jarang memperbaiki jumlah kontak masuk.
Halaman yang menjawab kebutuhan pembeli lebih sedikit dikunjungi, tetapi lebih berguna bagi penjualan.</p>

<h2>Mencari celah dari data yang sudah Anda miliki</h2>
<p>Celah paling murah biasanya sudah terlihat di Search Console. Saring kueri dengan posisi rata-rata
antara 8 dan 20, lalu lihat halaman mana yang muncul untuk kueri itu. Kueri seperti ini sudah punya
tayangan, artinya Google menganggap halaman Anda relevan, tetapi posisinya masih di halaman dua atau tiga
hasil pencarian.</p>

<p>Periksa halaman Anda, lalu bandingkan dengan yang berada di atasnya. Kalau pesaing di atas adalah
direktori atau halaman layanan yang tipis, celahnya jelas: halaman yang menjawab kebutuhan secara lengkap,
dengan cakupan layanan, wilayah, harga, dan cara menghubungi yang tertulis.</p>

<p>Saat kami memeriksa hasil pencarian untuk kueri bergaya lokal, posisi teratas beberapa kali diisi
artikel daftar dan halaman direktori, bukan beranda penyedia di kota itu. Temuan seperti itu mengubah
prioritas: yang lebih dibutuhkan adalah halaman yang lebih spesifik daripada daftar.</p>

<h2>Dari temuan ke keputusan</h2>
<p>Setiap temuan sebaiknya berujung pada satu dari tiga keputusan. Perbaiki halaman yang sudah ada kalau
kueri dan halamannya sudah cocok tetapi isinya kurang. Tulis halaman baru kalau kueri itu belum punya
halaman khusus di situs Anda. Tahan dulu kalau permintaannya kecil dan tidak berhubungan dengan layanan
yang Anda jual.</p>

<p>Urutkan berdasarkan kueri yang sudah punya tayangan lebih dulu, karena itu yang paling cepat bergerak.
Kueri tanpa tayangan tetap layak digarap kalau nilainya besar, hanya saja jangan dijadikan prioritas
pertama.</p>

<p>Ada lima hal yang membuat seluruh pekerjaan ini berhenti tanpa hasil.</p>
<ul>
<li>Menyalin seluruh daftar kata kunci pesaing tanpa memeriksa halaman mana yang benar-benar mendatangkan
pengunjung.</li>
<li>Menilai pesaing hanya dari beranda, padahal yang berada di posisi atas adalah halaman dalam.</li>
<li>Meniru artikel edukasi padahal yang Anda butuhkan adalah pembeli yang siap menghubungi.</li>
<li>Memakai angka volume dari alat pihak ketiga sebagai bukti di laporan.</li>
<li>Mengumpulkan temuan tanpa memutuskan halaman mana yang dikerjakan lebih dulu.</li>
</ul>

<h2>Alat yang membantu, dan batasnya</h2>
<p>Search Console adalah sumber paling dapat dipercaya karena datanya berasal dari pencarian nyata yang
memunculkan situs Anda. Untuk sisi kompetitor, pemeriksaan hasil pencarian secara manual sudah cukup untuk
memulai, dan hasilnya sering lebih akurat daripada perkiraan alat.</p>

<p>Alat berbayar berguna untuk melihat gambaran besar: kelompok topik, panjang halaman, dan perkiraan
volume. Angka volume di alat pihak ketiga tetap perkiraan, dan bisa berbeda jauh dari kenyataan, jadi
jangan dipakai sebagai bukti di laporan.</p>

<p>Untuk membaca performa akun pesaing di media sosial, pilihannya kami rangkum di
<a href=\"""" + L1 + """\">tools analisis kompetitor media sosial</a>. Untuk sisi kata kunci, langkah yang
lebih cepat kami bahas di <a href=\"""" + L2 + """\">cara menggunakan AI untuk riset kata kunci</a>.</p>

<h2>Pertanyaan yang sering diajukan</h2>
<h3>""" + FAQ[0][0] + """</h3>
<p>""" + FAQ[0][1] + """</p>
<h3>""" + FAQ[1][0] + """</h3>
<p>""" + FAQ[1][1] + """</p>
<h3>""" + FAQ[2][0] + """</h3>
<p>""" + FAQ[2][1] + """</p>
<h3>""" + FAQ[3][0] + """</h3>
<p>""" + FAQ[3][1] + """</p>

<p>Riset kompetitor paling berguna kalau berujung pada keputusan halaman mana yang dikerjakan. Mulai dari
sepuluh kueri terdekat dengan penjualan Anda, catat halaman yang menang, lalu putuskan urutannya. Kalau
Anda ingin bagian ini dikerjakan bersama tim, cakupan dan kisaran biayanya ada di
<a href=\"""" + L3 + """\">halaman jasa SEO Surabaya</a>.</p>

""" + TOMBOL + """
<p><em>Catatan: contoh pemeriksaan hasil pencarian di atas kami ambil dari pengecekan langsung hasil
Google.</em></p>
"""

LD = {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [{"@type": "Question", "name": q,
                    "acceptedAnswer": {"@type": "Answer", "text": a}} for q, a in FAQ],
}
ISI = ISI + '\n<script type="application/ld+json">' + json.dumps(LD, ensure_ascii=False) + "</script>\n"

UA = {"User-Agent": "Mozilla/5.0"}


def rest(p, method="GET", data=None):
    h = {"Authorization": f"Basic {AUTH}", **UA}
    body = None
    if data is not None:
        body = json.dumps(data).encode()
        h["Content-Type"] = "application/json"
    r = urllib.request.Request(f"https://{DOM}{p}", data=body, headers=h, method=method)
    for _ in range(3):
        try:
            with urllib.request.urlopen(r, timeout=180) as x:
                return x.status, json.loads(x.read())
        except urllib.error.HTTPError as e:
            return e.code, e.read().decode()[:300]
        except Exception:
            time.sleep(4)
    return 0, "gagal"


if __name__ == "__main__":
    tanpa_script = re.sub(r"<script.*?</script>", " ", ISI, flags=re.S)
    kata_visible = len(re.sub(r"<[^>]+>", " ", tanpa_script).split())
    kata_hitung = len(re.sub(r"<[^>]+>", " ", ISI).split())
    print("=== artikel baru:", JUDUL)
    print(f"   panjang naskah: {kata_visible} kata terlihat · {kata_hitung} kata versi cek_pola_ai")
    print(f"   meta judul: {len(META_JUDUL)} char (maks 60)")
    print(f"   meta desc : {len(META_DESC)} char (140-158) | fokus di awal: {META_DESC.lower().startswith(FOKUS)}")
    print(f"   tombol WA : {'ada' if WA in ISI else 'TIDAK ADA'}")
    print(f"   tautan internal: {len(re.findall(r'href=.https://studiosoft.id/', ISI))}")
    print(f"   h2: {len(re.findall('<h2', ISI))} | FAQPage: {'FAQPage' in ISI}")

    if "--apply" not in sys.argv and "--jadwalkan" not in sys.argv:
        print("\n(dry run - pakai --apply untuk bikin draf, --jadwalkan YYYY-MM-DD untuk menjadwalkan)")
        sys.exit(0)

    if "--apply" in sys.argv:
        st, d = rest(f"/wp-json/wp/v2/posts?slug={SLUG}&_fields=id,slug,status")
        if isinstance(d, list):
            for p in d:
                print(f"   ⚠ slug {SLUG} sudah dipakai: #{p['id']} [{p['status']}] - hentikan, ganti slug")
            if d:
                sys.exit(1)
        st, d = rest("/wp-json/wp/v2/posts", "POST", {
            "title": JUDUL, "slug": SLUG, "content": ISI, "status": "draft",
            "categories": KAT, "comment_status": "closed",
            "meta": {"_yoast_wpseo_title": META_JUDUL, "_yoast_wpseo_metadesc": META_DESC,
                     "_yoast_wpseo_focuskw": FOKUS}})
        if not isinstance(d, dict) or "id" not in d:
            print("   ❌ gagal bikin draf:", st, str(d)[:300])
            sys.exit(1)
        pid = d["id"]
        print(f"\n   ✅ draf #{pid} → {d.get('link')}")
        st2, d2 = rest(f"/wp-json/wp/v2/posts/{pid}?context=edit")
        raw = (d2.get("content") or {}).get("raw", "")
        meta = (d2.get("meta") or {})
        print(f"   baca balik: status={d2.get('status')} slug={d2.get('slug')} kata="
              f"{len(re.sub(r'<[^>]+>', ' ', raw).split())}")
        print("   meta: " + json.dumps({k: v for k, v in meta.items() if "yoast" in k}, ensure_ascii=False)[:400])
        simpan = {"id": pid, "judul": JUDUL, "slug": SLUG, "tautan": d.get("link")}
        json.dump(simpan, open(f"{WS}/drafts/ss_artikel_riset_kompetitor_seo.json", "w"), ensure_ascii=False, indent=1)
        print("   → id disimpan di drafts/ss_artikel_riset_kompetitor_seo.json")

    if "--jadwalkan" in sys.argv:
        tgl = sys.argv[sys.argv.index("--jadwalkan") + 1]
        pid = json.load(open(f"{WS}/drafts/ss_artikel_riset_kompetitor_seo.json"))["id"]
        st, d = rest(f"/wp-json/wp/v2/posts/{pid}", "POST",
                     {"status": "future", "date": f"{tgl}T08:00:00"})
        if not isinstance(d, dict) or d.get("status") != "future":
            print("   ❌ gagal menjadwalkan:", st, str(d)[:300])
            sys.exit(1)
        st2, d2 = rest(f"/wp-json/wp/v2/posts/{pid}?context=edit&_fields=id,status,date,slug,content,meta")
        raw = (d2.get("content") or {}).get("raw", "")
        print(f"   ✅ dijadwalkan #{pid}: status={d2.get('status')} date={d2.get('date')} slug={d2.get('slug')}")
        print(f"   isi: {len(re.sub(r'<[^>]+>', ' ', raw).split())} kata | tombol WA: "
              f"{'ada' if 'wa.me/6281935000624' in raw else 'TIDAK ADA'} | tautan internal: "
              f"{len(re.findall(r'href=.https://studiosoft.id/', raw))}")
