Merge pull request #3 from j4rj4r/fix-use-all-categories
Fix - Use all categories
This commit is contained in:
commit
f8192e0011
@ -1,7 +1,10 @@
|
|||||||
./data/logs/*.logs
|
./data/logs/*.logs
|
||||||
./data/data.db
|
./data/data.db
|
||||||
|
./data/profiles/prof_*
|
||||||
.vscode
|
.vscode
|
||||||
.gitignore
|
.gitignore
|
||||||
.idea/
|
.idea/
|
||||||
./__pycache__/
|
./__pycache__/
|
||||||
./GlobalExambBot/__pycache__/
|
./GlobalExambBot/__pycache__/
|
||||||
|
.git
|
||||||
|
*.md
|
||||||
@ -21,11 +21,11 @@ class Sheets:
|
|||||||
WebDriverWait(self.driver, 15).until(ec.visibility_of_element_located((By.XPATH, self.pagecard_xpath)))
|
WebDriverWait(self.driver, 15).until(ec.visibility_of_element_located((By.XPATH, self.pagecard_xpath)))
|
||||||
page_cards = self.driver.find_elements(by=By.XPATH, value=self.pagecard_xpath)
|
page_cards = self.driver.find_elements(by=By.XPATH, value=self.pagecard_xpath)
|
||||||
card_list = []
|
card_list = []
|
||||||
for card in page_cards :
|
for card in page_cards :
|
||||||
if not self.manageSheets.link_exist(card.get_attribute('href')):
|
if not self.manageSheets.link_exist(card.get_attribute('href')):
|
||||||
card_list.append(card)
|
card_list.append(card)
|
||||||
return card_list
|
return card_list
|
||||||
|
|
||||||
def watch(self, Sheets_el):
|
def watch(self, Sheets_el):
|
||||||
self.actions.move_to_element(Sheets_el).click(Sheets_el).perform()
|
self.actions.move_to_element(Sheets_el).click(Sheets_el).perform()
|
||||||
WebDriverWait(self.driver, 15).until(ec.visibility_of_element_located((By.XPATH, self.Sheetscard_xpath)))
|
WebDriverWait(self.driver, 15).until(ec.visibility_of_element_located((By.XPATH, self.Sheetscard_xpath)))
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from GlobalExamBot.helpers import TypeInField, element_exists, wait_between
|
from GlobalExamBot.helpers import TypeInField, element_exists, wait_between
|
||||||
from GlobalExamBot.Sheets import Sheets
|
from GlobalExamBot.Sheets import Sheets
|
||||||
@ -11,6 +12,7 @@ from selenium.webdriver.support.ui import WebDriverWait
|
|||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
|
||||||
class Bot:
|
class Bot:
|
||||||
|
|
||||||
def __init__(self, driver, action, configuration):
|
def __init__(self, driver, action, configuration):
|
||||||
self.driver = driver
|
self.driver = driver
|
||||||
self.actions = action
|
self.actions = action
|
||||||
@ -18,7 +20,7 @@ class Bot:
|
|||||||
self.email_xpath = '//input[@name="email"]'
|
self.email_xpath = '//input[@name="email"]'
|
||||||
self.password_xpath = '//input[@name="password"]'
|
self.password_xpath = '//input[@name="password"]'
|
||||||
self.index = 0
|
self.index = 0
|
||||||
self.scrollcount = 0
|
self.catindex = 0
|
||||||
self.categories = ['https://exam.global-exam.com/library/study-sheets/categories/grammar',
|
self.categories = ['https://exam.global-exam.com/library/study-sheets/categories/grammar',
|
||||||
'https://exam.global-exam.com/library/study-sheets/categories/language-functions',
|
'https://exam.global-exam.com/library/study-sheets/categories/language-functions',
|
||||||
'https://exam.global-exam.com/library/study-sheets/categories/vocabulary']
|
'https://exam.global-exam.com/library/study-sheets/categories/vocabulary']
|
||||||
@ -33,7 +35,7 @@ class Bot:
|
|||||||
password_el.send_keys(Keys.RETURN)
|
password_el.send_keys(Keys.RETURN)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
profile = f'prof_{self.configuration.username}'
|
profile = f'prof_{self.configuration.username}'
|
||||||
|
|
||||||
if not os.path.exists(f'./Profiles/{profile}'):
|
if not os.path.exists(f'./Profiles/{profile}'):
|
||||||
@ -49,20 +51,17 @@ class Bot:
|
|||||||
Sheets_action = Sheets(self.driver, self.actions, self.configuration)
|
Sheets_action = Sheets(self.driver, self.actions, self.configuration)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
self.driver.get('https://exam.global-exam.com/library/study-sheets/categories/grammar')
|
self.driver.get(self.categories[self.catindex])
|
||||||
Sheets_list = Sheets_action.search()
|
Sheets_list = Sheets_action.search()
|
||||||
if Sheets_list :
|
if Sheets_list :
|
||||||
logging.info(f'Sheets n°{ self.index }')
|
logging.info(f'Sheets n°{ self.index }')
|
||||||
Sheets_action.watch(Sheets_list[0])
|
Sheets_action.watch(Sheets_list[0])
|
||||||
self.index +=1
|
self.index +=1
|
||||||
self.scrollcount = 0
|
|
||||||
wait_between(3,10)
|
wait_between(3,10)
|
||||||
else:
|
else:
|
||||||
logging.info('All visible Sheets have already been read. Need to scroll down ...')
|
if self.catindex != len(self.categories) - 1 :
|
||||||
self.driver.execute_script(f"window.scrollTo(0, document.body.scrollHeight)")
|
logging.info('All visible Sheets have already been read. Use of the next category.')
|
||||||
self.scrollcount += 1
|
self.catindex += 1
|
||||||
wait_between(5,15)
|
else:
|
||||||
if self.scrollcount > 10:
|
logging.info('No category available.')
|
||||||
logging.info('End of page or network error.')
|
sys.exit(1)
|
||||||
self.scrollcount = 0
|
|
||||||
logging.info(self.driver.get_log('browser'))
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
def init():
|
def init():
|
||||||
global VERSION, APP_NAME
|
global VERSION, APP_NAME
|
||||||
APP_NAME = 'GlobalExamBot'
|
APP_NAME = 'GlobalExamBot'
|
||||||
VERSION = '1.0.0'
|
VERSION = '1.0.0'
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
class Database:
|
class Database:
|
||||||
|
"""
|
||||||
|
Database management
|
||||||
|
"""
|
||||||
def __init__(self, database_link='./data/data.db'):
|
def __init__(self, database_link='./data/data.db'):
|
||||||
"""
|
"""
|
||||||
Database constructor
|
Database constructor
|
||||||
@ -18,7 +21,7 @@ class Database:
|
|||||||
c.execute('''INSERT INTO sheet_links (link) VALUES (:link);''', (link,))
|
c.execute('''INSERT INTO sheet_links (link) VALUES (:link);''', (link,))
|
||||||
c.close()
|
c.close()
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
def link_exist(self, link):
|
def link_exist(self, link):
|
||||||
"""
|
"""
|
||||||
Returns true if the link exists in the database.
|
Returns true if the link exists in the database.
|
||||||
@ -45,4 +48,4 @@ def create_table_sheets():
|
|||||||
c.execute('''CREATE TABLE IF NOT EXISTS sheet_links
|
c.execute('''CREATE TABLE IF NOT EXISTS sheet_links
|
||||||
(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, link text);''')
|
(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, link text);''')
|
||||||
c.close()
|
c.close()
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|||||||
@ -3,6 +3,9 @@ from selenium.webdriver.common.action_chains import ActionChains
|
|||||||
from selenium.webdriver.chrome.options import Options
|
from selenium.webdriver.chrome.options import Options
|
||||||
|
|
||||||
class Driver:
|
class Driver:
|
||||||
|
"""
|
||||||
|
Browser management
|
||||||
|
"""
|
||||||
def __init__(self, profile):
|
def __init__(self, profile):
|
||||||
self.profile = profile
|
self.profile = profile
|
||||||
self.chrome_options = None
|
self.chrome_options = None
|
||||||
@ -10,6 +13,9 @@ class Driver:
|
|||||||
self.action = None
|
self.action = None
|
||||||
|
|
||||||
def setup(self, log_path='./data/logs/', headless=True):
|
def setup(self, log_path='./data/logs/', headless=True):
|
||||||
|
"""
|
||||||
|
Browser configuration
|
||||||
|
"""
|
||||||
self.chrome_options = Options()
|
self.chrome_options = Options()
|
||||||
|
|
||||||
# Anti bot detection
|
# Anti bot detection
|
||||||
@ -22,7 +28,7 @@ class Driver:
|
|||||||
|
|
||||||
# Maximize Browser
|
# Maximize Browser
|
||||||
self.chrome_options.add_argument('--start-maximized')
|
self.chrome_options.add_argument('--start-maximized')
|
||||||
|
|
||||||
# Headless Mode
|
# Headless Mode
|
||||||
if headless:
|
if headless:
|
||||||
self.chrome_options.add_argument('--headless')
|
self.chrome_options.add_argument('--headless')
|
||||||
@ -44,7 +50,6 @@ class Driver:
|
|||||||
self.chrome_options.add_argument("--disable-low-res-tiling")
|
self.chrome_options.add_argument("--disable-low-res-tiling")
|
||||||
self.chrome_options.add_argument("--log-level=3")
|
self.chrome_options.add_argument("--log-level=3")
|
||||||
self.chrome_options.add_argument("--silent")
|
self.chrome_options.add_argument("--silent")
|
||||||
|
|
||||||
|
|
||||||
# Disable save password
|
# Disable save password
|
||||||
prefs = {'credentials_enable_service': False,
|
prefs = {'credentials_enable_service': False,
|
||||||
@ -54,12 +59,12 @@ class Driver:
|
|||||||
# Set profile
|
# Set profile
|
||||||
self.chrome_options.add_argument(f'user-data-dir=./data/profiles/{self.profile}')
|
self.chrome_options.add_argument(f'user-data-dir=./data/profiles/{self.profile}')
|
||||||
|
|
||||||
self.driver = webdriver.Chrome(f'./ChromeDriver/chromedriver',options=self.chrome_options, service_args=[f'--log-path={log_path}ChromeDriver.log'])
|
self.driver = webdriver.Chrome('./ChromeDriver/chromedriver',options=self.chrome_options, service_args=[f'--log-path={log_path}ChromeDriver.log'])
|
||||||
self.action = ActionChains(self.driver)
|
self.action = ActionChains(self.driver)
|
||||||
return self.driver, self.action
|
return self.driver, self.action
|
||||||
|
|
||||||
def get_driver(self):
|
def get_driver(self):
|
||||||
return self.driver
|
return self.driver
|
||||||
|
|
||||||
def get_action(self):
|
def get_action(self):
|
||||||
return self.action
|
return self.action
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class Helpers:
|
|||||||
def load_configuration(self):
|
def load_configuration(self):
|
||||||
"""
|
"""
|
||||||
this method allows you to load arguments.
|
this method allows you to load arguments.
|
||||||
:return: args
|
:return: args
|
||||||
"""
|
"""
|
||||||
header()
|
header()
|
||||||
# Load all configuration variables
|
# Load all configuration variables
|
||||||
@ -50,10 +50,13 @@ class Helpers:
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
def logging_configuration(self, logging_level=logging.INFO, filename='data/logs/bot_globalexam.log'):
|
def logging_configuration(self, logging_level=logging.INFO, filename='data/logs/bot_globalexam.log'):
|
||||||
|
"""
|
||||||
|
Log configuration
|
||||||
|
"""
|
||||||
logging.basicConfig(filename=filename,
|
logging.basicConfig(filename=filename,
|
||||||
level=logging_level,
|
level=logging_level,
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s')
|
format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
root_logger = logging.getLogger()
|
root_logger = logging.getLogger()
|
||||||
root_logger.setLevel(logging_level)
|
root_logger.setLevel(logging_level)
|
||||||
|
|
||||||
@ -74,26 +77,26 @@ def header():
|
|||||||
logging.info('==\t version : ' + const.VERSION + ' \t==')
|
logging.info('==\t version : ' + const.VERSION + ' \t==')
|
||||||
logging.info('==\t=============================================================\t==')
|
logging.info('==\t=============================================================\t==')
|
||||||
|
|
||||||
def wait_between( min, max):
|
def wait_between( minimum, maximum):
|
||||||
"""
|
"""
|
||||||
Wait random time in second beetween min and max seconds, to have an not linear behavior and be more human.
|
Wait random time in second beetween min and max seconds,
|
||||||
|
to have an not linear behavior and be more human.
|
||||||
"""
|
"""
|
||||||
rand=uniform(min, max)
|
rand=uniform(minimum, maximum)
|
||||||
sleep(rand)
|
sleep(rand)
|
||||||
|
|
||||||
def TypeInField(element, xpath, myValue):
|
def TypeInField(element, xpath, value):
|
||||||
"""Type in a field"""
|
"""Type in a field"""
|
||||||
val = myValue
|
|
||||||
elem = element.find_element(by=By.XPATH, value=xpath)
|
elem = element.find_element(by=By.XPATH, value=xpath)
|
||||||
for i in range(len(val)):
|
for ele in enumerate(value):
|
||||||
elem.send_keys(val[i])
|
elem.send_keys(ele[1])
|
||||||
wait_between(0.2, 0.4)
|
wait_between(0.2, 0.4)
|
||||||
wait_between(0.4, 0.7)
|
wait_between(0.4, 0.7)
|
||||||
|
|
||||||
def element_exists(xpath, element, by=By.XPATH):
|
def element_exists(xpath, element, by=By.XPATH):
|
||||||
"""
|
"""
|
||||||
Check if an element exist
|
Check if an element exist
|
||||||
|
|
||||||
:return: Boolean
|
:return: Boolean
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@ -101,4 +104,4 @@ def element_exists(xpath, element, by=By.XPATH):
|
|||||||
element.find_element(by=by, value=xpath)
|
element.find_element(by=by, value=xpath)
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|||||||
8
main.py
8
main.py
@ -8,14 +8,14 @@ from GlobalExamBot.database import create_table_sheets
|
|||||||
|
|
||||||
from GlobalExamBot.driver import Driver
|
from GlobalExamBot.driver import Driver
|
||||||
from GlobalExamBot.bot import Bot
|
from GlobalExamBot.bot import Bot
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
helpers = Helpers()
|
helpers = Helpers()
|
||||||
|
|
||||||
# Configuration of the logging library
|
# Configuration of the logging library
|
||||||
helpers.logging_configuration()
|
helpers.logging_configuration()
|
||||||
|
|
||||||
# Load all configuration variables
|
# Load all configuration variables
|
||||||
config = helpers.load_configuration()
|
config = helpers.load_configuration()
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ def main():
|
|||||||
create_table_sheets()
|
create_table_sheets()
|
||||||
|
|
||||||
profile = f'prof_{config.username}'
|
profile = f'prof_{config.username}'
|
||||||
|
|
||||||
logging.info(f'Username : {config.username}')
|
logging.info(f'Username : {config.username}')
|
||||||
|
|
||||||
# Initialize driver and actions
|
# Initialize driver and actions
|
||||||
@ -46,4 +46,4 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user