Skip to content

Instantly share code, notes, and snippets.

@r614
Last active January 30, 2025 21:59
Show Gist options
  • Save r614/751a030f28fd234a38fddcc09f496d10 to your computer and use it in GitHub Desktop.
Save r614/751a030f28fd234a38fddcc09f496d10 to your computer and use it in GitHub Desktop.
# Setup:
# uv pip install playwright plyer
# playwright install
from playwright.sync_api import sync_playwright
import time
import random
from plyer import notification
import sys
PRODUCT_URL = "https://www.bestbuy.com/site/nvidia-geforce-rtx-5090-32gb-gddr7-graphics-card-dark-gun-metal/6614151.p?skuId=6614151&irclickid=WiYW2YV%3AoxyKWA234nVPV0QXUks2ye2gEUU52o0&irgwc=1&ref=198&loc=Troposphere%20LLC&acampID=0&mpid=62662&affgroup=%22Deals%22"
def send_notification(title, message):
notification.notify(
title=title,
message=message,
app_icon=None,
timeout=10,
)
def random_delay(min_seconds=45, max_seconds=75):
"""Add random delay between checks to appear more human-like"""
delay = random.uniform(min_seconds, max_seconds)
return delay
def setup_browser_context(playwright):
"""Setup browser with anti-bot detection configurations"""
# Use a common browser viewport size
viewport = {"width": 1920, "height": 1080}
# Common user agent for Chrome
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
# Browser context with various settings to appear more human-like
context = playwright.chromium.launch_persistent_context(
user_data_dir="./user-data", # Persist login sessions
headless=False,
viewport=viewport,
user_agent=user_agent,
java_script_enabled=True,
locale="en-US",
timezone_id="America/New_York",
geolocation={"latitude": 40.7128, "longitude": -74.0060}, # NYC coordinates
permissions=["geolocation"],
args=[
"--disable-blink-features=AutomationControlled",
"--disable-automation",
"--no-sandbox",
],
)
return context
def check_and_add_to_cart(page, product_url):
try:
# Add some randomization to navigation but with shorter timeouts
page.set_default_timeout(random.randint(10000, 15000))
# Use a more lenient loading state and catch timeout
try:
page.goto(product_url, wait_until="domcontentloaded")
except Exception as e:
print(f"Page load warning (continuing anyway): {str(e)}")
# Give the page a moment to settle
time.sleep(random.uniform(1, 2))
# Simulate human-like scrolling with more natural timing
page.mouse.move(random.randint(0, 800), random.randint(0, 600))
page.mouse.wheel(delta_x=0, delta_y=random.randint(-300, -100))
time.sleep(random.uniform(0.5, 1))
button_locators = [
# Try simpler selectors first
page.locator('button[data-button-state="ADD_TO_CART"]'),
page.locator('button.add-to-cart-button'),
page.get_by_role("button", name="Add to Cart", exact=True),
page.locator('button:has-text("Add to Cart")'),
]
for button in button_locators:
try:
# Shorter timeout for button checks
if button.is_visible(timeout=3000):
if not button.is_disabled():
# More natural mouse movement
button.hover()
time.sleep(random.uniform(0.1, 0.3))
button.click(delay=random.randint(50, 150))
# Wait a moment to confirm the click worked
time.sleep(1)
send_notification(
"Product Available!",
"The item has been added to your cart!",
)
return True
except Exception as e:
print(f"Button attempt failed: {str(e)}")
continue
print("Add to Cart button not available")
return False
except Exception as e:
print(f"Error checking product: {str(e)}")
return False
def main():
with sync_playwright() as p:
context = setup_browser_context(p)
page = context.new_page()
print("Please log into your Best Buy account...")
print("After logging in, press Enter to start monitoring...")
# Navigate to Best Buy to allow manual login
page.goto("https://www.bestbuy.com")
input()
print("Starting to monitor the product...")
try:
while True:
if check_and_add_to_cart(page, PRODUCT_URL):
print("Product added to cart successfully!")
print("Browser will remain open for you to complete the purchase.")
print("Press Ctrl+C when you're done to close the browser.")
# Keep the script running until user interrupts
while True:
time.sleep(1)
delay = random_delay()
print(
f"Product not available. Checking again in {delay:.1f} seconds..."
)
time.sleep(delay)
except KeyboardInterrupt:
print("\nBot stopped by user. Closing browser...")
except Exception as e:
print(f"An error occurred: {str(e)}")
finally:
# Close all pages first
for page in context.pages:
try:
page.close()
except:
pass
# Then close the context with a timeout
try:
context.close()
except:
print("Force closing browser...")
import os
import signal
# Force kill any remaining browser processes
os.kill(context.browser.process.pid, signal.SIGTERM)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment