Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Costco Bot #102

Open
andresej21 opened this issue Mar 31, 2021 · 0 comments
Open

Costco Bot #102

andresej21 opened this issue Mar 31, 2021 · 0 comments
Assignees
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed

Comments

@andresej21
Copy link

andresej21 commented Mar 31, 2021

Hi could a Costco Bot be added? I'm very new to python and started trying to frankenstein some of this using existing bots, but havent been able to add the username/password to the UI to be able to test it.

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait as wait
from webdriver_manager.chrome import ChromeDriverManager
from chromedriver_py import binary_path as driver_path
from utils import random_delay, send_webhook, create_msg
from utils.selenium_utils import change_driver
import settings, time

class Costco:
    def __init__(self, task_id, status_signal, image_signal, product, profile, proxy, monitor_delay, error_delay, max_price):
        self.task_id, self.status_signal, self.image_signal, self.product, self.profile, self.monitor_delay, self.error_delay, self.max_price = task_id, status_signal, image_signal, product, profile, float(
            monitor_delay), float(error_delay), max_price


        starting_msg = "Starting Costco"
        self.browser = self.init_driver()
        self.product_image = None

        self.SHORT_TIMEOUT = 5
        self.LONG_TIMEOUT = 20

        if settings.dont_buy:
            starting_msg = "Starting Costco in dev mode; will not actually checkout."

        self.status_signal.emit(create_msg(starting_msg, "normal"))
        self.login()
        self.monitor()
        self.add_to_cart()
        self.submit_billing()
        self.submit_order()




    def init_driver(self):
        driver_manager = ChromeDriverManager()
        driver_manager.install()
        # change_driver(self.status_signal, driver_path)
        var = driver_path
        browser = webdriver.Chrome(driver_path)

        browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """
                  Object.defineProperty(navigator, 'webdriver', {
                   get: () => undefined
                  })
                """
        })

        return browser


    def login(self):
        self.status_signal.emit(create_msg("Logging In..", "normal"))

        self.browser.maximize_window()
        
        self.browser.get("https://www.costco.com")

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.LINK_TEXT, "Sign In / Register")))
        self.browser.find_element_by_link_text('My Account').click()

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.value, "Sign In"))).click()

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.ID, "passwordSuccessLogonMessage")))

        email = self.browser.find_element_by_id("passwordSuccessLogonMessage")
        email.send_keys(settings.costco_user)

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.ID, "login-form-password")))

        password = self.browser.find_element_by_id("login-form-password")
        password.send_keys(settings.costco_pass)

        time.sleep(1) # slight delay for in-between filling out login info and clicking Sign In

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="signinCheck"]/button')))
        sign_in_btn = self.browser.find_element_by_xpath('//*[@id="signinCheck"]/button')
        sign_in_btn.click()


    def monitor(self):
        wait(self.browser, self.LONG_TIMEOUT).until(lambda _: self.browser.current_url == "https://www.costco.com/AccountInformationView/")

        self.status_signal.emit(create_msg("Checking Stock..", "normal"))
        
        self.browser.set_window_size(900, 900)

        self.browser.get(self.product)
        wait(self.browser, self.LONG_TIMEOUT).until(lambda _: self.browser.current_url == self.product)

        in_stock = False

        while not in_stock:
            try: 
                wait(self.browser, random_delay(self.monitor_delay, settings.random_delay_start, settings.random_delay_stop)).until(EC.element_to_be_clickable((By.XPATH, '//button[@data-buttontext="Add to Cart"]')))
                add_to_cart_btn = self.browser.find_element_by_xpath('//button[@data-buttontext="Add to Cart"]')
                add_to_cart_btn.click()
                time.sleep(1)
                if not add_to_cart_btn.is_enabled():
                    self.status_signal.emit(create_msg("Waiting For Restock", "normal"))
                    self.browser.refresh()
                    continue
                in_stock = True
                self.status_signal.emit(create_msg("Added to cart", "normal"))
                self.browser.get("https://www.costco.com/CheckoutCartView")
            except:
                self.status_signal.emit(create_msg("Waiting For Restock", "normal"))
                self.browser.refresh()


    def add_to_cart(self):
        wait(self.browser, self.LONG_TIMEOUT).until(lambda _: self.browser.current_url == "https://www.costco.com/CheckoutCartView")
        
        self.status_signal.emit(create_msg("Checking Age Verification", "normal"))

        try:
            #seventeen_or_older_btn = self.browser.find_element_by_xpath('//*[@id="age-gate-modal"]/div/div/div[2]/div/div[2]/button')
            #seventeen_or_older_btn.click()
            time.sleep(2) # short delay for age verification modal to disappear

            # self.browser.get("https://www.gamestop.com/checkout/?stage=payment#payment")
            placeOrderBtn = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "shopCartCheckoutSubmitButton"))
                )
                placeOrderBtn.click()

        isComplete = True
        except:
            # self.browser.get("https://www.gamestop.com/checkout/?stage=payment#payment")
            placeOrderBtn = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "shopCartCheckoutSubmitButton"))
                )
                placeOrderBtn.click()

    def submit_billing(self):
        wait(self.browser, self.LONG_TIMEOUT).until(lambda _: self.browser.current_url == "https://www.costco.com/CheckoutCartDisplayView?storeId=10301&storeId=10301&catalogId=10701&catalogId=10701&langId=-1&langId=-1&krypto=I02KnWToSIKwa1OYQB6%2FxucsXvzHqCgjuMd0HyGz9C42xgGMalifOko2IATKnAbZ9wDF0q7ELVTdRx9fenKd5uj3j%2FerWgYhlLtt4SLftw7cyCTJwbopTSRVlF1THaP5fNBc6dCzj9zDmqkbqRkr%2FpBnTU5Fmw95GpJWx%2BDn14HsSh7RiQYMGGW0rNCxKErLcWqHUE64UrU6AxtJ1ExrJ1lFOWdQiDZrIHLgZIltjllBQjP77J12JsJQoxKo62DKdTJYcwXc4KkWxespZKi9K355aD8UoUUSd0%2Bb%2Fes1CWo%3D&ddkey=http%3AManageShoppingCartCmd")

        self.status_signal.emit(create_msg("Entering CVV #", "normal"))

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.ID, "saved-payment-security-code")))
        cvv_input = self.browser.find_element_by_id("saved-payment-security-code")
        cvv_input.send_keys(self.profile["card_cvv"])
        order_review_btn = self.browser.find_element_by_class_name("btn.btn-primary.btn-block.submit-payment")
        order_review_btn.click()


    def submit_order(self):
        wait(self.browser, self.LONG_TIMEOUT).until(lambda _: self.browser.current_url == "COSTCO.OrderSummaryCart.submitCart('https://www.costco.com/ManageShoppingCartCmd?actionType=expressCheckout');")

        self.status_signal.emit(create_msg("Submitting Order..", "normal"))

        wait(self.browser, self.LONG_TIMEOUT).until(EC.element_to_be_clickable((By.CLASS_NAME, 'btn.btn-primary.btn-block.place-order')))

        if not settings.dont_buy:
            order_review_btn = self.browser.find_element_by_class_name("btn.btn-primary.btn-block.place-order")
            order_review_btn.click()
            self.status_signal.emit(create_msg("Order Placed", "success"))
            send_webhook("OP", "Costco", self.profile["profile_name"], self.task_id, self.product_image)
        else:
            self.status_signal.emit(create_msg("Mock Order Placed", "success"))
            send_webhook("OP", "Costco", self.profile["profile_name"], self.task_id, self.product_image)
`

@jack60612 jack60612 added enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed labels May 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants