# 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()