-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
auto_fill.py
226 lines (187 loc) · 8.56 KB
/
auto_fill.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
##############################################################################################
## Author: Ruan Pretorius ##
## GitHub: https://github.com/ruankie ##
## Last Updated: 13 June 2021 ##
## Disclaimer: This is for website testing and educational purposes only. ##
## This programme was intended for users to learn how the Selenium ##
## library works in the Python environment while exposing users to ##
## online photography competitions. The author will not be held ##
## responsible for any misuse of this code. ##
##############################################################################################
######################
## import libraries ##
######################
import time
import selenium
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.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from credentials import my_email_address, my_password
import numpy as np
#########################
## consants and config ##
#########################
CHROMEDRIVER_PATH = '/usr/bin/chromedriver' # location of driver
LOGIN_WAIT = 15 # max time to wait for login elements to load
IMPLICIT_WAIT = 5 # implicit wait time
LOW_WAIT_TIME_BETWEEN_CHALLENGES = 4.0 # lower limit of wait time between filling challenges
HIGH_WAIT_TIME_BETWEEN_CHALLENGES = 10.0 # upper limit of wait time between filling challenges
LOW_WAIT_TIME_BETWEEN_VOTES = 0.05 # lower limit of wait time between voting for photos
HIGH_WAIT_TIME_BETWEEN_VOTES = 0.5 # upper limit of wait time between voting for photos
FILL_THRESHOLD = 85.0 # only vote if exposure less than this
BOOST = True # whether ot not to boost where free boosts are available
HEADLESS = False # whether or not to run Chrome headless
if HEADLESS:
options = Options()
# options.headless = True
options.add_argument('--no-sandbox')
options.add_argument("--headless")
options.add_argument("user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36")
driver = webdriver.Chrome(CHROMEDRIVER_PATH, chrome_options=options) # load driver
else:
driver = webdriver.Chrome(CHROMEDRIVER_PATH) # load driver
######################
## helper functions ##
######################
def go_to_home_page():
'''
go to page GuruShots home page
'''
driver.get('https://gurushots.com/')
#driver.fullscreen_window()
# driver.set_window_size(1280, 1024)
def go_to_challenges_page():
'''
go to page that contains currently enrolled challenges
'''
driver.get('https://gurushots.com/challenges/my-challenges/current')
#driver.fullscreen_window()
# driver.set_window_size(1280, 1024)
def log_in(email, password):
'''
log into GuruShots account with specified email address and password
store your credentials inside the credentials.py file
'''
try:
print('logging in...')
# click login button
log_in_button = WebDriverWait(driver, LOGIN_WAIT).until(
EC.presence_of_element_located((By.XPATH, "//*[@ng-click='$ctrl.signin()']"))
)
log_in_button.click()
# send login credentials and hit enter to log in
email_field = WebDriverWait(driver, LOGIN_WAIT).until(
EC.presence_of_element_located((By.NAME, "email"))
)
email_field.send_keys(email)
password_field = WebDriverWait(driver, LOGIN_WAIT).until(
EC.presence_of_element_located((By.NAME, "password"))
)
password_field.send_keys(password)
password_field.send_keys(Keys.RETURN)
print('logged in.')
except Exception as e:
print('*** ERROR: ',e)
def fill_exposure(challenge_nb=0):
'''
fill exposure of specific challenge
'''
driver.implicitly_wait(IMPLICIT_WAIT)
vote_buttons = driver.find_elements("xpath", "//div[@ng-click='$ctrl.vote()']")
try:
# click on challenge vote button
vote_button = vote_buttons[challenge_nb]
driver.implicitly_wait(IMPLICIT_WAIT)
vote_button.click()
# click LET'S GO button
driver.implicitly_wait(IMPLICIT_WAIT)
lets_go_button = driver.find_element("xpath", "//div[text()=" + "\"LET'S GO\"" + "]")
lets_go_button.click()
# click 3 photos until exposure meter is full
last_photo_voted = 0
exposure_filled = False
while not exposure_filled:
# check if exposure full
driver.implicitly_wait(IMPLICIT_WAIT)
exposure_meter = driver.find_element("xpath", "//div[@class='modal-vote__exposure-meter__arrow']")
rotation = float(exposure_meter.get_attribute('style').split('rotate(')[1].split('deg)')[0])
if rotation < 90.0:
for i in range(last_photo_voted, last_photo_voted+3):
driver.implicitly_wait(IMPLICIT_WAIT)
photo = driver.find_element("xpath", f"//div[@id='vote-photo-{i}']")
time.sleep(np.round(np.random.uniform(low=0.05, high=0.5),2)) # wait between photo clicks for realism
photo.click()
last_photo_voted += 1
else:
print('\texposure full.')
exposure_filled = True
# click submit vote
driver.implicitly_wait(IMPLICIT_WAIT)
submit_vote_button = driver.find_element("xpath", "//span[text()='SUBMIT VOTE']")
submit_vote_button.click()
# close vote window
driver.implicitly_wait(IMPLICIT_WAIT)
done_button = driver.find_element("xpath", '//*[@id="gs-app-main"]/div/gs-modals/div/modal-vote/div[4]/div/div[2]/div[2]')
done_button.click()
except Exception as e:
print('\t*** ERROR: ',e)
go_to_challenges_page()
def boost_available():
'''
find all available boosts and boost most pupular image for given challenge
'''
try:
# find available boosts
driver.implicitly_wait(IMPLICIT_WAIT)
boosts_abailable = driver.find_elements("class", "challenge-action-button__content__boost-state__available")
nb_boosts_abailable = len(boosts_abailable)
print(f'{nb_boosts_abailable} available boosts found.')
# loop through available boosts and boost most popular image
for i, boost_button in enumerate(boosts_abailable):
print(f'\tboosting {i+1}/{nb_boosts_abailable}...')
# click boost
boost_button.click()
driver.implicitly_wait(IMPLICIT_WAIT)
# click on left-most picture
left_image = driver.find_element("xpath", "//md-dialog-content/div[2]/div[3]/div[1]")
left_image.click()
driver.implicitly_wait(IMPLICIT_WAIT)
except Exception as e:
print('\t*** ERROR: ',e)
go_to_challenges_page()
####################
## main execution ##
####################
if __name__ == '__main__':
# open home page
go_to_home_page()
# log in
log_in(my_email_address, my_password)
# check exposure meters of active challenges
print('looking for unfilled exposure meters...')
driver.implicitly_wait(IMPLICIT_WAIT)
exposure_meters = driver.find_elements("xpath", "//div[@class='c-challenges-item__exposure__meter__arrow']")
print(f'{len(exposure_meters)} active challenges found.')
# add challenge id to list if exposure meter below threshold
unfilled_meters_idxs = []
for e, exp_meter in enumerate(exposure_meters):
rotation = float(exp_meter.get_attribute('style').split('rotate(')[1].split('deg)')[0])
if rotation < FILL_THRESHOLD:
unfilled_meters_idxs.append(e)
# fill exposure meters
nb_vote_buttons = len(unfilled_meters_idxs)
for i, idx in enumerate(unfilled_meters_idxs):
time.sleep(np.random.randint(low=LOW_WAIT_TIME_BETWEEN_CHALLENGES, high=HIGH_WAIT_TIME_BETWEEN_CHALLENGES)) # to keep request frequency low and realism high
print(f'filling challenge {i+1}/{nb_vote_buttons}...')
fill_exposure(challenge_nb=idx)
# boost all available
if BOOST:
boost_available()
# wait for a second
time.sleep(1)
# close window
driver.quit()
print('done.')