Skip to content

Commit

Permalink
v1.7.1
Browse files Browse the repository at this point in the history
Added code sent verifier
  • Loading branch information
davidwickerhf committed Oct 29, 2020
1 parent d8149f2 commit 516d412
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 24 deletions.
51 changes: 32 additions & 19 deletions instaclient/client/instaclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(self, driver_type: int=CHROMEDRIVER, host:int=LOCAHOST):
chrome_options = webdriver.ChromeOptions()
chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
chrome_options.add_argument('--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1')
chrome_options.add_argument("--window-size=720,1280")
chrome_options.add_argument("--window-size=343,915")
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--no-sandbox")
Expand All @@ -46,7 +46,7 @@ def __init__(self, driver_type: int=CHROMEDRIVER, host:int=LOCAHOST):
# Running locally
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1')
chrome_options.add_argument("--window-size=720,1280")
chrome_options.add_argument("--window-size=343,915")
#chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--no-sandbox")
Expand Down Expand Up @@ -101,7 +101,7 @@ def login(self, username:str, password:str, check_user:bool=True):
try:
# Attempt Login
self.driver.get(ClientUrls.LOGIN_URL)
print('Got Login Page')
print('INSTACLIENT: Got Login Page')
# Detect Cookies Dialogue
try:
alert = self.__find_element(EC.element_to_be_clickable((By.XPATH, Paths.ACCEPT_COOKIES)), wait_time=4)
Expand All @@ -113,24 +113,24 @@ def login(self, username:str, password:str, check_user:bool=True):
username_input = self.__find_element(EC.presence_of_element_located((By.XPATH,Paths.USERNAME_INPUT)))
password_input = self.__find_element(EC.presence_of_element_located((By.XPATH,Paths.PASSWORD_INPUT)))
login_btn = self.__find_element(EC.presence_of_element_located((By.XPATH,Paths.LOGIN_BTN)))# login button xpath changes after text is entered, find first
print('Found elements')
print('INSTACLIENT: Found elements')
# Fill out form
print('Username: ', username, ' ', type(username))
print('INSTACLIENT: Username: ', username, ' ', type(username))
username_input.send_keys(username)
time.sleep(1)
print('Username: ', username, ' ', type(username))
print('INSTACLIENT: Username: ', username, ' ', type(username))
password_input.send_keys(password)
time.sleep(1)
print('Filled in form')
print('INSTACLIENT: Filled in form')
login_btn.click()
print('Sent form')
print('INSTACLIENT: form')
except Exception as error:
# User already logged in ?
result = self.check_status()
if not result:
raise error
else:
print('User already logged in?')
print('INSTACLIENT: User already logged in?')
return self.logged_in

# Detect correct Login
Expand All @@ -152,17 +152,27 @@ def login(self, username:str, password:str, check_user:bool=True):
# Detect Suspicious Login Attempt Dialogue
send_code = self.__check_existence(EC.presence_of_element_located((By.XPATH, Paths.SEND_CODE)), wait_time=3)
if send_code:
print('Suspicious Login Attempt.')
print('INSTACLIENT: Suspicious Login Attempt.')
send_code = self.__find_element(EC.presence_of_element_located((By.XPATH, Paths.SEND_CODE)), wait_time=4)
send_code.click()
print('Sent Security Code')
raise SuspisciousLoginAttemptError()
print('INSTACLIENT: Sent Security Code')
# Detect Error
alert = self.__check_existence(EC.presence_of_element_located((By.XPATH, Paths.ERROR_SENDING_CODE)), wait_time=4)
if alert:
# Error in sending code, send via email
email = self.__find_element(EC.presence_of_element_located((By.XPATH, Paths.SELECT_EMAIL_BTN)), wait_time=4)
email.click()
time.sleep(0.5)
send_code.click()
print('INSTACLIENT: Sending code via email')
raise SuspisciousLoginAttemptError(mode=SuspisciousLoginAttemptError.EMAIL)
raise SuspisciousLoginAttemptError(mode=SuspisciousLoginAttemptError.PHONE)

# Detect 2FS
scode_input = self.__check_existence(EC.presence_of_element_located((By.XPATH, Paths.VERIFICATION_CODE)), wait_time=3)
if scode_input:
# 2F Auth is enabled, request security code
print('2FA Required. Check Auth App')
print('INSTACLIENT: 2FA Required. Check Auth App')
raise VerificationCodeNecessary()
else:
self.logged_in = True
Expand All @@ -180,6 +190,14 @@ def login(self, username:str, password:str, check_user:bool=True):
return self.logged_in


@insta_method
def resend_security_code(self):
url = self.driver.current_url
if ClientUrls.SECURITY_CODE_URL in url:
print('INSTACLIENT: Resending code')
resend_btn = self.__find_element(EC.presence_of_element_located((By.XPATH, Paths.RESEND_CODE_BTN)), wait_time=4)
resend_btn.click()

@insta_method
def input_security_code(self, code:int or str):
code = str(code)
Expand All @@ -206,11 +224,6 @@ def input_security_code(self, code:int or str):
return self.logged_in







@insta_method
def input_verification_code(self, code:int or str):
"""
Expand Down Expand Up @@ -280,7 +293,7 @@ def unfollow_user(self, user:str):
unfollow_confirmation = self.__find_buttons('Unfollow')[0]
unfollow_confirmation.click()
else:
print('No {} buttons were found.'.format('Following'))
print('INSTACLIENT: No {} buttons were found.'.format('Following'))


@insta_method
Expand Down
3 changes: 3 additions & 0 deletions instaclient/client/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ class Paths:
SECURITY_CODE_INPUT = '//input[@name="security_code" or @class="_281Ls zyHYP"]'
INPUT_CODE_BTN = '//button[@class="_5f5mN jIbKX KUBKM yZn4P "]'
INVALID_CODE = '//div[@class="_3_2jD" and @id="form_error"]'
ERROR_SENDING_CODE = '//div[@class="_3_2jD" and @id="form_error"]//descendant::p'
RESEND_CODE_BTN = '//p[@class="GusmU t_gv9 "]//descendant::a'
SELECT_EMAIL_BTN = '//label[@class="UuB0U " and @for="choice_1"]//descendant::div'
# 2FA Verification
VERIFICATION_CODE = '//input[@name="verificationCode"]'
SECURITY_CODE_BTN = '//button[@class="sqdOP L3NKy y3zKF "]'
Expand Down
3 changes: 2 additions & 1 deletion instaclient/client/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ class ClientUrls:
NAV_USER='https://www.instagram.com/{}/'
SEARCH_TAGS='https://www.instagram.com/explore/tags/{}/'
FOLLOWERS_URL = 'https://www.instagram.com/{}/followers/'
HOME_URL = 'https://instagram.com/'
HOME_URL = 'https://instagram.com/'
SECURITY_CODE_URL = 'https://www.instagram.com/challenge/'
10 changes: 8 additions & 2 deletions instaclient/errors/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,15 @@ def __init__(self):


class SuspisciousLoginAttemptError(InstaClientError):
PHONE = 0
EMAIL = 1
"""Raised if security code is necessary to log in"""
def __init__(self):
super().__init__(message='The provided security code is invalid.')
def __init__(self, mode=PHONE):
self.mode = mode
super().__init__(message='Suspicious Login Attempt warning detected. Sending code mode: '.format(mode))

def __str__(self):
return f'{self.message}'


class InvalidSecurityCodeError(InstaClientError):
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
setup(
name = 'instaclient', # How you named your package folder (MyLib)
packages = find_packages(exclude=['tests']), # Chose the same as "name"
version = '1.6.5', # Start with a small number and increase it with every change you make
version = '1.7.1', # Start with a small number and increase it with every change you make
license='MIT', # Chose a license from here: https://help.github.com/articles/licensing-a-repository
description = 'Instagram client built with Python 3.8 and the Selenium package.',
long_description=README,
long_description_content_type="text/markdown",
author = 'David Wicker', # Type in your name
author_email = '[email protected]', # Type in your E-Mail
url = 'https://github.com/wickerdevs/py-instaclient', # Provide either the link to your github or to your website
download_url = 'https://github.com/wickerdevs/py-instaclient/archive/v1.6.5.tar.gz', # I explain this later on
download_url = 'https://github.com/wickerdevs/py-instaclient/archive/v1.7.1.tar.gz', # I explain this later on
keywords = ['INSTAGRAM', 'BOT', 'INSTAGRAM BOT', 'INSTAGRAM CLIENT'], # Keywords that define your package best
install_requires=[ # I get to this in a second
'selenium',
Expand Down

0 comments on commit 516d412

Please sign in to comment.