Spaces:
Sleeping
Sleeping
| 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() |