-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwhatnot_order.py
More file actions
297 lines (247 loc) · 13.3 KB
/
whatnot_order.py
File metadata and controls
297 lines (247 loc) · 13.3 KB
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
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import logging
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
def get_user_input():
"""Get user input for credentials and settings"""
print("=== Whatnot Bot Configuration ===")
email = input("📧 Enter your email: ").strip()
while not email:
print("❌ Email cannot be empty!")
email = input("📧 Enter your email: ").strip()
password = input("🔑 Enter your password: ").strip()
while not password:
print("❌ Password cannot be empty!")
password = input("🔑 Enter your password: ").strip()
live_url = input("🔗 Enter the live stream URL: ").strip()
while not live_url:
print("❌ Live stream URL cannot be empty!")
live_url = input("🔗 Enter the live stream URL: ").strip()
try:
timeout = int(input("⏰ Enter timeout in seconds (default 2000): ").strip() or "2000")
if timeout <= 0:
timeout = 2000
except ValueError:
timeout = 2000
print("⚠️ Invalid timeout, using default 2000 seconds")
try:
chrome_version = int(input("🌐 Enter Chrome version (default 140): ").strip() or "140")
if chrome_version <= 0:
chrome_version = 140
except ValueError:
chrome_version = 140
print("⚠️ Invalid Chrome version, using default 140")
keyword = input("🔍 Enter search keyword (default 'Goku'): ").strip() or "Goku"
return email, password, live_url, timeout, chrome_version, keyword
def remove_overlays(driver):
"""Remove common blocking overlays"""
overlay_selectors = [
"//div[contains(@style, 'backdrop-filter') and @style[contains(., 'z-index')]]",
"//div[@class='modal-overlay']",
"//div[contains(@class, 'overlay') and contains(@style, 'absolute')]",
"//div[@role='dialog']",
"//div[contains(@class, 'backdrop')]",
"//div[@data-testid='modal-backdrop']"
]
removed_count = 0
for selector in overlay_selectors:
try:
overlays = driver.find_elements(By.XPATH, selector)
for overlay in overlays:
if overlay.is_displayed():
driver.execute_script("""
arguments[0].style.display = 'none';
arguments[0].style.visibility = 'hidden';
""", overlay)
logger.info(f"Removed overlay: {selector}")
removed_count += 1
except:
continue
if removed_count > 0:
logger.info(f"Removed {removed_count} overlay(s)")
return removed_count
def main():
# Get user input
EMAIL, PASSWORD, LIVE_URL, TIMEOUT, CHROME_VERSION, KEYWORD = get_user_input()
options = uc.ChromeOptions()
options.add_argument("--start-maximized")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--disable-infobars")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36")
try:
# ✅ Force correct ChromeDriver version
driver = uc.Chrome(options=options, version_main=CHROME_VERSION)
# Remove webdriver property
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
logger.info("🚀 Chrome launched successfully.")
print(f"📝 Configuration Summary:")
print(f" Email: {EMAIL}")
print(f" Live URL: {LIVE_URL}")
print(f" Timeout: {TIMEOUT} seconds")
print(f" Search Keyword: {KEYWORD}")
except Exception as e:
logger.error(f"❌ Could not start Chrome: {e}")
return
try:
# 🔐 Go to login page
print("\n🔄 Navigating to login page...")
driver.get("https://www.whatnot.com/en-GB/login")
# Wait for page to load
time.sleep(3)
WebDriverWait(driver, 30).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="input-login-email"]'))
)
logger.info("✅ Login page loaded.")
# Clear and fill email
email_field = driver.find_element(By.XPATH, '//*[@id="input-login-email"]')
email_field.clear()
email_field.send_keys(EMAIL)
# Clear and fill password
password_field = driver.find_element(By.XPATH, '//*[@id="input-login-password"]')
password_field.clear()
password_field.send_keys(PASSWORD)
# Click submit with JavaScript to avoid detection
submit_button = driver.find_element(By.XPATH, "//button[@type='submit']")
driver.execute_script("arguments[0].click();", submit_button)
logger.info("🔓 Submitted login.")
# 2FA step (manual)
logger.info("📱 Complete 2FA, then press ENTER.")
input("✅ Press ENTER after completing 2FA...")
WebDriverWait(driver, 30).until_not(EC.url_contains("/login"))
logger.info("✅ Logged in successfully.")
# 🛑 Wait for user to manually start browser/goto live stream
logger.info("🛑 Browser is ready. Press ENTER to navigate to the live stream...")
input("👉 Press ENTER to go to the live stream...")
# 🎥 Navigate to live stream
driver.get(LIVE_URL)
# Wait for the page to load some content
try:
WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
logger.info("✅ Live stream page loaded.")
except Exception:
logger.warning("⚠️ Live page might not be fully loaded. Continuing anyway...")
# 🔍 Buy loop with refresh every 2 seconds
bought = False
start_time = time.time()
print(f"🔄 Starting search loop with keyword: '{KEYWORD}'")
print(f"⏰ Timeout set to: {TIMEOUT} seconds")
while not bought and (time.time() - start_time < TIMEOUT):
try:
driver.refresh()
logger.info("🔄 Page refreshed.")
time.sleep(5) # Wait for content to reload
# Remove overlays before clicking
remove_overlays(driver)
time.sleep(1)
# Click buy section using JavaScript to avoid overlay issues
try:
buy_section = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//h5[normalize-space(text()) = 'Buy Now']"))
)
if buy_section.is_displayed():
driver.execute_script("arguments[0].click();", buy_section)
logger.info("🛒 Clicked buy section")
time.sleep(3)
except Exception as e:
logger.warning(f"❌ Could not find/click buy section: {e}")
# 🔍 Try entering keyword in search (optional — if applicable)
try:
search_input = WebDriverWait(driver, 5).until(
EC.presence_of_element_located(
(By.XPATH, '//input[@data-cy="inventory_search"]')
)
)
search_input.clear()
search_input.send_keys(KEYWORD)
logger.info(f"🔎 Searched for keyword: {KEYWORD}")
time.sleep(3)
except Exception as e:
logger.warning(f"❌ Could not find search input: {e}")
# 🛒 Check for "Buy" buttons (initial product buttons)
try:
# Use a more specific XPath to distinguish from confirmation buttons
buttons = driver.find_elements(By.XPATH, "//button[contains(@class, 'buy') and contains(text(), 'Buy Now') and not(@disabled)] | //button[@data-cy='buy-now-button' and not(@disabled)] | //div[@data-testid='product-item']//button[contains(text(), 'Buy Now') and not(@disabled)]")
# Fallback to original XPath if specific ones don't work
if not buttons:
buttons = driver.find_elements(By.XPATH, "//button[contains(text(), 'Buy Now') and not(@disabled)]")
if buttons:
logger.info(f"🎯 Found {len(buttons)} 'Buy Now' button(s)")
for btn in buttons:
if btn.is_displayed() and btn.is_enabled():
try:
# Remove overlays before clicking
remove_overlays(driver)
time.sleep(1)
# Scroll to button
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", btn)
time.sleep(1)
# Click with JavaScript to bypass overlay issues
driver.execute_script("arguments[0].click();", btn)
logger.info("🛒 Clicked 'Buy' button!")
time.sleep(3)
# Try to confirm purchase with specific confirmation button XPaths
try:
# Wait for confirmation modal/popup to appear
time.sleep(2)
remove_overlays(driver)
# Look for confirmation buttons (different from initial buy buttons)
confirm_buttons = driver.find_elements(By.XPATH, "//button[contains(text(), 'Confirm') or contains(text(), 'Yes') or contains(text(), 'Place Order') or @type='submit' and not(contains(text(), 'Buy Now'))]")
if confirm_buttons:
# Click the first available confirmation button
confirm_btn = confirm_buttons[0]
if confirm_btn.is_displayed() and confirm_btn.is_enabled():
driver.execute_script("arguments[0].click();", confirm_btn)
logger.info("🎉 Purchase confirmed!")
bought = True
break
else:
# Fallback: try to find any submit button in a modal
submit_buttons = driver.find_elements(By.XPATH, "//div[@role='dialog']//button[@type='submit'] | //div[contains(@class, 'modal')]//button[@type='submit']")
if submit_buttons:
submit_btn = submit_buttons[0]
if submit_btn.is_displayed() and submit_btn.is_enabled():
driver.execute_script("arguments[0].click();", submit_btn)
logger.info("🎉 Purchase confirmed (submit button)!")
bought = True
break
except Exception as e:
logger.warning(f"⚠️ Could not confirm purchase: {e}")
bought = True
break
except Exception as e:
logger.warning(f"⚠️ Error clicking Buy button: {e}")
continue
except Exception as e:
logger.warning(f"⚠️ No buy buttons found: {e}")
except Exception as e:
logger.warning(f"⚠️ Error during loop: {e}")
if not bought:
logger.info(f"⌛ Timeout reached ({TIMEOUT} seconds). No product purchased.")
else:
logger.info("✅ Purchase completed successfully!")
except Exception as e:
logger.error(f"❌ Unexpected error: {type(e).__name__}: {e}")
try:
logger.error(f"Current URL: {driver.current_url}")
except:
pass
finally:
logger.info("👋 Closing browser.")
print("\n📊 Session Summary:")
print(f" Keyword searched: {KEYWORD}")
print(f" Duration: {min(int(time.time() - start_time), TIMEOUT)} seconds")
try:
driver.quit()
except:
pass
if __name__ == "__main__":
main()