Merhaba LinkedIn üzerinden şöyle bir isim soyisim mesleı alıcı bot yazdım ama bot çalışmıyor yardımcı olur musunuz




import sys
import subprocess
import threading
import time
import random
import os
import queue
import tkinter as tk
from tkinter import ttk

# ==========================================
# 1. OTOMATİK KÜTÜPHANE KONTROL VE KURULUMU
# ==========================================
def install_dependencies():
required_packages = ["selenium==4.18.1", "pandas", "openpyxl"]
missing_packages = []

try:
import selenium
except ImportError:
missing_packages.append("selenium==4.18.1")

try:
import pandas
except ImportError:
missing_packages.append("pandas")

try:
import openpyxl
except ImportError:
missing_packages.append("openpyxl")

if missing_packages:
print(f"Eksik kütüphaneler tespit edildi, kuruluyor: {missing_packages}")
print("Lütfen bekleyin (1-2 dakika sürebilir)...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", *missing_packages])
print("Kurulum tamamlandı. Uygulama başlatılıyor...")

install_dependencies()

import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException

# ==========================================
# 2. SELENIUM SCRAPER MOTORU
# ==========================================
class LinkedInScraperEngine:
def __init__(self, log_queue):
self.log_queue = log_queue
self.driver = None
self.wait = None
self.employees_data = set()

self.next_pause_target = random.randint(30, 70)
self.next_save_target = random.randint(25, 65)

if not os.path.exists("data"):
os.makedirs("data")

def log(self, message):
self.log_queue.put(message)

def initialize_driver(self):
if self.driver is not None:
self.log("Tarayıcı zaten açık.")
return

self.log("Tarayıcı başlatılıyor... Lütfen bekleyin.")
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExte nsion', False)
prefs = {"profile.default_content_setting_values.notificat ions": 2}
options.add_experimental_option("prefs", prefs)

self.driver = webdriver.Chrome(options=options)
self.driver.execute_cdp_cmd("Page.addScriptToEvalu ateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
self.wait = WebDriverWait(self.driver, 15) # Bekleme süresi 15 saniyeye çıkarıldı
self.driver.get("https://www.linkedin.com/login")
self.log("Lütfen açılan tarayıcıda LinkedIn'e giriş yapın ve ardından arayüzden işlemleri seçin.")

def human_like_scroll(self, scroll_pauses=3):
try:
total_height = int(self.driver.execute_script("return document.body.scrollHeight"))
for i in range(1, scroll_pauses + 1):
scroll_to = int(total_height * (i / scroll_pauses))
self.driver.execute_script(f"window.scrollTo(0, {scroll_to});")
time.sleep(random.uniform(1.2, 2.5))
self.driver.execute_script("window.scrollBy(0, -300);")
time.sleep(random.uniform(1.0, 1.5))
except Exception as e:
self.log(f"Kaydırma sırasında uyarı: {e}")

def extract_name_parts(self, full_name):
if not full_name: return "", ""
clean_name = full_name.split('n')[0].strip()
parts = clean_name.split()
if len(parts) > 1:
return " ".join(parts[:-1]), parts[-1]
return clean_name, ""

def export_data_to_files(self, is_auto_save=False):
if not self.employees_data:
return

data_list = [{"Ad": emp[0], "Soyad": emp[1], "Sirket_ve_Unvan": emp[2]} for emp in self.employees_data]
df = pd.DataFrame(data_list)
df.drop_duplicates(subset=["Ad", "Soyad", "Sirket_ve_Unvan"], inplace=True)

excel_path = os.path.join("data", "linkedin_verileri.xlsx")
csv_path = os.path.join("data", "linkedin_verileri.csv")

df.to_excel(excel_path, index=False, engine='openpyxl')
df.to_csv(csv_path, index=False, encoding='utf-8-sig')

if not is_auto_save:
self.log(f"BAŞARILI! Toplam {len(df)} benzersiz kayıt dosyaya yazıldı.")
self.log(f"Dosya yolları:n{os.path.abspath(excel_path)}")

def check_anti_ban_and_save(self):
current_count = len(self.employees_data)

if current_count >= self.next_pause_target:
sleep_time = random.uniform(15.0, 20.0)
self.log(f"n--- RASTGELE DİNLENME MOLASI ---")
self.log(f"İnsan davranışı simüle ediliyor... {sleep_time:.1f} saniye bekleniyor.")
time.sleep(sleep_time)
self.next_pause_target = current_count + random.randint(30, 70)
self.log("Dinlenme bitti, okumaya devam ediliyor...n")

if current_count >= self.next_save_target:
self.log(f"n--- OTOMATİK ARA KAYIT ---")
self.log(f"Arka planda Excel'e kaydediliyor... (Toplam ulaşılan: {current_count} kişi)")
self.export_data_to_files(is_auto_save=True)
sleep_time = random.uniform(10.0, 20.0)
self.log(f"Kayıt sonrası {sleep_time:.1f} saniye dinleniliyor...")
time.sleep(sleep_time)
self.next_save_target = current_count + random.randint(25, 65)
self.log("Kayıt ve dinlenme tamamlandı, taramaya devam ediliyor...n")

def scrape_profile_and_sidebar(self):
if not self.driver:
self.log("HATA: Önce tarayıcıyı başlatmalısınız!")
return

self.log("Profil ve sağ panel taranıyor... Lütfen tarayıcıya dokunmayın.")
time.sleep(2) # Sayfanın ve DOM'un tam oturması için mutlak bekleme eklendi
added_count = 0

# Ana Profil (Daha esnek seçiciler ve WebDriverWait)
try:
self.wait.until(EC.presence_of_element_located((By .TAG_NAME, "h1")))
main_name = self.driver.find_element(By.TAG_NAME, "h1").text.strip()

try:
# 'text-body-medium.break-words' yerine daha geniş bir class
main_company = self.driver.find_element(By.CSS_SELECTOR, ".text-body-medium").text.strip()
except NoSuchElementException:
main_company = "Unvan/Şirket Bulunamadı"

f_name, l_name = self.extract_name_parts(main_name)
if f_name:
self.employees_data.add((f_name, l_name, main_company))
added_count += 1
self.log(f"Ana Profil Eklendi: {f_name} {l_name} | {main_company}")
except Exception as e:
self.log("Ana profil h1 etiketi bulunamadı. Sayfanın tam yüklendiğinden emin olun.")

self.human_like_scroll(scroll_pauses=4) # Yan panelin yüklenmesi için scroll

# Sağ Panel
try:
# Sadece 'aside' içindeki 'li' etiketlerini bul (En güvenli yöntem)
sidebar_elements = self.driver.find_elements(By.XPATH, "//aside//li")
for elem in sidebar_elements:
try:
# İsim etiketi için çoklu alternatif
name_elem = elem.find_element(By.CSS_SELECTOR, ".artdeco-entity-lockup__title, span[dir='ltr']")
name_text = name_elem.text.strip().split('n')[0]

try:
title_text = elem.find_element(By.CSS_SELECTOR, ".artdeco-entity-lockup__subtitle").text.strip()
except:
title_text = "Belirtilmemiş"

f_name, l_name = self.extract_name_parts(name_text)
# "LinkedIn Üyesi" veya reklam olabilecek girdileri engelle
if f_name and "LinkedIn" not in f_name:
before = len(self.employees_data)
self.employees_data.add((f_name, l_name, title_text))
if len(self.employees_data) > before:
added_count += 1
except NoSuchElementException:
continue

self.log(f"İşlem Tamam. Bu sayfadan toplam {added_count} yeni kişi eklendi.")
self.check_anti_ban_and_save()

except Exception as e:
self.log("Sağ panel taramasında veri bulunamadı veya panel yok.")

def scrape_company_people(self):
if not self.driver:
self.log("HATA: Önce tarayıcıyı başlatmalısınız!")
return

self.log("Şirket çalışanları taranıyor... Lütfen sayfaya müdahale etmeyin.")
time.sleep(2)

try:
self.wait.until(EC.presence_of_element_located((By .TAG_NAME, "h1")))
company_header = self.driver.find_element(By.TAG_NAME, "h1").text.strip()
except:
company_header = "Bilinmeyen Şirket"

# Şirket listesi sayfasında olduğumuzu teyit et
try:
self.wait.until(EC.presence_of_element_located((By .CSS_SELECTOR, ".artdeco-entity-lockup__title")))
except:
self.log("Uyarı: Ekranda çalışan kartı bulunamadı. Şirketin 'Kişiler' sekmesinde misiniz?")
return

last_height = self.driver.execute_script("return document.body.scrollHeight")
attempts = 0

while True:
try:
# Daha genel kart seçicileri
cards = self.driver.find_elements(By.CSS_SELECTOR, "li .artdeco-entity-lockup, .org-people-profile-card")
initial_count = len(self.employees_data)

for card in cards:
try:
name_text = card.find_element(By.CSS_SELECTOR, ".artdeco-entity-lockup__title, span[dir='ltr']").text.strip()
try:
subtitle_text = card.find_element(By.CSS_SELECTOR, ".artdeco-entity-lockup__subtitle").text.strip()
except:
subtitle_text = company_header

f_name, l_name = self.extract_name_parts(name_text)
if f_name and "LinkedIn" not in f_name:
self.employees_data.add((f_name, l_name, subtitle_text))
except NoSuchElementException:
continue

new_count = len(self.employees_data)

if new_count == initial_count:
attempts += 1
else:
attempts = 0
self.log(f"Tarama devam ediyor... Anlık toplam kişi: {new_count}")

self.check_anti_ban_and_save()

if attempts >= 3:
self.log("Listenin sonuna gelindi veya yeni veri yüklenmiyor. Tarama bitti.")
break

self.human_like_scroll(scroll_pauses=2)
new_height = self.driver.execute_script("return document.body.scrollHeight")

if new_height == last_height:
attempts += 1
else:
last_height = new_height

except Exception as e:
self.log(f"Tarama sırasında bir hata oluştu: {e}")
break

def export_and_close(self):
if not self.employees_data:
self.log("Dışa aktarılacak veri bulunamadı. Tarayıcı kapatılıyor.")
else:
self.log("Tüm işlemler bitti. Final kayıtlar Excel ve CSV'ye işleniyor...")
self.export_data_to_files(is_auto_save=False)

if self.driver:
self.driver.quit()
self.driver = None
self.log("Tarayıcı güvenli bir şekilde kapatıldı.")

# ==========================================
# 3. KULLANICI ARAYÜZÜ (GUI)
# ==========================================
class LinkedInScraperGUI:
def __init__(self, root):
self.root = root
self.root.title("LinkedIn Bot & Ağ Gezgini")
self.root.geometry("650x550")
self.root.configure(padx=20, pady=20)

self.log_queue = queue.Queue()
self.scraper = LinkedInScraperEngine(self.log_queue)

self.create_widgets()
self.root.after(100, self.process_log_queue)

def create_widgets(self):
info_label = ttk.Label(self.root, text="LinkedIn Veri Çekme Otomasyonu", font=("Arial", 14, "bold"))
info_label.pack(pady=(0, 15))

btn_frame = ttk.Frame(self.root)
btn_frame.pack(fill=tk.X, pady=10)

self.btn_start = ttk.Button(btn_frame, text="1. Tarayıcıyı Başlat ve Giriş Yap", command=self.start_browser_thread)
self.btn_start.pack(fill=tk.X, pady=5)

self.btn_profile = ttk.Button(btn_frame, text="2. Açık Olan Kişi Profilini ve Sağ Paneli Tara", command=self.scrape_profile_thread)
self.btn_profile.pack(fill=tk.X, pady=5)

self.btn_company = ttk.Button(btn_frame, text="3. Açık Olan Şirketin Çalışanlarını Tara", command=self.scrape_company_thread)
self.btn_company.pack(fill=tk.X, pady=5)

self.btn_export = ttk.Button(btn_frame, text="4. Verileri Kaydet ve Uygulamayı Kapat", command=self.export_thread)
self.btn_export.pack(fill=tk.X, pady=5)

log_label = ttk.Label(self.root, text="İşlem Kayıtları (Log):")
log_label.pack(anchor=tk.W, pady=(15, 5))

self.log_text = tk.Text(self.root, height=12, state='disabled', bg="#f0f0f0", font=("Consolas", 9))
self.log_text.pack(fill=tk.BOTH, expand=True)

def write_log(self, message):
self.log_text.config(state='normal')
self.log_text.insert(tk.END, f"> {message}n")
self.log_text.see(tk.END)
self.log_text.config(state='disabled')

def process_log_queue(self):
try:
while True:
msg = self.log_queue.get_nowait()
self.write_log(msg)
except queue.Empty:
pass
finally:
self.root.after(100, self.process_log_queue)

def start_browser_thread(self):
threading.Thread(target=self.scraper.initialize_dr iver, daemon=True).start()

def scrape_profile_thread(self):
threading.Thread(target=self.scraper.scrape_profil e_and_sidebar, daemon=True).start()

def scrape_company_thread(self):
threading.Thread(target=self.scraper.scrape_compan y_people, daemon=True).start()

def export_thread(self):
def task():
self.scraper.export_and_close()
self.log_queue.put("Tüm işlemler bitti. Pencereyi kapatabilirsiniz.")
threading.Thread(target=task, daemon=True).start()

if __name__ == "__main__":
root = tk.Tk()

style = ttk.Style()
if "clam" in style.theme_names():
style.theme_use("clam")

app = LinkedInScraperGUI(root)

def on_closing():
if app.scraper.employees_data:
print("nPencere kapatıldı. Veriler otomatik olarak Excel'e yedekleniyor...")
try:
app.scraper.export_data_to_files(is_auto_save=Fals e)
print("Kayıt başarılı!")
except:
pass

if app.scraper.driver:
try:
app.scraper.driver.quit()
except:
pass

root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()