import os import sys # --- OTOMATISASI INSTALASI PLAYWRIGHT & DEPENDENSI LINUX --- # Langkah ini mendeteksi jika aplikasi berjalan di server Hugging Face (Linux) if not os.path.exists("/home/user/.cache/ms-playwright"): print("Menginstal Chromium dan dependensi sistem Linux yang dibutuhkan...") # Menginstal biner chromium os.system("python -m playwright install chromium") # Menginstal pustaka sistem (APT) yang kurang agar Chromium bisa jalan di Ubuntu HF os.system("python -m playwright install-deps chromium") import random import time import urllib.parse from datetime import datetime import re import gradio as gr from playwright.sync_api import sync_playwright user_agents = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" ] def process_target(browser, target, rentang_waktu, max_halaman, progress=gr.Progress()): query_lengkap = f"{target} site:instagram.com" clean_query = urllib.parse.quote_plus(query_lengkap) context_args = { "user_agent": random.choice(user_agents), "viewport": {"width": 1366, "height": 768}, "locale": "id-ID", "timezone_id": "Asia/Jakarta" } context = browser.new_context(**context_args) page = context.new_page() page.add_init_script("delete navigator.__proto__.webdriver;") clean_links = set() log_output = f"Memulai pencarian untuk target: '{target}'\n" try: for page_num in range(1, int(max_halaman) + 1): progress(page_num / int(max_halaman), desc=f"Memproses Halaman {page_num}") start_index = (page_num - 1) * 10 tbs_param = f"&tbs={rentang_waktu}" if rentang_waktu != "all" else "" google_url = f"https://www.google.com/search?q={clean_query}{tbs_param}&start={start_index}" log_output += f"[SEARCHING] Halaman {page_num} -> URL: {google_url}\n" page.goto(google_url, wait_until="domcontentloaded", timeout=30000) time.sleep(random.uniform(2, 4)) if page_num == 1: tombol_persetujuan = ["button:has-text('Setuju')", "button:has-text('Accept all')", "#L2AGLb"] for selector in tombol_persetujuan: if page.is_visible(selector): page.click(selector) time.sleep(2) break is_captcha = page.is_visible("form#captcha-form") or page.is_visible("#captcha") or "detected unusual traffic" in page.content().lower() if is_captcha: log_output += "[PENTING] Google mendeteksi CAPTCHA! Karena berjalan secara headless di server cloud, proses dihentikan untuk keamanan.\n" break if "tidak cocok dengan dokumen apa pun" in page.content().lower() or "did not match any documents" in page.content().lower(): log_output += f"[INFO] Hasil pencarian sudah habis di halaman {page_num}.\n" break html_content = page.content() raw_links = re.findall(r'https?://(?:www\.)?instagram\.com/[a-zA-Z0-9_\-\./\?&=]+', html_content) links_in_this_page = 0 for link in raw_links: link = link.split('"')[0].split("'")[0].split(')')[0].split('\\')[0] if "google.com" in link: continue is_postingan = any(pola in link for pola in ["/p/", "/reel/", "/tv/"]) if not is_postingan: continue if link not in clean_links: clean_links.add(link) links_in_this_page += 1 log_output += f"[PAGE {page_num}] Menemukan {links_in_this_page} link postingan baru.\n" time.sleep(random.randint(2, 5)) log_output += f"\n[SELESAI] Total menemukan {len(clean_links)} link unik untuk target '{target}'\n" except Exception as e: log_output += f"[ERROR]: {e}\n" finally: page.close() context.close() return clean_links, log_output def scraper_interface(target, rentang_waktu, max_halaman, progress=gr.Progress()): if not target: return "Target query tidak boleh kosong.", None, None file_name = "instagram_links_output.txt" if os.path.exists(file_name): os.remove(file_name) with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=[ "--disable-blink-features=AutomationControlled", "--no-sandbox", "--disable-setuid-sandbox", "--disable-infobars", "--ignore-certificate-errors" ] ) links, logs = process_target(browser, target, rentang_waktu, max_halaman, progress) browser.close() if links: timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with open(file_name, "w", encoding="utf-8") as f: for link in links: f.write(f"[{timestamp}] [Target: {target}] {link}\n") links_text = "\n".join(links) return logs, links_text, file_name else: return logs, "Tidak ada link yang ditemukan.", None # ===================== UI DESIGN (GRADIO) ===================== with gr.Blocks(title="Google Instagram Scraper") as demo: gr.Markdown("# 🕷️ Google Instagram Link Scraper") gr.Markdown("Cari tautan postingan Instagram melalui Google Search berdasarkan target kata kunci, rentang waktu, dan jumlah halaman.") with gr.Row(): with gr.Column(scale=1): input_target = gr.Textbox(label="Target / Kata Kunci", placeholder="Contoh: Pengembang Aplikasi", value="Pengembang Aplikasi") input_waktu = gr.Dropdown( label="Rentang Waktu Pencarian", choices=[("24 Jam Terakhir", "qdr:d"), ("1 Minggu Terakhir", "qdr:w"), ("1 Bulan Terakhir", "qdr:m"), ("Semua Waktu", "all")], value="qdr:d" ) input_halaman = gr.Slider(label="Maksimal Halaman Pencarian", minimum=1, maximum=35, step=1, value=5) btn_run = gr.Button("Mulai Scraping", variant="primary") with gr.Column(scale=2): output_logs = gr.TextArea(label="Proses Log / Status", interactive=False, lines=6) output_file = gr.File(label="Unduh Hasil (.txt)") output_links = gr.TextArea(label="Hasil Tautan Instagram", interactive=False, lines=10) btn_run.click( fn=scraper_interface, inputs=[input_target, input_waktu, input_halaman], outputs=[output_logs, output_links, output_file] ) if __name__ == "__main__": demo.launch()