nakas commited on
Commit
12ab85e
·
verified ·
1 Parent(s): aa1cbf0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +379 -6
app.py CHANGED
@@ -7,6 +7,7 @@ from PIL import Image
7
  import io
8
  import logging
9
  import traceback
 
10
 
11
  # Configure logging
12
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -246,12 +247,377 @@ def run_instagram_liker(username, password, max_likes):
246
  browser.close()
247
  return "\n".join(status_updates), image_path
248
 
249
- # Rest of the function would go here...
250
- status_updates.append("Login field found! Stopping here for now.")
251
- # Take final screenshot
252
- final_screenshot = f"screenshots/final_{int(time.time())}.png"
253
- page.screenshot(path=final_screenshot)
254
- image_path = final_screenshot
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
256
  # Close the browser
257
  browser.close()
@@ -262,6 +628,13 @@ def run_instagram_liker(username, password, max_likes):
262
  traceback_msg = traceback.format_exc()
263
  logger.error(traceback_msg)
264
  status_updates.append("See logs for detailed error information")
 
 
 
 
 
 
 
265
 
266
  except Exception as e:
267
  error_message = f"Error with Playwright: {str(e)}"
 
7
  import io
8
  import logging
9
  import traceback
10
+ from pathlib import Path
11
 
12
  # Configure logging
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
247
  browser.close()
248
  return "\n".join(status_updates), image_path
249
 
250
+ # Try multiple selectors for password input
251
+ password_selectors = [
252
+ "input[name='password']",
253
+ "input[aria-label='Password']",
254
+ "input[placeholder='Password']",
255
+ "input[type='password']"
256
+ ]
257
+
258
+ password_field = None
259
+ for selector in password_selectors:
260
+ try:
261
+ status_updates.append(f"Trying to find password field with selector: {selector}")
262
+ field = page.query_selector(selector)
263
+ if field:
264
+ password_field = field
265
+ status_updates.append(f"Found password field with selector: {selector}")
266
+ break
267
+ except Exception as e:
268
+ logger.debug(f"Selector {selector} failed: {str(e)}")
269
+
270
+ if not password_field:
271
+ status_updates.append("Could not find password field. Instagram may have changed their interface.")
272
+ # Take final screenshot before closing
273
+ final_screenshot = f"screenshots/final_error_{int(time.time())}.png"
274
+ page.screenshot(path=final_screenshot)
275
+ image_path = final_screenshot
276
+ browser.close()
277
+ return "\n".join(status_updates), image_path
278
+
279
+ # Enter credentials
280
+ status_updates.append(f"Entering username: {username}")
281
+ username_field.fill(username)
282
+ password_field.fill(password)
283
+ status_updates.append("Credentials entered")
284
+
285
+ # Take a screenshot of filled form
286
+ try:
287
+ creds_screenshot = f"screenshots/credentials_pw_{int(time.time())}.png"
288
+ page.screenshot(path=creds_screenshot)
289
+ image_path = creds_screenshot
290
+ status_updates.append("Credentials screenshot saved")
291
+ except Exception as e:
292
+ status_updates.append(f"Error taking screenshot: {str(e)}")
293
+
294
+ # Find login button
295
+ login_button_selectors = [
296
+ "button[type='submit']",
297
+ "button:has-text('Log in')",
298
+ "button:has-text('Sign in')",
299
+ "button:has-text('Log In')",
300
+ "form button"
301
+ ]
302
+
303
+ login_button = None
304
+ for selector in login_button_selectors:
305
+ try:
306
+ status_updates.append(f"Trying to find login button with selector: {selector}")
307
+ button = page.query_selector(selector)
308
+ if button:
309
+ login_button = button
310
+ status_updates.append(f"Found login button with selector: {selector}")
311
+ break
312
+ except Exception as e:
313
+ logger.debug(f"Selector {selector} failed: {str(e)}")
314
+
315
+ if not login_button:
316
+ status_updates.append("Could not find login button. Instagram may have changed their interface.")
317
+ # Take final screenshot before closing
318
+ final_screenshot = f"screenshots/final_error_{int(time.time())}.png"
319
+ page.screenshot(path=final_screenshot)
320
+ image_path = final_screenshot
321
+ browser.close()
322
+ return "\n".join(status_updates), image_path
323
+
324
+ # Click login button
325
+ status_updates.append("Clicking login button...")
326
+ login_button.click()
327
+
328
+ # Wait for navigation to complete
329
+ status_updates.append("Waiting for login process...")
330
+ page.wait_for_timeout(5000)
331
+
332
+ # Take post-login screenshot
333
+ try:
334
+ post_login_screenshot = f"screenshots/post_login_pw_{int(time.time())}.png"
335
+ page.screenshot(path=post_login_screenshot)
336
+ image_path = post_login_screenshot
337
+ status_updates.append("Post-login screenshot saved")
338
+ except Exception as e:
339
+ status_updates.append(f"Error taking screenshot: {str(e)}")
340
+
341
+ # Check if login was successful
342
+ current_url = page.url
343
+ if "/accounts/login" in current_url or "/login" in current_url:
344
+ # Still on login page - check for error messages
345
+ error_selectors = [
346
+ "#slfErrorAlert",
347
+ "p[data-testid='login-error-message']",
348
+ "div[role='alert']",
349
+ "p.sIKKJ",
350
+ ".coreSpriteAccessUpsell + div"
351
+ ]
352
+
353
+ error_message = ""
354
+ for selector in error_selectors:
355
+ try:
356
+ el = page.query_selector(selector)
357
+ if el:
358
+ error_message = el.text_content()
359
+ break
360
+ except:
361
+ pass
362
+
363
+ if error_message:
364
+ status_updates.append(f"Login failed: {error_message}")
365
+ else:
366
+ status_updates.append("Login failed: Reason unknown. Check your credentials.")
367
+
368
+ browser.close()
369
+ return "\n".join(status_updates), image_path
370
+
371
+ status_updates.append("Login successful! Now handling post-login dialogs...")
372
+
373
+ # Handle "Save Login Info" popup if it appears
374
+ try:
375
+ page.wait_for_timeout(2000) # Wait a bit for dialog to appear
376
+
377
+ save_info_selectors = [
378
+ "text=Save Login Info",
379
+ "text=Save Your Login Info",
380
+ "text=Save Info"
381
+ ]
382
+ not_now_selectors = [
383
+ "text=Not Now",
384
+ "button:has-text('Not Now')",
385
+ "button.sqdOP.yWX7d",
386
+ "button:not(:has-text('Save'))"
387
+ ]
388
+
389
+ # Check if any save info dialog appears
390
+ dialog_found = False
391
+ for selector in save_info_selectors:
392
+ if page.query_selector(selector):
393
+ dialog_found = True
394
+ status_updates.append(f"Save Login Info dialog found with: {selector}")
395
+ break
396
+
397
+ if dialog_found:
398
+ # Try to click "Not Now"
399
+ dismissed = False
400
+ for not_now in not_now_selectors:
401
+ try:
402
+ button = page.query_selector(not_now)
403
+ if button:
404
+ button.click()
405
+ status_updates.append(f"Dismissed 'Save Login Info' popup using: {not_now}")
406
+ page.wait_for_timeout(2000)
407
+ dismissed = True
408
+ break
409
+ except Exception as e:
410
+ logger.debug(f"Not Now button {not_now} failed: {str(e)}")
411
+ continue
412
+
413
+ if not dismissed:
414
+ status_updates.append("Found Save Login dialog but couldn't dismiss it")
415
+ else:
416
+ status_updates.append("No 'Save Login Info' popup detected")
417
+ except Exception as e:
418
+ status_updates.append(f"Error handling Save Login dialog: {str(e)}")
419
+
420
+ # Take a screenshot after handling first dialog
421
+ try:
422
+ after_save_screenshot = f"screenshots/after_save_dialog_{int(time.time())}.png"
423
+ page.screenshot(path=after_save_screenshot)
424
+ image_path = after_save_screenshot
425
+ status_updates.append("Screenshot after Save Info dialog")
426
+ except Exception as e:
427
+ status_updates.append(f"Error taking screenshot: {str(e)}")
428
+
429
+ # Handle notifications popup if it appears
430
+ try:
431
+ page.wait_for_timeout(2000) # Wait a bit for dialog to appear
432
+
433
+ notifications_selectors = [
434
+ "text=Turn on Notifications",
435
+ "text=Enable Notifications",
436
+ "h2:has-text('Notifications')"
437
+ ]
438
+ not_now_selectors = [
439
+ "text=Not Now",
440
+ "button:has-text('Not Now')",
441
+ "button.sqdOP.yWX7d",
442
+ "button:not(:has-text('Allow'))"
443
+ ]
444
+
445
+ # Check if any notifications dialog appears
446
+ dialog_found = False
447
+ for selector in notifications_selectors:
448
+ if page.query_selector(selector):
449
+ dialog_found = True
450
+ status_updates.append(f"Notifications dialog found with: {selector}")
451
+ break
452
+
453
+ if dialog_found:
454
+ # Try to click "Not Now"
455
+ dismissed = False
456
+ for not_now in not_now_selectors:
457
+ try:
458
+ button = page.query_selector(not_now)
459
+ if button:
460
+ button.click()
461
+ status_updates.append(f"Dismissed notifications popup using: {not_now}")
462
+ page.wait_for_timeout(2000)
463
+ dismissed = True
464
+ break
465
+ except Exception as e:
466
+ logger.debug(f"Not Now button {not_now} failed: {str(e)}")
467
+ continue
468
+
469
+ if not dismissed:
470
+ status_updates.append("Found Notifications dialog but couldn't dismiss it")
471
+ else:
472
+ status_updates.append("No notifications popup detected")
473
+ except Exception as e:
474
+ status_updates.append(f"Error handling Notifications dialog: {str(e)}")
475
+
476
+ # Take feed screenshot
477
+ try:
478
+ feed_screenshot = f"screenshots/feed_pw_{int(time.time())}.png"
479
+ page.screenshot(path=feed_screenshot)
480
+ image_path = feed_screenshot
481
+ status_updates.append("Feed screenshot saved")
482
+ except Exception as e:
483
+ status_updates.append(f"Error taking screenshot: {str(e)}")
484
+
485
+ status_updates.append("Successfully navigated to Instagram feed!")
486
+
487
+ # Start liking posts
488
+ status_updates.append(f"Starting to like posts (target: {max_likes})...")
489
+
490
+ # Like posts
491
+ likes_count = 0
492
+ scroll_count = 0
493
+ max_scrolls = 30
494
+
495
+ # Try to find posts with multiple selectors
496
+ article_selectors = [
497
+ "article",
498
+ "div[role='presentation']",
499
+ "div[data-testid='post-content']",
500
+ "div._aac4._aac5._aac6",
501
+ "div._ab6k"
502
+ ]
503
+
504
+ article_found = False
505
+ for selector in article_selectors:
506
+ try:
507
+ if page.query_selector(selector):
508
+ article_found = True
509
+ status_updates.append(f"Found posts using selector: {selector}")
510
+ break
511
+ except Exception as e:
512
+ logger.debug(f"Article selector {selector} failed: {str(e)}")
513
+
514
+ if not article_found:
515
+ status_updates.append("Could not find posts on feed. Instagram may have changed their interface.")
516
+ browser.close()
517
+ return "\n".join(status_updates), image_path
518
+
519
+ while likes_count < max_likes and scroll_count < max_scrolls:
520
+ # Try different selectors for like buttons
521
+ like_button_selectors = [
522
+ "article section svg[aria-label='Like']",
523
+ "article svg[aria-label='Like']",
524
+ "svg[aria-label='Like']",
525
+ "span[class*='_aamw'] svg[aria-label='Like']",
526
+ "article button[type='button'] svg:not([aria-label='Unlike'])"
527
+ ]
528
+
529
+ like_buttons = []
530
+ used_selector = ""
531
+ for selector in like_button_selectors:
532
+ try:
533
+ buttons = page.query_selector_all(selector)
534
+ if buttons and len(buttons) > 0:
535
+ like_buttons = buttons
536
+ used_selector = selector
537
+ status_updates.append(f"Found {len(buttons)} like buttons with selector: {selector}")
538
+ break
539
+ except Exception as e:
540
+ logger.debug(f"Like button selector {selector} failed: {str(e)}")
541
+
542
+ status_updates.append(f"Found {len(like_buttons)} like buttons on scroll {scroll_count}")
543
+
544
+ if len(like_buttons) == 0 and scroll_count > 5:
545
+ status_updates.append("No more like buttons found. Stopping.")
546
+ break
547
+
548
+ # Click like buttons
549
+ for i, button in enumerate(like_buttons):
550
+ if likes_count >= max_likes:
551
+ break
552
+
553
+ try:
554
+ # Scroll to button
555
+ button.scroll_into_view_if_needed()
556
+ page.wait_for_timeout(1000)
557
+
558
+ # Take pre-click screenshot occasionally
559
+ if likes_count % 5 == 0:
560
+ try:
561
+ pre_like_screenshot = f"screenshots/pre_like_pw_{likes_count}_{int(time.time())}.png"
562
+ page.screenshot(path=pre_like_screenshot)
563
+ image_path = pre_like_screenshot
564
+ status_updates.append(f"Pre-like screenshot {likes_count} saved")
565
+ except Exception as e:
566
+ status_updates.append(f"Error taking screenshot: {str(e)}")
567
+
568
+ # Get parent button if needed
569
+ if "svg" in used_selector:
570
+ try:
571
+ # Find the parent button of the SVG
572
+ parent_button = button.evaluate("node => node.closest('button')")
573
+ if parent_button:
574
+ parent_button.click()
575
+ else:
576
+ button.click()
577
+ except Exception as e:
578
+ # If error finding parent, click the button directly
579
+ button.click()
580
+ else:
581
+ # Click directly if it's already a button
582
+ button.click()
583
+
584
+ likes_count += 1
585
+ status_updates.append(f"Liked post {likes_count}/{max_likes}")
586
+
587
+ # Take screenshot occasionally
588
+ if likes_count % 5 == 0:
589
+ try:
590
+ like_screenshot = f"screenshots/after_like_pw_{likes_count}_{int(time.time())}.png"
591
+ page.screenshot(path=like_screenshot)
592
+ image_path = like_screenshot
593
+ status_updates.append(f"After-like screenshot {likes_count} saved")
594
+ except Exception as e:
595
+ status_updates.append(f"Error taking screenshot: {str(e)}")
596
+
597
+ # Wait between likes to avoid rate limiting
598
+ page.wait_for_timeout(2000 + (likes_count % 3) * 1000) # Varying delay
599
+ except Exception as e:
600
+ status_updates.append(f"Error liking post {i+1}: {str(e)}")
601
+ continue
602
+
603
+ # Scroll down to load more
604
+ page.evaluate("window.scrollBy(0, 1000)")
605
+ status_updates.append("Scrolled down to load more posts")
606
+ page.wait_for_timeout(3000)
607
+ scroll_count += 1
608
+
609
+ # Final status
610
+ final_message = f"Finished! Liked {likes_count} posts."
611
+ status_updates.append(final_message)
612
+
613
+ # Final screenshot
614
+ try:
615
+ final_screenshot = f"screenshots/final_{int(time.time())}.png"
616
+ page.screenshot(path=final_screenshot)
617
+ image_path = final_screenshot
618
+ status_updates.append("Final screenshot saved")
619
+ except Exception as e:
620
+ status_updates.append(f"Error taking final screenshot: {str(e)}")
621
 
622
  # Close the browser
623
  browser.close()
 
628
  traceback_msg = traceback.format_exc()
629
  logger.error(traceback_msg)
630
  status_updates.append("See logs for detailed error information")
631
+
632
+ # Try to close browser in case of error
633
+ try:
634
+ browser.close()
635
+ status_updates.append("Browser closed after error")
636
+ except:
637
+ pass
638
 
639
  except Exception as e:
640
  error_message = f"Error with Playwright: {str(e)}"