Anlık Kelime Bulucu (Google Autocomplete API) Forum Ruhunu Diriltiyorum Konu 3
Anlık Kelime Bulucu (Google Autocomplete API): Siz arama kutusuna yazı yazdıkça (örneğin "araba" yazdığınızda), Google'da o kelimeden sonra en çok aranan popüler kelime gruplarını saniyesinde aşağıda listeler.
import customtkinter as ctk
import urllib.request
import json
import urllib.parse
from tkinter import filedialog
import threading
import concurrent.futures
def get_suggestions(query, target_count=50):
"""Google Autocomplete API ile girilen kelimeyi harflerle genişleterek daha fazla sonuç çeker."""
base_url = "https://suggestqueries.google.com/complete/search?client=firefox&q="
results = []
seen = set()
def add_results(items):
for item in items:
if item not in seen:
seen.add(item)
results.append(item)
# Önce tam kelime için temel sonuçları çekelim
try:
req = urllib.request.Request(base_url + urllib.parse.quote(query), headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=3) as response:
data = json.loads(response.read().decode())
add_results(data[1])
except Exception:
pass
if len(results) >= target_count:
return results[:target_count]
# Sonuçlar hedef sayıya (50) ulaşmadıysa kelimenin sonuna boşluk, a-z harfleri ve 0-9 rakamlarını
# teker teker ekleyerek farklı tamamlama isteklerini aynı anda çoklu parçacıkla (thread) gönderiyoruz
suffixes = [" "] + [chr(i) for i in range(ord('a'), ord('z')+1)] + [str(i) for i in range(10)]
def fetch_suffix(suffix):
url = base_url + urllib.parse.quote(f"{query} {suffix}")
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=3) as response:
return json.loads(response.read().decode())[1]
except Exception:
return []
# Eşzamanlı 10 istek ile olabildiğince hızlı sonuç üretiyoruz
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(fetch_suffix, suffix) for suffix in suffixes]
for future in concurrent.futures.as_completed(futures):
add_results(future.result())
if len(results) >= target_count:
break
return results[:target_count]
class GFinderApp(ctk.CTk):
def __init__(self):
super().__init__()
self.title("gfinder")
self.geometry("600x750")
self.minsize(500, 600)
# Arayüz ızgara ayarları
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(3, weight=1) # Sonuçlar çerçevesi dinamik büyüyecek
self.grid_rowconfigure(4, weight=0) # İşlem butonları
# Başlık ve Alt Başlık
self.title_label = ctk.CTkLabel(
self, text="gfinder", font=ctk.CTkFont(size=38, weight="bold"), text_color="#1DA1F2"
)
self.title_label.grid(row=0, column=0, padx=20, pady=(30, 5))
self.subtitle_label = ctk.CTkLabel(
self, text="Anlık Anahtar Kelime Bulucu", font=ctk.CTkFont(size=14), text_color="gray"
)
self.subtitle_label.grid(row=1, column=0, padx=20, pady=(0, 20))
# Arama Kutusu
self.search_var = ctk.StringVar()
self.search_var.trace_add("write", self.on_search_change)
self.search_entry = ctk.CTkEntry(
self,
textvariable=self.search_var,
placeholder_text="Bir kelime girin... (Örn: araba)",
font=ctk.CTkFont(size=16),
height=50,
corner_radius=25,
border_width=2,
border_color="#1DA1F2"
)
self.search_entry.grid(row=2, column=0, padx=40, pady=10, sticky="ew")
# Sonuçların Gösterileceği Çerçeve
self.results_frame = ctk.CTkScrollableFrame(self, corner_radius=15, fg_color="transparent")
self.results_frame.grid(row=3, column=0, padx=20, pady=(10, 10), sticky="nsew")
# İşlem Butonları Çerçevesi
self.action_frame = ctk.CTkFrame(self, fg_color="transparent")
self.action_frame.grid(row=4, column=0, padx=20, pady=(0, 20), sticky="ew")
self.select_all_btn = ctk.CTkButton(self.action_frame, text="Hepsini Seç / Bırak", command=self.select_all)
self.select_all_btn.pack(side="left", padx=10, expand=True, fill="x")
self.export_btn = ctk.CTkButton(self.action_frame, text="Seçili Olanları Dışa Aktar", command=self.export_results)
self.export_btn.pack(side="right", padx=10, expand=True, fill="x")
self.checkboxes = []
self.debounce_timer = None
# Uygulama açıldığında her zaman temiz bir başlangıç
self.search_var.set("")
self.update_results([], "Arama bekleniyor...")
self.search_entry.focus()
def update_results(self, results, title="Sonuçlar"):
# Önceki sonuçları temizle
for widget in self.results_frame.winfo_children():
widget.destroy()
self.checkboxes.clear()
# Kategori/Durum başlığı
title_lbl = ctk.CTkLabel(
self.results_frame,
text=title,
font=ctk.CTkFont(size=18, weight="bold"),
text_color="#AAB8C2"
)
title_lbl.pack(pady=(5, 10), anchor="w", padx=10)
if not results:
if "bekle" not in title.lower():
lbl = ctk.CTkLabel(self.results_frame, text="Aramanıza uygun sonuç bulunamadı.", font=ctk.CTkFont(size=15))
lbl.pack(pady=10)
return
# Gelen sonuçları listele
for result in results:
if result == "Aranıyor...":
lbl = ctk.CTkLabel(self.results_frame, text=result, font=ctk.CTkFont(size=15))
lbl.pack(pady=10)
continue
# Her bir sonuç için kart (frame)
result_frame = ctk.CTkFrame(self.results_frame, fg_color=("gray85", "#2b2b2b"), corner_radius=10)
result_frame.pack(pady=5, padx=10, fill="x")
var = ctk.BooleanVar(value=False)
chk = ctk.CTkCheckBox(
result_frame,
text=result,
variable=var,
font=ctk.CTkFont(size=16),
border_width=2
)
chk.pack(pady=10, padx=15, anchor="w")
self.checkboxes.append((var, result))
def select_all(self):
if not self.checkboxes:
return
# Eğer hepsi seçiliyse seçimleri kaldır, aksi halde hepsini seç
all_selected = all(var.get() for var, _ in self.checkboxes)
for var, _ in self.checkboxes:
var.set(not all_selected)
def export_results(self):
# Seçili olanları bul
selected = [text for var, text in self.checkboxes if var.get()]
# Seçili yoksa hepsini dışa aktar (kullanıcı dostu)
if not selected:
selected = [text for var, text in self.checkboxes]
if not selected:
return
filepath = filedialog.asksaveasfilename(
defaultextension=".txt",
filetypes=[("Metin Belgesi", "*.txt"), ("Tüm Dosyalar", "*.*")],
title="Anahtar Kelimeleri Kaydet"
)
if filepath:
try:
with open(filepath, "w", encoding="utf-8") as f:
f.write("\n".join(selected))
except Exception as e:
print(f"Kaydetme hatası: {e}")
def on_search_change(self, *args):
"""Arama kutusuna her harf girildiğinde tetiklenir"""
if self.debounce_timer:
self.after_cancel(self.debounce_timer)
# Arama API'sine aşırı istek atmamak için 300ms gecikme ekliyoruz (Debounce)
self.debounce_timer = self.after(300, self.trigger_search)
def trigger_search(self):
query = self.search_var.get().strip()
if query:
self.update_results(["Aranıyor..."], f"🔍 '{query}' için popüler aramalar")
threading.Thread(target=self._fetch_suggestions_bg, args=(query,), daemon=True).start()
else:
self.update_results([], "Arama bekleniyor...")
def _fetch_suggestions_bg(self, query):
"""Kelime tamamlama isteklerini arkaplanda yükler"""
suggestions = get_suggestions(query)
# API yanıtı geldiğinde arama kutusundaki veri aynıysa güncelle
if self.search_var.get().strip() == query:
self.after(0, lambda: self.update_results(suggestions, f"🔍 '{query}' için popüler aramalar"))
if __name__ == "__main__":
# Modern tema ayarları
ctk.set_appearance_mode("dark") # Koyu tema
ctk.set_default_color_theme("blue")
app = GFinderApp()
app.mainloop()