diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df99a2c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +chromedriver* +geckodriver* diff --git a/README.md b/README.md index 54ded0e..f6ff1f4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ # Whole Foods and Amazon Fresh Delivery Slot Automated Script -Yes, amid COVID-19 trying to get Whole Foods and Amazon Fresh delivery slots can get cumbersome. To free you off the constant hassle of checking for slots (and almost never finding one), this automated script can notify you (yes notifies you verbally, so you can go about your tasks) of when new delivery slots open. +Yes, amid COVID-19 trying to get Whole Foods and Amazon Fresh delivery slots can get cumbersome. To free you of the constant hassle of checking for slots (and almost never finding one), this automated script can notify you (yes notifies you verbally, so you can go about your tasks) of when new delivery slots open. ## Usage: @@ -17,8 +17,6 @@ Supports **MacOS, Linux, and Windows**. The script works on **Chrome** (```whole_foods_delivery_slot_chrome.py``` for Whole Foods) (```amazon_fresh_delivery_slot_chrome.py``` for Amazon Fresh) and **FireFox** (```whole_foods_delivery_slot_firefox.py```) for now. This does not support "Autobuy feature". -Note, use the ```whole_foods_delivery_windows.py``` for Windows. Also, only for this OS, you'll have to install an additional package ```winsound``` - ### Autobuy feature: If you'd like the script to select the first available time, and proceed all the way through checkout, please use the ```whole_foods_delivery_autobuy.py```. @@ -70,19 +68,5 @@ _Note, I haven't written this blog, but I'd like to thank the person (don't who # FAQ ## say is not a recognized command -If say is not native to your OS. Please try using winsound. Comment/delete the code in the script that has `os.system('say...')` and incorporate the following snippet: - -`import winsound` - -`duration = 1000` - -`freq = 440` - -~~os.system('say ...')~~ - -`winsound.Beep(freq, duration)` - -As an example, you can look at any of the Windows scripts. Also, there are certain issues in this repository revolving around this issue that have been solved. Please feel to check them out too. -Meanwhile, if you'd not like to edit, there is a PR: https://github.com/pcomputo/Whole-Foods-Delivery-Slot/pull/32, you can try to switch to that branch to get audible notifications. I'm in the testing phasing of this PR. - +This fork uses the [pyttsx3](https://pypi.org/project/pyttsx3/) module, so you shouldn't get a "say is not a recognized command" error as long as [pyttsx3 supports your platform and installed TTS libraries](https://pyttsx3.readthedocs.io/en/latest/support.html). diff --git a/amazon_fresh_delivery_slot_chrome.py b/amazon_fresh_delivery_slot_chrome.py index 48630d0..e03bd4a 100644 --- a/amazon_fresh_delivery_slot_chrome.py +++ b/amazon_fresh_delivery_slot_chrome.py @@ -6,7 +6,13 @@ import sys import time import os +import pyttsx3 +engine = pyttsx3.init() # object creation + +def sayIt(textToSay): + engine.say(textToSay) + engine.runAndWait() def getWFSlot(productUrl): headers = { @@ -34,12 +40,12 @@ def getWFSlot(productUrl): pass else: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) except NoSuchElementException: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) @@ -48,7 +54,7 @@ def getWFSlot(productUrl): open_slots = soup.find('div', class_ ='orderSlotExists').text() if open_slots != "false": print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) except AttributeError: @@ -59,6 +65,7 @@ def getWFSlot(productUrl): +sayIt("Starting") getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') - +engine.stop() diff --git a/requirements.txt b/requirements.txt index e61fa79..24813be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ chromedriver-binary==81.0.4044.69.0 selenium==3.141.0 urllib3==1.25.8 webdriver-manager==2.3.0 +pyttsx3==2.7 diff --git a/whole_foods_delivery_autobuy.py b/whole_foods_delivery_autobuy.py index 7a10936..9a94f39 100644 --- a/whole_foods_delivery_autobuy.py +++ b/whole_foods_delivery_autobuy.py @@ -9,7 +9,13 @@ import sys import time import os +import pyttsx3 +engine = pyttsx3.init() # object creation + +def sayIt(textToSay): + engine.say(textToSay) + engine.runAndWait() def autoCheckout(driver): driver = driver @@ -62,11 +68,9 @@ def autoCheckout(driver): review_select_continue.click() print("Order reviewed") - print("Order Placed!") - os.system('say "Order Placed!"') + sayIt("Order Placed!") except NoSuchElementException: - print("Found a slot but it got taken, run script again.") - os.system('say "Found a slot but it got taken, run script again."') + sayIt("Found a slot but it got taken, run script again.") time.sleep(1400) def getWFSlot(productUrl): @@ -108,7 +112,7 @@ def getWFSlot(productUrl): for each_date in all_dates: if slot_opened_text not in each_date.text: print('SLOTS OPEN! 2') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False autoCheckout(driver) @@ -121,12 +125,14 @@ def getWFSlot(productUrl): print("NO SLOTS!") except AttributeError: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False autoCheckout(driver) -getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') +sayIt("Starting") +getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') +engine.stop() diff --git a/whole_foods_delivery_autobuy_windows.py b/whole_foods_delivery_autobuy_windows.py deleted file mode 100644 index d8ae385..0000000 --- a/whole_foods_delivery_autobuy_windows.py +++ /dev/null @@ -1,130 +0,0 @@ -import bs4 - -from selenium import webdriver -from selenium.common.exceptions import NoSuchElementException -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC -from selenium.webdriver.common.by import By - -import sys -import time -import os - -import winsound - - -def autoCheckout(driver): - driver = driver - duration = 1000 - freq = 440 - - time.sleep(4) - driver.execute_script("window.scrollTo(0, 200)") - try: - slot_select_button = driver.find_element_by_xpath('/html/body/div[5]/div[1]/div/div[2]/div/div/div/div/div[1]/div[4]/div[2]/div/div[3]/div/div/ul/li/span/span/div/div[2]/span/span/button') - slot_select_button.click() - print("Clicked open slot") - except NoSuchElementException: - slot_select_button = driver.find_element_by_xpath('/html/body/div[5]/div[1]/div/div[2]/div/div/div/div/div[1]/div[4]/div[2]/div/div[4]/div/div/ul/li/span/span/div/div[2]/span/span/button') - slot_select_button.click() - - slot_continue_button = driver.find_element_by_xpath('/html/body/div[5]/div[1]/div/div[2]/div/div/div/div/div[2]/div[3]/div/span/span/span/input') - slot_continue_button.click() - print("Selected slot and continued to next page") - - try: - time.sleep(6) - outofstock_select_continue = driver.find_element_by_xpath('/html/body/div[5]/div/form/div[25]/div/div/span/span/input') - outofstock_select_continue.click() - print("Passed out of stock") - except NoSuchElementException: - pass - - try: - time.sleep(6) - payment_select_continue = driver.find_element_by_xpath('/html/body/div[5]/div[1]/div[2]/div[2]/div[4]/div/form/div[3]/div[1]/div[2]/div/div/div/div[1]/span/span/input') - payment_select_continue.click() - print("Payment method selected") - - - time.sleep(6) - try: - review_select_continue = driver.find_element_by_xpath('/html/body/div[5]/div[1]/div[2]/form/div/div/div/div[2]/div/div[1]/div/div[1]/div/span/span/input') - review_select_continue.click() - print("Order reviewed") - except NoSuchElementException: - review_select_continue = driver.find_element_by_xpath('/html/body/div[5]/div[1]/div[2]/form/div/div/div/div[2]/div[2]/div/div[1]/span/span/input') - review_select_continue.click() - print("Order reviewed") - - print("Order Placed!") - winsound.Beep(freq, duration) - except NoSuchElementException: - print("Found a slot but it got taken, run script again.") - winsound.Beep(freq, duration) - time.sleep(1400) - -def getWFSlot(productUrl): - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', - } - duration = 1000 - freq = 440 - - driver = webdriver.Chrome() - driver.get(productUrl) - driver.maximize_window() - html = driver.page_source - soup = bs4.BeautifulSoup(html, "html.parser") - time.sleep(60) - no_open_slots = True - - while no_open_slots: - driver.refresh() - print("refreshed") - html = driver.page_source - soup = bs4.BeautifulSoup(html, "html.parser") - time.sleep(4) - - slot_patterns = ['Next available', '1-hour delivery windows', '2-hour delivery windows'] - try: - next_slot_text = str([x.text for x in soup.findAll('h4', class_ ='ufss-slotgroup-heading-text a-text-normal')]) - if any(next_slot_text in slot_pattern for slot_pattern in slot_patterns): - print('SLOTS OPEN!') - winsound.Beep(freq, duration) - no_open_slots = False - - autoCheckout(driver) - - except AttributeError: - pass - - try: - slot_opened_text = "Not available" - all_dates = soup.findAll("div", {"class": "ufss-date-select-toggle-text-availability"}) - for each_date in all_dates: - if slot_opened_text not in each_date.text: - print('SLOTS OPEN!') - winsound.Beep(freq, duration) - no_open_slots = False - autoCheckout(driver) - - except AttributeError: - pass - - try: - no_slot_pattern = 'No delivery windows available. New windows are released throughout the day.' - if no_slot_pattern == soup.find('h4', class_ ='a-alert-heading').text: - print("NO SLOTS!") - except AttributeError: - print('SLOTS OPEN!') - winsound.Beep(freq, duration) - no_open_slots = False - - autoCheckout(driver) - - - -getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') - - diff --git a/whole_foods_delivery_slot_REDUNDANT.py b/whole_foods_delivery_slot_REDUNDANT.py index ee2fc15..139269c 100644 --- a/whole_foods_delivery_slot_REDUNDANT.py +++ b/whole_foods_delivery_slot_REDUNDANT.py @@ -5,7 +5,13 @@ import sys import time import os +import pyttsx3 +engine = pyttsx3.init() # object creation + +def sayIt(textToSay): + engine.say(textToSay) + engine.runAndWait() def getWFSlot(productUrl): headers = { @@ -31,7 +37,7 @@ def getWFSlot(productUrl): next_slot_text = soup.find('h4', class_ ='ufss-slotgroup-heading-text a-text-normal').text if slot_pattern in next_slot_text: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) except AttributeError: @@ -43,10 +49,11 @@ def getWFSlot(productUrl): print("NO SLOTS!") except AttributeError: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False +sayIt("Starting") getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') - +engine.stop() diff --git a/whole_foods_delivery_slot_chrome.py b/whole_foods_delivery_slot_chrome.py index f898550..c0bb6d5 100644 --- a/whole_foods_delivery_slot_chrome.py +++ b/whole_foods_delivery_slot_chrome.py @@ -5,7 +5,13 @@ import sys import time import os +import pyttsx3 +engine = pyttsx3.init() # object creation + +def sayIt(textToSay): + engine.say(textToSay) + engine.runAndWait() def getWFSlot(productUrl): headers = { @@ -13,6 +19,7 @@ def getWFSlot(productUrl): } driver = webdriver.Chrome() +# driver = webdriver.Chrome(executable_path=r"C:\Users\jason\Downloads\chromedriver_win32\chromedriver.exe") driver.get(productUrl) html = driver.page_source soup = bs4.BeautifulSoup(html, "html.parser") @@ -32,7 +39,7 @@ def getWFSlot(productUrl): for each_date in all_dates: if slot_opened_text not in each_date.text: print('SLOTS OPEN 2!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) except AttributeError: @@ -44,7 +51,7 @@ def getWFSlot(productUrl): print("NO SLOTS!") except AttributeError: print('SLOTS OPEN 3!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False @@ -53,7 +60,7 @@ def getWFSlot(productUrl): next_slot_text = str([x.text for x in soup.findAll('h4', class_ ='ufss-slotgroup-heading-text a-text-normal')]) if any(next_slot_text in slot_pattern for slot_pattern in slot_patterns): print('SLOTS OPEN!') - winsound.Beep(freq, duration) + sayIt("Slots for delivery opened!") no_open_slots = False autoCheckout(driver) @@ -62,6 +69,7 @@ def getWFSlot(productUrl): pass +sayIt("Starting") getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') - +engine.stop() diff --git a/whole_foods_delivery_slot_firefox.py b/whole_foods_delivery_slot_firefox.py index 790a3d5..eaddbc8 100644 --- a/whole_foods_delivery_slot_firefox.py +++ b/whole_foods_delivery_slot_firefox.py @@ -5,10 +5,18 @@ import sys import time import os +import winsound +import pyttsx3 +engine = pyttsx3.init() # object creation + +def sayIt(textToSay): + engine.say(textToSay) + engine.runAndWait() def getWFSlot(productUrl): driver = webdriver.Firefox() +# driver = webdriver.Firefox(executable_path=r"C:\Users\jason\Downloads\geckodriver-v0.26.0-win64\geckodriver.exe") driver.get(productUrl) html = driver.page_source soup = bs4.BeautifulSoup(html) @@ -27,7 +35,7 @@ def getWFSlot(productUrl): next_slot_text = soup.find('h4', class_ ='ufss-slotgroup-heading-text a-text-normal').text if any(next_slot_text in slot_pattern for slot_pattern in slot_patterns): print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) except AttributeError: @@ -39,7 +47,7 @@ def getWFSlot(productUrl): for each_date in all_dates: if slot_opened_text not in each_date.text: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False time.sleep(1400) except AttributeError: @@ -51,10 +59,10 @@ def getWFSlot(productUrl): print("NO SLOTS!") except AttributeError: print('SLOTS OPEN!') - os.system('say "Slots for delivery opened!"') + sayIt("Slots for delivery opened!") no_open_slots = False - +sayIt("Starting") getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') - +engine.stop() diff --git a/whole_foods_delivery_windows.py b/whole_foods_delivery_windows.py deleted file mode 100644 index e028e21..0000000 --- a/whole_foods_delivery_windows.py +++ /dev/null @@ -1,52 +0,0 @@ -import bs4 - -from selenium import webdriver - -import sys -import time - -import winsound - - -def getWFSlot(productUrl): - driver = webdriver.Chrome() - driver.get(productUrl) - html = driver.page_source - soup = bs4.BeautifulSoup(html) - time.sleep(60) - no_open_slots = True - - duration = 1000 - freq = 440 - - while no_open_slots: - driver.refresh() - print("refreshed") - html = driver.page_source - soup = bs4.BeautifulSoup(html) - time.sleep(4) - - slot_pattern = 'Next available' - try: - next_slot_text = soup.find('h4', class_ ='ufss-slotgroup-heading-text a-text-normal').text - if slot_pattern in next_slot_text: - print('SLOTS OPEN!') - winsound.Beep(freq, duration) - no_open_slots = False - time.sleep(1400) - except AttributeError: - continue - - try: - no_slot_pattern = 'No delivery windows available. New windows are released throughout the day.' - if no_slot_pattern == soup.find('h4', class_ ='a-alert-heading').text: - print("NO SLOTS!") - except AttributeError: - print('SLOTS OPEN!') - winsound.Beep(freq, duration) - no_open_slots = False - - -getWFSlot('https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1') - -