-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.py
1230 lines (996 loc) · 45.1 KB
/
bot.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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
███╗ ██╗██╗██╗ ██╗███████╗ ██████╗ ██████╗ ████████╗
████╗ ██║██║██║ ██╔╝██╔════╝ ██╔══██╗██╔═══██╗╚══██╔══╝
██╔██╗ ██║██║█████╔╝ █████╗ ██████╔╝██║ ██║ ██║
██║╚██╗██║██║██╔═██╗ ██╔══╝ ██╔══██╗██║ ██║ ██║
██║ ╚████║██║██║ ██╗███████╗ ██████╔╝╚██████╔╝ ██║
╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝
"""
#Coded by Mark Cuccarese
import sys
import os
import platform
import pause
import arrow
import webbrowser
import urllib3
import selenium
import time
import psutil
import signal
import subprocess
import versionCheck #import python versionCheck file
from os import path
from pyvirtualdisplay import Display
from urllib.request import urlopen
from datetime import datetime
from selenium import webdriver
from contextlib import suppress
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.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import StaleElementReferenceException
#Just a fancy exception
class WebpageNotFound(Exception):
"""
This will be raised if the webpage cannot be found
"""
#Display system version check info
def displaySysInfo(driver):
print("++++++++++++++++++++++++++++++++++++++++++++++++++")
print("Linux platform system: " + platform.system())
print("Linux platform version: " + platform.version())
print("Linux platform release: " + platform.release())
print("Selenium version: " + (selenium.__version__))
print("Python version: " + sys.version)
if 'browserVersion' in driver.capabilities:
print("Chrome version: " + driver.capabilities['browserVersion'])
else:
print("Chrome version: " + driver.capabilities['version'])
print("Chrome driver version: " + driver.capabilities['chrome']['chromedriverVersion'].split(' ')[0])
print("++++++++++++++++++++++++++++++++++++++++++++++++++\n")
#Check for appropriate time to exectute
def waitUntil(specified_dt):
#Setting a default refresh rate and updating current time
refresh = 10
current_dt = arrow.utcnow()
#Checking that we are not within 11 seconds of drop
while current_dt < specified_dt:
current_dt = arrow.utcnow()
remain = specified_dt - current_dt
#Shortening refresh rate if we are close
if (remain).seconds < 11:
refresh = .001
print("Waiting..." + str(remain))
time.sleep(refresh)
else:
print("Starting...")
return
#Prompt the user for config file
def printConfigPrompt():
print("""
Please place the a text file exactly as shown called config.txt
in the root directory of this script, delete any excess spaces
____________________________________________________________
time of drop in 24hrs EXAMPLE [15]
size needed EXAMPLE [7.5]
pre-release url EXAMPLE [https://www.nike.com/launch/t/air-force-1-lv8-pacific-blue]
quantity desired EXAMPLE [1]
email address EXAMPLE [YouKindaSus@gmail.com]
password EXAMPLE [DooDooNose1]
phone number EXAMPLE [4074074077]
card number EXAMPLE [2222 2222 2222 2222]
expiration date EXAMPLE [02/22]
cvv EXAMPLE [222]
zipcode EXAMPLE [22222]
name on card EXAMPLE [Martin Lawrence]
shipping address EXAMPLE [2222 Estern Way Orlando, Fl 32789]
____________________________________________________________
***Make sure your config file matches this EXACTLY***
***The shoe sizing of the program is should be given in US mens sizes (Does not support children sizes)***
***Make sure you have an active internet connection the entire time***
***To account for crashes, this program kills any chrome/chromium sessions once finished***\n
***Press enter whenever you are ready!***\n
""")
#Make sure internet is available
def checkinternet():
try:
#Setting up a pool to make a request to google
http = urllib3.PoolManager()
resp = http.request('GET', 'https://www.google.com/')
#For success we should have 200
if resp.status == 200:
return True
else:
return False
except:
return False
"""
#A second option for checking internet
def checkinternet2():
#get_network_conditions()
cond = {}
cond = webdrier.get_network_conditions()
if cond["offline"] is True:
time.sleep(2)
checkinternet2()
else:
return
#A third option for checking internet
def checkinternet3(driver):
if driver.capabilities['networkConnection'] == 'Disabled':
time.sleep(2)
checkInternet3(driver)
else:
return
"""
#Read input from file
def openfile():
try:
#Opening the file and reading into list
file = open("configfile.txt", "r+")
lines = file.read().split("\n")
#Switching them to lowercase
lines = [lines.lower() for x in lines]
finally:
#Closing the file
file.close()
return lines
#Verifies that the name of product matches URL
def compare(elem_name, url):
url = url.lower()
elem_name = elem_name.lower()
#Omitting everything except shoe name
string = url[30:len(url)]
#Remove dashes from string/url
new_string = string.replace('-', '')
#Remove spaces from elem_name
new_elem_name = elem_name.replace(' ', '')
#Extra check for edge cases
new_elem_name2 = new_elem_name[0:5]
#Success, the scraped name is in the url
if new_elem_name in new_string:
print("Website certainty accepted by name match")
return
#Some cases dictate that the name is not the same, will not exit but will raise notice
elif new_elem_name2 in new_string:
print("Website certainty accepted by name match")
return
else:
print("Website certainty challenged by name mismatch")
return
#This function is used to kill the Child PID in the event of an error
#To stop the formation of zombie processes
def kill():
#Get the PID
#driver.service.process #<- this is the popen instance for the chroemdriver
#Cpid = psutil.Process(driver.service.process.pid)
#print(Cpid.children(recursive=False))
print("\nChecking for sleeping/zombie chromium sessions to kill\n")
#Loop through process table
for process in psutil.process_iter():
#Check for any zombie or sleeping chromium processes
if process.name() == 'chromium': #and process.status() == 'zombie':
#Attemp to kill zombie processes
print("\tFound zombie chromium to kill: " + str(process.ppid()))
try:
os.kill(int(process.ppid()), signal.SIGTERM)
continue
except:
print("Failed to kill chromium process\n")
driver.quit()
quit()
print("Checking for sleeping/zombie google-chrome sessions to kill\n")
#Loop through the process table
for process in psutil.process_iter():
#Check for any zombie or sleeping chrome processes
if process.name() == 'chrome':
print("\tFound google chrome process to kill: " + str(process.ppid()))
try:
os.kill(int(process.ppid()), signal.SIGTERM)
continue
except:
print("Failed to kill google-chrome process\n")
driver.quit()
quit()
return
#Takes the sizes and determines type
def tellType(driver):
#This will get the UL list of sizes
resultSet = driver.find_element_by_css_selector(".size-layout")
#This list hold our list for iteration of individual sizes
options = resultSet.find_elements_by_tag_name("li")
#Setting our sizes into the list
for option in options:
sizeList.append(option.text)
#We are going to use the first size option present on the page to evaluate
string = sizeList[0]
#If the string starts with a number
if string[0].isdigit():
#Check to see if the sizing is youths [5]
if string.find('Y') != -1:
sizeType = 5
#Adults [1]
else:
sizeType = 1
#If this string starts with M and the next char is a space [2]
elif string[0] == 'M' and string[1] == ' ':
sizeType = 2
#elis if this string starts with W and the next char is a space [3]
elif string[0] == 'W' and string[1] == ' ':
sizeType = 3
#If the string starts with XXS S M L {No numbers} [4]
elif not any(char.isdigit() for char in string):
sizeType = 4
return sizeType
#This function has to filter all the sizes to only shoe available ones
def checkSize(driver, sizeME, sizeType):
#Clear the sizeList, because it currently holds ALL sizes
sizeList.clear()
#Retrieve only available sizes
resultSet = driver.find_element_by_css_selector(".size-layout")
options = resultSet.find_elements_by_tag_name("li")
print("\nOur Available list:")
#Take the option from the list and check avail
for option in options:
#If the option is available, place it into the list
if(option.get_attribute("data-qa") == 'size-available'):
print(option.text)
print("\t")
sizeList.append(option.text)
print("++++++++++++++++++++++++++\n")
sizeME = str(sizeME)
#Verify that we can find our size in the list
if sizeME in sizeList:
print("Desired size: " + sizeME + " is available!")
return True
print("Could not find size {0} in list!\n".format(sizeME))
return False
#Function will convert the size taken from config into the size style used on the site
def stringMagic(driver, temp, sizeType):
#Cheeky way of using lists in a dictionary
dictionary = {}
dictionary["XXS"] = [1, 1.5, 2]
dictionary["XS"] = [2.5, 3]
dictionary["S"] = [3.5, 4, 4.5, 5, 5.5]
dictionary["M"] = [6, 6.5, 7, 7.5, 8]
dictionary["L"] = [8.5, 9, 9.5, 10, 10.5]
dictionary["XL"] = [11, 11.5, 12, 12.5, 13]
dictionary["XXL"] = [13.5, 14, 14.5, 15.5]
tempWomens1 = float(temp) + 1.5
tempWomens2 = float(temp) - 1.5
#If temp is a float, the second value must be int
if temp.find(".") != -1:
temp = str(temp)
tempWomens1 = int(tempWomens1)
tempWomens2 = int(tempWomens2)
#If temp is an int, the second value must be a float
else:
temp = int(temp)
tempWomens1 = str(tempWomens1)
tempWomens2 = str(tempWomens2)
#If type int just return otherwise convert singular string to type and return
if sizeType > 1:
#The case where M X / W X
if sizeType == 2:
string = ("M " + str(temp) + " / W " + str(tempWomens1))
return string
#The case where W X / M X
elif sizeType == 3:
string = ("W " + str(temp) + " / M " + str(tempWomens2))
return string
#The case were XXS S M L XL
elif sizeType == 4:
#Breaking up the keys and values
key_list = list(dictionary.keys())
val_list = list(dictionary.values())
#Sorting the key by the value index
position = val_list.index(temp)
size = key_list[position]
return size
#The case we have a YOUTHS shoe
elif sizeType == 5:
youths = str(temp) + "Y"
return youths
#The case where the value is simplly an int
else:
return temp
#Determine if the user wants a different shoe size
def ask(question):
#Present the question
reply = (input(question)).lower().strip()
if reply[0] == 'y':
return True
elif reply[0] == 'n':
return False
else:
return ask("Please enter either y or n dummy: ")
#Make sure that size elements are present!
def checkAvail(driver):
#checkme = str(driver.find_element_by_css_selector('.mt9-sm').text)
#Check if the shoe is sold out
#if checkme == 'Sold Out':
# driver.quit()
# raise NoSuchElementException("Sold out :c\n")
#else:
# print("Shoe is available!\n")
# return
try:
#Wait until the size display is loaded
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, '.size-layout')))
if driver.find_element_by_css_selector('.size-layout').is_displayed():
return
except:
#If the display is not loaded the shoe must be sold out
raise NoSuchElementException("Sold out\n")
kill()
driver.quit()
quit()
#Method to take a screenshot of purchase page
def shotScreen(driver):
#Verify that the file doesnt already exist in root directory
if os.path.exists("ConfirmationPage.png") == True:
os.remove("ConfirmationPage.png")
try:
#Try and screenshot the confirmation
if driver.get_screenshot_as_file("ConfirmationPage.png") == True:
print("Screenshot of Order Confirmation has generated!\n")
return
else:
time.sleep(2)
driver.quit()
kill()
quit()
except:
time.sleep(2)
driver.quit()
kill()
quit()
#Open chrome application and execute operations
def openURL(url):
try:
#Uncommenting the following 2 lines will use PyVirtualDisplay module, in which case you will not see the window##########
#display = Display(visible = 0, size = (800, 800))
#display.start()
try:
#Load the browser instance
driver = webdriver.Chrome() #This assumes that you have proper permissions for chrome and the driver in root directory of folder, have it in /usr/bin/ also just to be safe
print("I have spawned the browser!\n")
except:
#The following takes effect in the instance that Chromedriver assuming google chrome has crashed##########
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(chrome_options=chrome_options)
###############################################
print("I have spawned the browser with additional arguments!\n")
#Show system information and versions
displaySysInfo(driver)
#Open the given url and wait for it to load
driver.get(url)
time.sleep(5)
except Exception as e:
print("Caught an error while opening browser\n" + e)
driver.quit()
quit()
#This will give us the name of the shoe and price
elem_name1 = driver.find_element_by_tag_name('h1').text
elem_name2 = driver.find_element_by_tag_name('h5').text
price = driver.find_element_by_css_selector('.headline-5').text
print("++++++++++++++++++++++++++++++++")
print("\t+++++ " + elem_name1 + " +++++")
print("\t+++++ " + elem_name2 + " +++++")
print("\t+++++ " + price + " +++++")
print("++++++++++++++++++++++++++++++++\n")
#Check the name of the shoe with the name in the url
#if compare(elem_name1, url) or compare(elem_name2, url) is True:
# print("Landed on correct web page! Continuing!\n")
#Check url and shoe name
compare(elem_name1, url)
compare(elem_name2, url)
#Check for error
try:
error1 = driver.find_element_by_css_selector(".text-color-error")
error2 = driver.find
if error.is_displayed():
print("HALTED no sizes displayed")
except:
pass
#Get the desired size from config file
sizeME = lines[1]
#Check to make sure that its not sold out and is buy able
checkAvail(driver)
#This func will analyze the sizing style used by the site to later adjust for the the user input
sizeType = tellType(driver)
#Changes the sizeME var into correct type for checking
sizeME = stringMagic(driver, sizeME, sizeType)
#This will input only available sizes into list and check availability
#certain = checkSize(driver, sizeME, sizeType)
#Raise an assertation error if the size is not available
assert checkSize(driver,sizeME,sizeType), "Size requested is not available"
#Begin the heading to cart process
try:
#Getting the elements for sizing
resultSet = driver.find_element_by_css_selector(".size-layout")
options = resultSet.find_elements_by_tag_name("li")
#Finding the correct shoe size and selecting
for option in options:
if(option.get_attribute("data-qa") == 'size-available'):
if option.text == sizeME:
option.click()
print("Selected size!")
break
#Clicking the "Add to cart"
Add2Cart = driver.find_element_by_css_selector(".ncss-btn-primary-dark").click()
print("Added size " + sizeME + " to cart without error!\n")
#Failure to select a size
except:
try:
time.sleep(2)
#Failed to select a size
obj = driver.find_element_by_css_selector('.test-error-message')
print("Error has been found: {0}\n -->Has been handled<--\n".format(obj.text))
#If we find an error we are going to handle with different elements
if obj.is_displayed():
resultSet = driver.find_element_by_css_selector(".border-light-grey")
options = resultSet.find_elements_by_tag_name("li")
#Finding the correct shoe size and selecting
for option in options:
if(option.get_attribute("data-qa") == 'size-available'):
if str(option.text) == str(sizeME):
option.click()
print("Selected size!")
break
#Selecting add to cart option
Add2Cart = driver.find_element_by_css_selector("[data-qa='add-to-cart']")
Add2Cart.click()
except:
print("Error inside of error!\n")
time.sleep(3)
try:
#Check to find out of the shopping cart popup is visible [timer of approx 8 seconds]
cartWindow = driver.find_element_by_css_selector(".cart-item-modal-content-container") #Window to proceed to checkout
checkoutButton = driver.find_element_by_xpath("/html/body/div[2]/div/div/div[2]/div/div/div/div/div[3]/button[2]") #Go to cart button
filledShoppingCart1 = driver.find_element_by_css_selector(".right-menu").text #Indicator of a filled cart
except:
time.sleep(1.5)
#Check to find out of the shopping cart popup is visible [timer of approx 8 seconds]
cartWindow = driver.find_element_by_css_selector(".cart-item-modal-content-container") #Window to proceed to checkout
checkoutButton = driver.find_element_by_xpath("/html/body/div[2]/div/div/div[2]/div/div/div/div/div[3]/button[2]") #Go to cart button
filledShoppingCart1 = driver.find_element_by_css_selector(".right-menu").text
try:
#While the checout window is visible
if cartWindow.is_displayed():
cart = checkoutButton.click()
print("+++++++++++++++++++++++++++++++++++++")
print("Heading to login page with: ")
#In the even that the 'head to cart option disappears'
except StaleElementReferenceException as Exception:
try:
#In the event that the window expires we can go to cart manually
if int(filledShoppingCart1) >= 1:
print("Heading to cart manually, rather than through the banner.\n")
shoppingCart = driver.find_element_by_css_selector(".shopping-cart-button")
shoppingCart.click()
#This is the cart page...now we wait a second and proceed
time.sleep(2)
goToCheckout = driver.find_element_by_xpath("/html//div[@id='react-root']//button[@class='css-1cv3jkg ezigbjr0']")
print(goToCheckout.text)
except:
#Need to add functionality to account for difference in proceedure
print("Unsupported functionality at the momment")
time.sleep(2)
#CHECK FOR INTERNET CONNECTION
#BETTER EXCEPTION AND ERROR CHECKING AND FIXXING
#CLEAN CODE COMMENTS
#CHECK FOR CONFIRMATION PAGE
#KNOWN BUG - SOME CASES WHEN ADDY IS ALREADY SAVED IN ACCOUNT,
#THE WEBSITE WILL AUTOMATICALLY SELECT CHEAPEST SHIPPING OPTION
#THE SCRIPT DOES NOT ACCOUNT FOR THIS SKIPPED STEP YET
#KNOWN BUG - IF THE "CHECKOUT BUTTON" DISAPPEARS, THE PROCESS TO CHECKOUT IS
#NOT SUPPORTED ATM
#errormsgCheck(driver):
#MORE THAN 1 "Sorry, you have reached the quantity limit. Please remove an item and try again." Resolution >cart> delete> reopen previous page>reselect
#GO TO CART AND REMOVE
#UNAVAILABLE "Sorry, the product you have selected is not available at this time." Resolution > Refresh the page
#CANT ADD "We were unable to load the product data at this time. Please refresh, or try again later." (.text-color-error)
#PRODUCT OUT OF STOCK <p class="error-code-msg mb4-sm">Sorry, one of the products in your bag is now out of stock. Please select another product or size.<br><span class="error-code ncss-base mb8-sm u-bold">[Code: B6CFCA37 ]</span></p>
#driver.delete_all_cookies()
#REFRESH PAGE
#ELEMENT NOT PRESENT
#CLICK THE CART ICON
#ELSE QUIT
#InvalidArgumentException
#NoSuchAttributeException
#NoSuchAttributeException
#TimeoutException
#ConnectionClosedException
#Want this to return the driver to main for continued use
return driver
#Function used to read and input all delivery information
def deliveryOptions(driver):
#Wait for form to load
try:
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, ('#shipping > div > div.ncss-container.pt5-sm'))))
except:
time.sleep(1)
try:
#Attemp to get element for later use
presentAddress = driver.find_element_by_css_selector('.label-extra')
except:
try:
presentAddress = driver.find_element_by_css_selector(".label-extra.ncss-label.pb2-lg.pb3-sm.pl4-sm.pr4-sm.pt2-lg.pt3-sm")
except:
pass
try:
#Entering name details from the card holder field
name = lines[10].split(" ")
firstname = driver.find_element_by_id('firstName')
firstname.click()
firstname.send_keys(name[0])
lastname = driver.find_element_by_id('lastName')
lastname.click()
lastname.send_keys(name[1])
#Entering the address details from config
addy = lines[11]
address = driver.find_element_by_id('search-address-input')
address.click()
address.send_keys(addy)
#Wait for the drop down to load
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, ('.suggestion-enter-done'))))
#Find the suggested address list and click it button.d-sm-b
suggestions = driver.find_element_by_css_selector('.suggestion-enter-done')
time.sleep(1)
#options = suggestions.find_elements_by_tag_name('li')
options = suggestions.find_elements_by_tag_name('button')
time.sleep(1)
#This is done becuase the webpage shores part of the address
#in one element and the other half in another
shortAddy = addy.replace(' ', '') #Cutting out spaces
x = len(shortAddy)//2
shortAddy = shortAddy[:x] #Cutting the string to remove state and zipcode
#Moving through address results
for option in options:
#We are going to remove all spaces and check for substring
testString = option.text
testString = testString.replace(' ', '')
#Checking for addy in the HTML
if shortAddy in testString != -1:
print("I have selected the correct address: " + str(addy))
option.click()
time.sleep(3)
#Entering email
email = lines[4]
emailAddress = driver.find_element_by_css_selector('#email')
emailAddress.click()
emailAddress.send_keys(email)
#Enter the phone number for updates
phone = lines[6]
phoneNumber = driver.find_element_by_id('phoneNumber')
phoneNumber.click()
phoneNumber.send_keys(phone)
#Click save and continue
savecont = driver.find_element_by_css_selector('#shipping > div > div.ncss-container.pt5-sm > form > div > div > div > div.ncss-col-sm-12.mt2-sm.va-sm-t.ta-sm-r > button')
savecont.click()
time.sleep(2)
print("Saved and proceeding to shipping options \n")
return None
except:
try:
#Just display and return to shipping function
if presentAddress.is_displayed():
print("Address information is already provided---")
print(presentAddress.text)
print("...........................................")
time.sleep(2)
return None
except:
print("We failed to enter address information\n and it doesnt appear to be present on the page :c\n")
print("This is a known bug. The site automatically enters the shipping speed thus breaking the bot.")
try:
#This is my attempt to avoid the bug by checking if the
#Checkout steps are only 1 and 2 meaning Delivery and Payment because the site lumped Shipping into category 1
print("Handling bug...")
skipShipping = driver.find_element_by_css_selector('#payment > header > h2')
if '2' in skipShipping.text:
return True
except:
time.sleep(2222222)
driver.quit()
kill()
quit()
#Small shipping selector function
def shippingOptions(driver):
#Vital that we wait
try:
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, ('div > .d-sm-tc.pb2-sm.pt2-sm.u-full-width > .ncss-label.pl10-sm.u-full-width'))))
except:
try:
time.sleep(1)
savecont = driver.find_element_by_css_selector('#shipping > div > div.ncss-container.pt5-sm > form > div > div > div > div.ncss-col-sm-12.mt2-sm.va-sm-t.ta-sm-r > button')
savecont.click()
except:
pass
#This will give us the list of shipping options
shipping = driver.find_elements_by_css_selector('div > .d-sm-tc.pb2-sm.pt2-sm.u-full-width > .ncss-label.pl10-sm.u-full-width')
print("Automatically proceeding with the cheapest shipping!")
#Goin through and clicking proceeding with the cheapest
for count, i in enumerate(shipping):
if count == 1:
print(i.text + " |")
print("----------------------------------------------------")
try:
#Attemp to proceed to payment information
time.sleep(2)
paymentButton = driver.find_element_by_css_selector('.continuePaymentBtn')
paymentButton.click()
except:
#If we failed used js to click button
print("Failure in continuing...trying alternate method")
time.sleep(2)
pio = WebDriverWait(driver, 4).until(EC.presence_of_element_located((By.CSS_SELECTOR, (".continuePaymentBtn"))))
driver.execute_script("arguments[0].click();", pio)
finally:
print("Saved and proceeding to payment details\n")
time.sleep(2)
return
def paymentOptions(driver, guest):
#Wait for the payment form to load
WebDriverWait(driver, 4).until(EC.presence_of_element_located((By.CSS_SELECTOR, ("[class='ncss-col-sm-12 bg-offwhite border-light-grey p5-sm mb3-sm'"))))
card = lines[6]
#Navigate to the iframe and wait for them to be clickable
cardey = WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,'//*[@id="payment"]/div/div[1]/div[2]/div[4]/div/div[1]/div[2]/iframe')))
cc = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="creditCardNumber"]')))
#Because the driver was sending keys too fast, the iframe was not recieving the full card number
billMe = driver.find_element_by_xpath('//*[@id="creditCardNumber"]')
#This single line executes JS and inputs card details. I had to use this
#because send_keys would mismatch order without fail somehow
driver.execute_script("arguments[0].value= '{0}';".format(card), billMe)
time.sleep(.5)
#Sending a single space so that the element formats itself
#thus making avaiable to order review button
billMe.send_keys(' ')
#Check here for card error message
try:
#Try to see if we got an error message
fail = driver.find_element_by_css_selector('.number-error')
#If error message is displayed, clear and retry
while fail.is_displayed():
print(fail.text)
billMe.clear()
#Try to reinput card details
try:
driver.execute_script("arguments[0].value= '{0}';".format(card), billMe)
time.sleep(.5)
billMe.send_keys(' ')
except:
fail = False
except:
print("Card input failed.\n")
expire = lines[7]
expire = expire.replace('/', '')
expireDate = driver.find_element_by_xpath('//*[@id="expirationDate"]')
expireDate.click()
expireDate.send_keys(expire)
#Check here for Expiration error message
secu = lines[8]
securityCVV = driver.find_element_by_xpath('//*[@id="cvNumber"]')
securityCVV.click()
securityCVV.send_keys(secu)
time.sleep(1)
print("Card details entered successfully: ")
print("|Card: {0}|Expiration: {1}|CVV: {2}|\n".format(card, expire, secu))
#Sending keys to body element to escape from CC iframe information
#For guest checkout, it lacks an option
if guest == True:
try:
#This will push us into order review
cum = driver.find_element_by_tag_name("body")
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.ENTER)
except:
print("ERROR -> shitty coder")
driver.quit()
kill()
quit()
#There is an additional option on creditial prompt
elif guest == False:
#This will push us into order review
try:
cum = driver.find_element_by_tag_name("body")
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.TAB)
cum.send_keys(Keys.ENTER)
except:
print("ERROR -> shitty coder")
driver.quit()
kill()
quit()
print("Saved and proceeding to order review\n")
time.sleep(2)
try:
#This is to verify we are at the correct screen before clicking place order
WebDriverWait(driver, 4).until(EC.presence_of_element_located((By.CSS_SELECTOR, ("#orderreview .text-color-white"))))
orderReviewMSG = driver.find_element_by_css_selector("#orderreview .text-color-white")
if orderReviewMSG.is_displayed():
print("Successfully arrived at confirmation page!")
else:
print("Problem. Not at Order Review Screen")
except:
print("HOLD IT ")
#This is to verify we are at the correct screen before clicking place order
WebDriverWait(driver, 4).until(EC.presence_of_element_located((By.CSS_SELECTOR, ("#orderreview"))))
orderReviewMSG = driver.find_element_by_css_selector("#orderreview")
if orderReviewMSG.is_displayed():
print("Successfully arrived at confirmation page!")
else:
print("Problem. Not at Order Review Screen")
time.sleep(5)
def verifyCheckout(driver):
print("Waiting to verify order has been placed ... ")
currentURL = driver.current_url
time.sleep(10)
expectedURL = 'https://www.nike.com/checkout#orderconfirmation'
currentURL = driver.current_url
#Looking for a error code
try:
tooManyReq = driver.find_element_by_xpath('//*[@id="checkout-wrapper"]/div/div/div[2]/div/div/div/div/div/div/p/span')
print("Checkout failed, due to {0} error -> too many purchases too quickly or with the same card".format(tooManyReq.text))
time.sleep(2222222)
return False
except:
pass
#Checking to see if we are taken to confirmation screen
if expectedURL != currentURL:
print("Expected url not met! There must be an error.")
return False
else:
print("Expect url met! - Additional check - ...")
try:
order = driver.find_element_by_css_selector('.lh24-sm.u-uppercase')
thanks = driver.find_element_by_css_selector('.fs34-md')
if order.is_displayed() or thanks.is_displayed():
print("Confirmed that we the order has been placed. Check screenshot")
return True
else:
print("That is strange. The expected URL is present but the expected elements are not ")
return True
except:
print("That is strange. The expected URL is present but the expected elements are not ")
return True
#This function will manager the cart and checkout process
def checkoutProcess(driver):
#Check the internet connection
#Retrive fields for login
email = lines[4]
password = lines[5]
#Reaping our current url for checking
siteCheck = False
expectedURL = 'https://www.nike.com/checkout'
expectedURL2 = 'https://www.nike.com/us/en/checkout'
currentURL = driver.current_url
#Enter login info
try:
#Halt until login form is pressent
WebDriverWait(driver, 4).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#tunnelPage')))
try:
#Find the email element
emailField = driver.find_element_by_name("emailAddress")
print("email: " + str(email))
emailField.send_keys(email)
except:
#Retry if not immediately present
print("Waiting for email field to load...")
time.sleep(1)
emailField = driver.find_element_by_name("emailAddress")
print("email: " + str(email))
emailField.send_keys(email)
try:
#Find the password element
passField = driver.find_element_by_name("password")
print("password: " + str(password))
print("+++++++++++++++++++++++++++++++++++++")
passField.send_keys(password)