• 11-08-2023, 19:47:19
    #1
    # Gerekli kütüphaneler ve modüllerin import edilmesi
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.action_chains import ActionChains
    from time import sleep
    import time
    import logging
    import sys
    import pyotp
    from selenium.common.exceptions import StaleElementReferenceException
    from firefox_setup import initialize_driver  # Firefox sürücüsünün başlatılması
    
    # Web sayfasındaki öğelerin XPath lokasyonlarını içeren bir sözlük (dizin)
    LOCATORS = {
        "cookie_accept": "//button[text()='Opsiyonel çerezleri reddet']",  # Çerezlerin kabul edilmesi düğmesi
        "cookie_text": "//*[text()='Bu tarayıcıda Instagram\'ın çerez kullanımına izin verilsin mi?']",  # Çerez metni
        "login_username_field": "//input[@name='username']",  # Kullanıcı adı giriş alanı
        "login_password_field": "//input[@name='password']",  # Şifre giriş alanı
        "new_dm_btn": "//div[@role= 'button'][.//div//*//*[text()='Yeni mesaj']]",  # Yeni mesaj düğmesi
        "dm_type_username": "//input[@placeholder='Ara...']",  # Kullanıcı adı arama alanı
        "dm_select_user": '//span/span/span[text()="{}"]',  # Kullanıcı adını seçmek için XPath
        "dm_user_not_found": "//span[text()='Hesap bulunamadı.']",  # Kullanıcı bulunamadı hatası metni
        "dm_start_chat_btn": "//div/div[text()='Sohbet' and @role='button']",  # Sohbet başlat düğmesi
        "dm_msg_field": "//div[@role='textbox' and @aria-label='Mesaj']",  # Mesaj giriş alanı
        "dm_notification_present": "//span[text()='Bildirimleri Aç']",  # Bildirimleri aç metni
        "dm_notification_disable": "//button[text()='Şimdi Değil']",  # Bildirimleri kapat düğmesi
        "dm_send_button": "//div[@role='button' and text()='Gönder']",  # Mesaj gönder düğmesi
        "dm_error_present": "//*[contains(text(), 'IGD mesaj gönderme hatası simgesi')]",  # Mesaj gönderme hatası simgesi
        "2f_screen_present": "//input[@aria-describedby='verificationCodeDescription' and @aria-label='Güvenlik Kodu']",  # İki faktörlü kimlik doğrulama ekranı
        "2f_entering_error": "//p[@id='twoFactorErrorAlert' and @role='alert']",  # İki faktörlü kimlik doğrulama hatası metni
        "check_dm_message_sent_to_user": "//div[@role='none']//div[@dir='auto' and @role='none']",  # Kullanıcıya gönderilen mesajın doğrulaması
        "login_error": "//p[@id='slfErrorAlert']"  # Giriş hatası metni
    }
    
    # Özel hata sınıfları tanımlamaları
    class WaitAndClickException(Exception):
        pass
    
    class WaitException(Exception):
        pass
    
    # Kullanıcı sınıfı
    class User:
        def __init__(self, username, password, token=False, debug=False, use_chrome=False, Name="Acc"):
            # Kullanıcı bilgileri ve seçenekleri
            self.username = username
            self.password = password
            self.two_factor_token = token
            self.name = Name
            self.cookies_dict = None
            self.is_logged = False
            self.debug = debug
            self.logger = self.__initialize_log()  # Loglama ayarlarının başlatılması
            self.driver = None
            self.wait = None
            self.use_chrome = use_chrome
    
        # Loglama ayarlarını yapılandıran metot
        def __initialize_log(self):
            logger = logging.getLogger(f"instagram_web {self.name} - {self.username}")
            if self.debug:
                logger.setLevel(logging.DEBUG)
            else:
                logger.setLevel(logging.INFO)
    
            stream_handler = logging.StreamHandler(sys.stdout)
            stream_handler.setLevel(logging.DEBUG)
    
            file_handler = logging.FileHandler(f'log/{self.name} - {self.username}.log')
            file_handler.setLevel(logging.DEBUG)
    
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
            stream_handler.setFormatter(formatter)
            file_handler.setFormatter(formatter)
    
            logger.addHandler(stream_handler)
            logger.addHandler(file_handler)
    
            return logger
    
        # WebDriver'ı başlatan metot
        def __initialize_driver(self, use_chrome=False):
            try:
                self.logger.debug('initialize_driver() çağrıldı, hata ayıklama: %s', self.debug)
                if use_chrome:
                    self.driver, self.wait = initialize_chrome_driver()
                else:
                    self.driver, self.wait = initialize_driver()
                self.__accept_cookie(self.driver)
                self.logger.debug("Sürücü başlatıldı")
            except:
                self.logger.exception("__initialize_driver")
    
        # İki faktörlü kimlik doğrulama kodunu üreten metot
        def __generate_2factor_code(self, token):
            totp = pyotp.TOTP(token)
            current_time = time.time()
            time_step = 30  # TOTP zaman adımı, genellikle 30 saniye
            remaining_time = time_step - (current_time % time_step)
    
            # Kodun geçerli olduğu süre 5 saniyeden azsa, bir sonraki kodu bekleyin
            if remaining_time < 4:
                time.sleep(remaining_time)
    
            new_code = totp.now()
            return new_code
    
        # Çerezleri kabul eden metot
        def __accept_cookie(self, driver):
            self.logger.debug(f"__accept_cookie() çağrıldı, sürücü: {driver}")
            try:
                driver.get('https://instagram.com/')
                try:
                    cookie_elem = self.wait.until(EC.presence_of_element_located((By.XPATH, LOCATORS["cookie_text"])))
                except:
                    self.logger.warning("Kabul edilecek çerez yok!")
                    return True
    
                if cookie_elem:
                    driver.find_element("xpath", LOCATORS["cookie_accept"]).click()
                    self.logger.debug("Çerez kabul edildi")
                    sleep(2)
    
            except:
                self.logger.exception("__accept_cookie")
    
        # İki faktörlü kimlik doğrulama işlemini gerçekleştiren metot
        def __two_factor(self):
            try:
                url = self.driver.current_url
                self.logger.debug("5 saniye içinde 2f ekranını kontrol ediyor")
                sleep(5)
                two_factor_token_field = self.wait.until(
                    EC.presence_of_element_located((By.XPATH, LOCATORS['2f_screen_present'])))
                two_factor_token_field.send_keys(self.__generate_2factor_code(self.two_factor_token))
                two_factor_token_field.send_keys(Keys.RETURN)
    
                if self.__is_element_present(LOCATORS['2f_entering_error'], 3):
                    self.logger.error("2f_entering_error")
                    sleep(5)
                    two_factor_token_field.send_keys(Keys.CONTROL, "a")  # Eski kodu sil
                    two_factor_token_field.send_keys(Keys.DELETE)
                    two_factor_token_field.send_keys(self.__generate_2factor_code(self.two_factor_token))
                    two_factor_token_field.send_keys(Keys.RETURN)
                    if self.__is_element_present(LOCATORS['2f_entering_error'], 3):
                        self.logger.error("İkinci 2f_entering_error, giriş yapılamıyor")
                        return "Giriş yapılamıyor"
    
                for i in range(10):
                    if self.driver.current_url != url:
                        return True
                    self.logger.debug("Kod girildikten sonra 5 saniye boyunca URL değişmedi")
                    sleep(1)
                return "Giriş yapılamıyor"
            except:
                self.logger.exception("two_factor() hatası")
                return "Giriş yapılamıyor"
    
        # Kullanıcı girişi işlemini gerçekleştiren metot
        def login(self):
            self.__initialize_driver(use_chrome=self.use_chrome)
            self.logger.debug(f"login() çağrıldı, kullanıcı adı: {self.username}, şifre: {self.password}")
            try:
                self.driver.get('https://instagram.com/accounts/login')
                username_field = self.wait.until(
                    EC.presence_of_element_located((By.XPATH, LOCATORS["login_username_field"])))
                password_field = self.driver.find_element("xpath", LOCATORS["login_password_field"])
                url = self.driver.current_url
                username_field.send_keys(self.username)
                password_field.send_keys(self.password)
                password_field.send_keys(Keys.RETURN)
                print("aaaaaaa")
                if self.__is_element_present(LOCATORS['login_error'], 5):
                    self.logger.error(f"Instagram'a giriş yaparken bir sorun oluştu. Lütfen tekrar deneyin.")
                    print("ddddddd")
                    return "Instagram'a giriş yaparken bir sorun oluştu. Lütfen tekrar deneyin."
                print("aaaadawdawdawaaaa")
    
                # Instagram'ın giriş yapmasını bekleyin
                while True:
                    if self.driver.current_url != url:
                        self.logger.debug(f"İki faktörlü kimlik doğrulama kodu: {self.two_factor_token}")
                        if self.two_factor_token:
                            self.logger.debug("İki faktörlü kimlik doğrulama etkin, giriş yapmaya çalışılıyor")
                            self.__two_factor()
    
                        self.driver.get("https://www.instagram.com/direct/inbox")
    
                        self.wait.until(
                            EC.presence_of_element_located((By.XPATH, LOCATORS["dm_notification_present"])))
                        notifications = self.driver.find_element("xpath", LOCATORS["dm_notification_disable"])
                        notifications.click()
    
                        self.logger.info(f"Giriş başarılı yapıldı")
                        self.is_logged = True
                        return True
                    sleep(1)
    
            except:
                self.logger.exception("login() hatası")
    
        # Belirtilen kullanıcının önerilerini almak için kullanılan metot
        def get_suggestions(self, username):
            def get_all_usernames():
                usernames = set()
                repeated_count = 0
                threshold = 5  # Gerektiğinde eşik değerini ayarlayın
    
                while True:
                    elements = self.wait.until(
                        EC.presence_of_all_elements_located((By.XPATH, '//a//div//span//div')))
                    old_len = len(usernames)
                    for el in elements:
                        try:
                            # Öğenin metnini al
                            text = el.text
    
                            # Kullanıcı adı "Doğrulandı" içeriyorsa atla
                            if 'Doğrulandı' in text:
                                continue
    
                            # Kullanıcı adını küme içine ekle
                            usernames.add(text)
                        except StaleElementReferenceException:
                            continue
    
                    if old_len == len(usernames):
                        repeated_count += 1
                        if repeated_count >= threshold:
                            break
                    else:
                        repeated_count = 0
    
                    # Daha fazla kullanıcı adını yüklemek için aşağı kaydır
                    self.driver.execute_script("arguments[0].scrollIntoView();", elements[-1])
                    time.sleep(1)  # Gerektiğinde uyku süresini ayarlayın
    
                return usernames
    
            # Kullanıcının önerilerini almak için kullanılan metot
            LOCATORS_SUGGESTIONS = {
                'page_unavailable': "//span[text()='Üzgünüz, bu sayfa mevcut değil.']",  # Sayfa mevcut değil hatası metni
                'suggest_button': "//div[@role='button']//div//*[local-name() = 'svg']",  # Önerileri göster düğmesi
                'see_all_button': "//a[@role='link']//span[@dir='auto' and text()='Tümünü Gör']",  # Tümünü gör düğmesi
                'similar_acc_presence': "//div[text()='Sizin İçin Öneriliyor']",  # Sizin için öneriliyor metni
                'err_unable_to_load': "//div[text()='Öneriler yüklenemedi.']",  # Öneriler yüklenemedi hatası metni
            }
    
            try:
                self.logger.debug(f"get_suggestions() çağrıldı, kullanıcı adı: {username}")
    
                self.driver.get(f'https://www.instagram.com/{username}')
                try:
                    self.__wait_and_click(LOCATORS_SUGGESTIONS['suggest_button'])
                except WaitAndClickException:
                    if self.__is_element_present(LOCATORS_SUGGESTIONS["page_unavailable"]):
                        self.logger.debug("Profil mevcut değil")
                        return "Profil mevcut değil"
                    self.logger.exception("AJAJ")
    
                if self.__is_element_present(LOCATORS_SUGGESTIONS['err_unable_to_load'], 3):
                    return 'Hesap kilitli'
    
                self.__wait_and_click(LOCATORS_SUGGESTIONS['see_all_button'])
    
                self.__wait(LOCATORS_SUGGESTIONS['similar_acc_presence'])
                return get_all_usernames()
    
            except WaitAndClickException as e:
                self.logger.error(f"get_suggestions() - İşlem durduruldu. Hata: {str(e)}")
                return False
            except WaitException as e:
                self.logger.error(f"get_suggestions() - İşlem durduruldu. Hata: {str(e)}")
                return False
    
        # WebDriver'ı kapatmak için kullanılan metot
        def __exit_driver(self):
            self.driver.quit()
    
        # Çerezleri almak için kullanılan metot
        def get_cookies(self, close_after=True):
            def transform_cookies(cookies):
                headers = {}
                cookie_str = ""
                for cookie in cookies:
                    cookie_str += cookie['name'] + "=" + cookie['value'] + "; "
                headers["Cookie"] = cookie_str[:-2]  # Son noktalı virgül ve boşluğu kaldırın
                headers["X-Ig-App-Id"] = "936619743392459"  # <---------------------
                return headers
    
            try:
                self.login()
                cookies = self.driver.get_cookies()
                cookies_dict = transform_cookies(cookies)
                if close_after:
                    self.__exit_driver()
    
                self.cookies_dict = cookies_dict
                return cookies_dict
            except:
                self.logger.exception("get_cookies")
    
        # Belirtilen XPath ile öğenin varlığını kontrol eden metot
        def __is_element_present(self, xpath, time_to_wait=0):
            wait = WebDriverWait(self.driver, time_to_wait)
            self.logger.debug(f"__is_element_present() çağrıldı, xpath: {xpath} bekleme süresi: {time_to_wait}")
    
            try:
                wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
                self.logger.debug("__is_element_present() True dönüyor")
                return True
            except:
                self.logger.debug("__is_element_present() False dönüyor")
                return False
    
        # Belirtilen XPath ile öğenin tıklanabilir olmasını bekleyen ve tıklayan metot
        def __wait_and_click(self, xpath, time=5):
            self.logger.debug(f'__wait_and_click() çağrıldı, xpath: {xpath}, süre: {time}')
            try:
                button = WebDriverWait(self.driver, time).until(EC.element_to_be_clickable((By.XPATH, xpath)))
                button.click()
                self.logger.debug(f"XPath {xpath} ile öğeye tıklandı")
            except Exception as e:
                self.logger.debug(f"XPath {xpath} ile öğeye tıklanamadı. Hata: {str(e)}")
                raise WaitAndClickException(f"Öğeye tıklanamadığı için işlem durduruldu: {xpath}") from e
    
        # Belirtilen XPath ile öğenin varlığını bekleyen ve öğeyi döndüren metot
        def __wait(self, xpath, time=5):
            self.logger.debug(f'__wait() çağrıldı, xpath: {xpath}, süre: {time}')
            try:
                return WebDriverWait(self.driver, time).until(EC.presence_of_element_located((By.XPATH, xpath)))
            except Exception as e:
                self.logger.debug(f"XPath {xpath} ile öğenin beklenmesinde hata. Hata: {str(e)}")
                raise WaitException(f"Öğe beklenemediği için işlem durduruldu: {xpath}") from e
    
        # Belirtilen kullanıcıya mesaj göndermek için kullanılan metot
        def send_msg(self, to_username, msg, check_dm_message=False):
            def check_dm_message_sent_to_user():
                return self.__is_element_present(LOCATORS['check_dm_message_sent_to_user'], 2)
    
            def check_if_freezed():
                return self.__is_element_present(LOCATORS["dm_error_present"], 3)
    
            try:
                self.logger.debug(f"send_msg() çağrıldı, parametreler: to_username: {to_username}, msg: {msg}")
    
                if not self.is_logged:
                    self.logger.debug("Hesap oturum açmamış. Giriş yapmaya çalışılıyor")
                    self.login()
    
                if not self.__is_element_present(LOCATORS["new_dm_btn"], 0):
                    self.driver.get("https://www.instagram.com/direct/")
    
                wait = WebDriverWait(self.driver, 5)
                new_dm_btn = wait.until(
                    EC.presence_of_element_located((By.XPATH, LOCATORS["new_dm_btn"])))  # Yeni mesaj düğmesi
    
                try:
                    new_dm_btn.click()
                except:
                    self.driver.get("https://www.instagram.com/direct/")
                    new_dm_btn = wait.until(
                        EC.presence_of_element_located((By.XPATH, LOCATORS["new_dm_btn"])))  # Yeni mesaj düğmesi
                    new_dm_btn.click()
    
                search_user_field = wait.until(
                    EC.presence_of_element_located((By.XPATH, LOCATORS["dm_type_username"])))
                search_user_field.send_keys(to_username)
    
                wait = WebDriverWait(self.driver, 10)
                username_path = LOCATORS["dm_select_user"].format(to_username)
                try:
                    username_element = wait.until(EC.presence_of_element_located((By.XPATH, username_path)))
                    username_element.click()
                except:
                    self.logger.error("Listeden kullanıcı seçilemedi")
                    return "Hesap bulunamadı."
    
                next_btn = wait.until(
                    EC.presence_of_element_located((By.XPATH, LOCATORS["dm_start_chat_btn"])))
                last_url = self.driver.current_url
    
                self.driver.execute_script("arguments[0].click();", next_btn)
    
                tries = 0
                changed = False
                while tries < 50:
                    sleep(0.5)
                    if last_url == self.driver.current_url:
                        tries += 1
                        continue
                    else:
                        changed = True
                        break
    
                if changed == False:
                    self.logger.error("Yeni URL'ye erişilemiyor")
                    return "URL sorunu"
    
                msg_field = wait.until(
                    EC.presence_of_element_located((By.XPATH, LOCATORS["dm_msg_field"])))
    
                if check_dm_message:
                    if check_dm_message_sent_to_user():
                        return 'zaten gönderildi'
    
                action = ActionChains(self.driver)
                action.move_to_element(msg_field)
                action.click()
                action.send_keys(msg)
                action.perform()
                send_btn = self.driver.find_element("xpath", LOCATORS["dm_send_button"])
                send_btn.click()
    
                if check_if_freezed() == True:
                    self.logger.warn("Hesap dondu")
                    return "donma"
                
                return "gönderildi"
    
            except Exception as e:
                self.logger.error(f"Mesaj gönderme hatası: {str(e)}")
                return False
    
        # Mesaj gönderme işlemini kontrol eden ve gerekirse yeniden deneyen metot
        def send_message_and_retry(self, to_username, msg):
            result = self.send_msg(to_username, msg, check_dm_message=True)
            retry = 0
    
            while result == "donma":
                self.logger.debug(f"Donma sorunu nedeniyle mesaj yeniden gönderiliyor. Deneme: {retry}")
                retry += 1
                if retry > 2:
                    self.logger.error("Mesaj donma sorunu nedeniyle 3 denemede başarısız oldu")
                    break
                self.driver.get("https://www.instagram.com/direct/inbox")
                result = self.send_msg(to_username, msg, check_dm_message=True)
    
            if result == 'gönderildi':
                self.logger.info(f"Mesaj başarıyla gönderildi: '{msg}'")
                return True
            elif result == 'zaten gönderildi':
                self.logger.info(f"Mesaj zaten bu kullanıcıya daha önce gönderildi: '{msg}'")
                return True
            else:
                self.logger.error(f"Mesaj gönderme işlemi başarısız oldu: '{msg}'")
                return False
    
        # Kullanıcı sınıfını temizlemek için kullanılan metot
        def cleanup(self):
            self.__exit_driver()
            self.logger.info("Kullanıcı örneği kapatıldı")
    
    # Kullanıcı nesnesinin oluşturulması ve kullanılması
    if __name__ == "__main__":
        user = User("kullanici_adi", "sifre", token="iki_faktor_token", debug=True)
        user.get_cookies()
        suggestions = user.get_suggestions("hedef_kullanici")
        if suggestions:
            for suggestion in suggestions:
                message = "Merhaba, sizi takip etmek istiyorum!"
                user.send_message_and_retry(suggestion, message)
        user.cleanup()
  • 11-08-2023, 19:57:35
    #2
    Kullanım videosu vs de olsa güzel olurdu hocam