nakas commited on
Commit
84d6f3d
·
verified ·
1 Parent(s): 2ef74d3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +288 -166
app.py CHANGED
@@ -6,7 +6,7 @@ import sys
6
  from PIL import Image
7
  import io
8
  import logging
9
- from playwright.sync_api import sync_playwright
10
 
11
  # Configure logging
12
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -15,207 +15,322 @@ logger = logging.getLogger(__name__)
15
  # Create screenshots directory if it doesn't exist
16
  os.makedirs('screenshots', exist_ok=True)
17
 
18
- def save_screenshot(page, name):
19
- """Save a screenshot and return path"""
20
  try:
21
- timestamp = int(time.time())
22
- filename = f"screenshots/{name}_{timestamp}.png"
23
- page.screenshot(path=filename)
24
- logger.info(f"Saved screenshot: {filename}")
25
- return filename
26
  except Exception as e:
27
- logger.error(f"Error taking screenshot: {e}")
28
- return None
 
29
 
30
- def login_and_like_posts(username, password, max_likes):
31
- """Main function to login to Instagram and like posts"""
32
- status_updates = ["Starting Instagram Auto-Liker..."]
33
- image_path = None
 
 
 
 
34
 
 
35
  try:
36
- with sync_playwright() as p:
37
- status_updates.append("Launching browser...")
38
- browser = p.chromium.launch(
39
- headless=True,
40
- args=['--no-sandbox', '--disable-dev-shm-usage']
41
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
- # Create a context with realistic user agent
44
- context = browser.new_context(
45
- user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
46
- viewport={'width': 1280, 'height': 720}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  )
48
 
49
- # Create a new page
50
- page = context.new_page()
 
 
51
 
52
- # First test browser by visiting a simple site
53
- status_updates.append("Testing browser connection...")
54
- page.goto("https://www.google.com")
55
- page.wait_for_load_state("networkidle")
56
- status_updates.append(f"Browser working. Title: {page.title()}")
57
 
58
- # Take test screenshot
59
- test_screenshot = save_screenshot(page, "browser_test")
60
- image_path = test_screenshot
61
 
62
- # Instagram login
63
- status_updates.append("Navigating to Instagram...")
64
- page.goto("https://www.instagram.com/")
65
- page.wait_for_load_state("networkidle")
 
 
 
66
 
67
- # Take screenshot of Instagram landing
68
- landing_screenshot = save_screenshot(page, "instagram_landing")
69
- image_path = landing_screenshot
 
70
 
71
- # Handle cookie consent if present
72
- try:
73
- for button_text in ["Accept", "Allow", "Accept All"]:
74
- button = page.get_by_text(button_text, exact=False)
75
- if button.count() > 0:
76
- button.first.click()
77
- status_updates.append(f"Clicked '{button_text}' cookie button")
78
- page.wait_for_timeout(2000)
79
- break
80
- except Exception as e:
81
- status_updates.append(f"No cookie dialog or error: {str(e)}")
82
 
83
- # Wait for and fill login form
84
- status_updates.append("Looking for login form...")
85
  try:
86
- page.wait_for_selector('input[name="username"]', state="visible", timeout=10000)
87
-
88
- # Take pre-login screenshot
89
- pre_login_screenshot = save_screenshot(page, "pre_login")
90
- image_path = pre_login_screenshot
91
-
92
- # Enter credentials
93
- status_updates.append(f"Entering username: {username}")
94
- page.fill('input[name="username"]', username)
95
- page.fill('input[name="password"]', password)
96
- status_updates.append("Credentials entered")
97
-
98
- # Click login button
99
- status_updates.append("Clicking login button...")
100
- page.click('button[type="submit"]')
101
-
102
- # Wait for navigation
103
- page.wait_for_load_state("networkidle")
104
- page.wait_for_timeout(5000) # Additional wait for elements
105
-
106
- # Take post-login screenshot
107
- post_login_screenshot = save_screenshot(page, "post_login")
108
  image_path = post_login_screenshot
109
-
110
- # Check login status
111
- if "/accounts/login" in page.url:
112
- error_text = ""
113
- try:
114
- error_elem = page.query_selector('#slfErrorAlert')
115
- if error_elem:
116
- error_text = error_elem.text_content()
117
- except:
118
- pass
119
-
120
- status_updates.append(f"Login failed: {error_text or 'Unknown error'}")
121
- return "\n".join(status_updates), image_path
122
-
123
- # Handle "Save Login Info" popup if it appears
124
- try:
125
- not_now = page.get_by_text("Not Now", exact=True)
126
- if not_now.count() > 0:
127
- not_now.first.click()
128
- status_updates.append("Dismissed 'Save Login Info' popup")
129
- page.wait_for_timeout(2000)
130
- except Exception as e:
131
- status_updates.append("No 'Save Login Info' popup detected")
132
-
133
- # Handle notifications popup if it appears
134
  try:
135
- not_now = page.get_by_text("Not Now", exact=True)
136
- if not_now.count() > 0:
137
- not_now.first.click()
138
- status_updates.append("Dismissed notifications popup")
139
- page.wait_for_timeout(2000)
140
- except Exception as e:
141
- status_updates.append("No notifications popup detected")
142
 
143
- # Take feed screenshot
144
- feed_screenshot = save_screenshot(page, "feed")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  image_path = feed_screenshot
146
- status_updates.append("Successfully logged in! On Instagram feed now.")
147
-
148
- # Start liking posts
149
- status_updates.append(f"Starting to like posts (target: {max_likes})...")
150
 
151
- # Like posts
152
- likes_count = 0
153
- scroll_count = 0
154
- max_scrolls = 30
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
- # Try to find posts
157
- try:
158
- page.wait_for_selector('article', timeout=10000)
159
- status_updates.append("Found posts on feed")
 
160
 
161
- while likes_count < max_likes and scroll_count < max_scrolls:
162
- # Find like buttons
163
- like_buttons = page.query_selector_all('article svg[aria-label="Like"]')
164
-
165
- status_updates.append(f"Found {len(like_buttons)} like buttons on scroll {scroll_count}")
166
-
167
- if len(like_buttons) == 0 and scroll_count > 5:
168
- status_updates.append("No more like buttons found. Stopping.")
 
169
  break
170
 
171
- # Click like buttons
172
- for i, button in enumerate(like_buttons):
173
- if likes_count >= max_likes:
174
- break
175
 
176
- try:
177
- # Scroll to button
178
- button.scroll_into_view_if_needed()
179
- page.wait_for_timeout(500)
180
-
181
- # Click like
182
- button.click()
183
- likes_count += 1
184
- status_updates.append(f"Liked post {likes_count}/{max_likes}")
185
-
186
- # Wait between likes
187
- page.wait_for_timeout(2000)
188
- except Exception as e:
189
- status_updates.append(f"Error liking post {i+1}: {str(e)}")
190
- continue
191
-
192
- # Scroll down to load more
193
- page.evaluate("window.scrollBy(0, 1000)")
194
- status_updates.append(f"Scrolled down to load more posts")
195
- page.wait_for_timeout(3000)
196
- scroll_count += 1
197
-
198
- # Final status
199
- final_message = f"Finished! Liked {likes_count} posts."
200
- status_updates.append(final_message)
201
 
202
- except Exception as e:
203
- status_updates.append(f"Error finding or liking posts: {str(e)}")
 
 
 
 
 
 
 
204
 
205
  except Exception as e:
206
- status_updates.append(f"Error with login form: {str(e)}")
207
 
208
- # Close the browser
209
- browser.close()
210
- status_updates.append("Browser closed")
211
-
 
 
 
212
  except Exception as e:
213
  error_message = f"Error: {str(e)}"
214
  logger.error(error_message)
215
  status_updates.append(error_message)
 
216
 
217
  return "\n".join(status_updates), image_path
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  # Gradio Interface
220
  def create_interface():
221
  with gr.Blocks(title="Instagram Auto-Liker") as app:
@@ -243,5 +358,12 @@ def create_interface():
243
 
244
  # Launch the app
245
  if __name__ == "__main__":
 
 
 
 
 
 
 
246
  app = create_interface()
247
  app.launch(server_name="0.0.0.0", server_port=7860, share=True)
 
6
  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')
 
15
  # Create screenshots directory if it doesn't exist
16
  os.makedirs('screenshots', exist_ok=True)
17
 
18
+ def install_playwright():
19
+ """Install Playwright and its browsers"""
20
  try:
21
+ logger.info("Installing Playwright browsers...")
22
+ subprocess.run([sys.executable, "-m", "pip", "install", "playwright==1.39.0"], check=True)
23
+ subprocess.run([sys.executable, "-m", "playwright", "install", "chromium"], check=True)
24
+ return "Playwright browsers installed successfully."
 
25
  except Exception as e:
26
+ error_msg = f"Error installing browsers: {str(e)}"
27
+ logger.error(error_msg)
28
+ return error_msg
29
 
30
+ def save_placeholder_image(name):
31
+ """Create a placeholder image when no screenshot is available"""
32
+ timestamp = int(time.time())
33
+ filename = f"screenshots/{name}_{timestamp}.png"
34
+
35
+ # Create a simple colored image
36
+ img = Image.new('RGB', (400, 300), color=(73, 109, 137))
37
+ d = Image.new('RGB', (400, 300), color=(200, 200, 200))
38
 
39
+ # Add some text if possible
40
  try:
41
+ from PIL import ImageDraw, ImageFont
42
+ draw = ImageDraw.Draw(img)
43
+ draw.text((10, 150), f"Instagram Auto-Liker - {name}", fill=(255, 255, 255))
44
+ except:
45
+ pass
46
+
47
+ img.save(filename)
48
+ logger.info(f"Saved placeholder image: {filename}")
49
+ return filename
50
+
51
+ def run_with_selenium(username, password, max_likes):
52
+ """Run the Instagram auto-liker with Selenium"""
53
+ status_updates = ["Starting Instagram Auto-Liker with Selenium..."]
54
+ image_path = save_placeholder_image("start")
55
+
56
+ try:
57
+ # Import Selenium components
58
+ from selenium import webdriver
59
+ from selenium.webdriver.chrome.options import Options
60
+ from selenium.webdriver.common.by import By
61
+ from selenium.webdriver.support.ui import WebDriverWait
62
+ from selenium.webdriver.support import expected_conditions as EC
63
+
64
+ status_updates.append("Setting up Chrome driver...")
65
+
66
+ # Configure Chrome options
67
+ chrome_options = Options()
68
+ chrome_options.add_argument('--headless')
69
+ chrome_options.add_argument('--no-sandbox')
70
+ chrome_options.add_argument('--disable-dev-shm-usage')
71
+ chrome_options.add_argument('--disable-gpu')
72
+ chrome_options.add_argument('--window-size=1280,720')
73
+
74
+ # Start Chrome driver
75
+ driver = webdriver.Chrome(options=chrome_options)
76
+ driver.set_page_load_timeout(60)
77
+
78
+ # Test browser by visiting Google
79
+ status_updates.append("Testing browser connection...")
80
+ driver.get("https://www.google.com")
81
+ status_updates.append(f"Browser working. Title: {driver.title}")
82
+
83
+ # Take a screenshot if possible
84
+ try:
85
+ test_screenshot = f"screenshots/test_{int(time.time())}.png"
86
+ driver.save_screenshot(test_screenshot)
87
+ image_path = test_screenshot
88
+ status_updates.append("Browser screenshot saved")
89
+ except Exception as e:
90
+ status_updates.append(f"Error taking screenshot: {str(e)}")
91
+
92
+ # Navigate to Instagram
93
+ status_updates.append("Navigating to Instagram...")
94
+ driver.get("https://www.instagram.com/")
95
+ time.sleep(5) # Wait for page to load
96
+
97
+ # Take a screenshot
98
+ try:
99
+ landing_screenshot = f"screenshots/landing_{int(time.time())}.png"
100
+ driver.save_screenshot(landing_screenshot)
101
+ image_path = landing_screenshot
102
+ except Exception as e:
103
+ status_updates.append(f"Error taking screenshot: {str(e)}")
104
+
105
+ # Handle cookie dialog if present
106
+ try:
107
+ cookie_buttons = [
108
+ "//button[contains(text(), 'Accept')]",
109
+ "//button[contains(text(), 'Allow')]",
110
+ "//button[contains(text(), 'Only allow essential cookies')]"
111
+ ]
112
 
113
+ for button_xpath in cookie_buttons:
114
+ try:
115
+ cookie_btn = WebDriverWait(driver, 5).until(
116
+ EC.element_to_be_clickable((By.XPATH, button_xpath))
117
+ )
118
+ cookie_btn.click()
119
+ status_updates.append("Clicked cookie consent button")
120
+ time.sleep(2)
121
+ break
122
+ except:
123
+ continue
124
+ except:
125
+ status_updates.append("No cookie dialog detected or it was bypassed")
126
+
127
+ # Wait for login form
128
+ status_updates.append("Looking for login form...")
129
+ try:
130
+ username_field = WebDriverWait(driver, 15).until(
131
+ EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='username']"))
132
  )
133
 
134
+ # Enter credentials
135
+ status_updates.append(f"Entering username: {username}")
136
+ username_field.clear()
137
+ username_field.send_keys(username)
138
 
139
+ password_field = driver.find_element(By.CSS_SELECTOR, "input[name='password']")
140
+ password_field.clear()
141
+ password_field.send_keys(password)
 
 
142
 
143
+ status_updates.append("Credentials entered")
 
 
144
 
145
+ # Take a screenshot
146
+ try:
147
+ creds_screenshot = f"screenshots/credentials_{int(time.time())}.png"
148
+ driver.save_screenshot(creds_screenshot)
149
+ image_path = creds_screenshot
150
+ except:
151
+ pass
152
 
153
+ # Click login button
154
+ login_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
155
+ status_updates.append("Clicking login button...")
156
+ login_button.click()
157
 
158
+ # Wait for login to complete
159
+ time.sleep(5)
 
 
 
 
 
 
 
 
 
160
 
161
+ # Take post-login screenshot
 
162
  try:
163
+ post_login_screenshot = f"screenshots/post_login_{int(time.time())}.png"
164
+ driver.save_screenshot(post_login_screenshot)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  image_path = post_login_screenshot
166
+ except:
167
+ pass
168
+
169
+ # Check if login was successful
170
+ current_url = driver.current_url
171
+ if "/accounts/login" in current_url:
172
+ # Still on login page - check for error messages
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  try:
174
+ error_message = driver.find_element(By.ID, "slfErrorAlert").text
175
+ status_updates.append(f"Login failed: {error_message}")
176
+ except:
177
+ status_updates.append("Login failed: Reason unknown")
 
 
 
178
 
179
+ driver.quit()
180
+ return "\n".join(status_updates), image_path
181
+
182
+ # Handle "Save Login Info" popup if it appears
183
+ try:
184
+ not_now_button = WebDriverWait(driver, 5).until(
185
+ EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'Not Now')]"))
186
+ )
187
+ not_now_button.click()
188
+ status_updates.append("Dismissed 'Save Login Info' popup")
189
+ time.sleep(2)
190
+ except:
191
+ status_updates.append("No 'Save Login Info' popup detected")
192
+
193
+ # Handle notifications popup if it appears
194
+ try:
195
+ not_now_button = WebDriverWait(driver, 5).until(
196
+ EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'Not Now')]"))
197
+ )
198
+ not_now_button.click()
199
+ status_updates.append("Dismissed notifications popup")
200
+ time.sleep(2)
201
+ except:
202
+ status_updates.append("No notifications popup detected")
203
+
204
+ # Take feed screenshot
205
+ try:
206
+ feed_screenshot = f"screenshots/feed_{int(time.time())}.png"
207
+ driver.save_screenshot(feed_screenshot)
208
  image_path = feed_screenshot
209
+ except:
210
+ pass
 
 
211
 
212
+ status_updates.append("Successfully logged in! On Instagram feed now.")
213
+
214
+ # Start liking posts
215
+ status_updates.append(f"Starting to like posts (target: {max_likes})...")
216
+
217
+ # Like posts
218
+ likes_count = 0
219
+ scroll_count = 0
220
+ max_scrolls = 30
221
+
222
+ # Try to find posts
223
+ try:
224
+ WebDriverWait(driver, 10).until(
225
+ EC.presence_of_element_located((By.TAG_NAME, "article"))
226
+ )
227
+ status_updates.append("Found posts on feed")
228
 
229
+ while likes_count < max_likes and scroll_count < max_scrolls:
230
+ # Find like buttons
231
+ like_buttons = driver.find_elements(By.XPATH,
232
+ "//article//section//button//*[contains(@aria-label, 'Like') and not(contains(@aria-label, 'Unlike'))]/../.."
233
+ )
234
 
235
+ status_updates.append(f"Found {len(like_buttons)} like buttons on scroll {scroll_count}")
236
+
237
+ if len(like_buttons) == 0 and scroll_count > 5:
238
+ status_updates.append("No more like buttons found. Stopping.")
239
+ break
240
+
241
+ # Click like buttons
242
+ for i, button in enumerate(like_buttons):
243
+ if likes_count >= max_likes:
244
  break
245
 
246
+ try:
247
+ # Scroll to button
248
+ driver.execute_script("arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'});", button)
249
+ time.sleep(1)
250
 
251
+ # Click like
252
+ button.click()
253
+ likes_count += 1
254
+ status_updates.append(f"Liked post {likes_count}/{max_likes}")
255
+
256
+ # Take screenshot occasionally
257
+ if likes_count % 5 == 0:
258
+ try:
259
+ like_screenshot = f"screenshots/like_{likes_count}_{int(time.time())}.png"
260
+ driver.save_screenshot(like_screenshot)
261
+ image_path = like_screenshot
262
+ except:
263
+ pass
264
+
265
+ # Wait between likes
266
+ time.sleep(2)
267
+ except Exception as e:
268
+ status_updates.append(f"Error liking post {i+1}: {str(e)}")
269
+ continue
 
 
 
 
 
 
270
 
271
+ # Scroll down to load more
272
+ driver.execute_script("window.scrollBy(0, 1000);")
273
+ status_updates.append(f"Scrolled down to load more posts")
274
+ time.sleep(3)
275
+ scroll_count += 1
276
+
277
+ # Final status
278
+ final_message = f"Finished! Liked {likes_count} posts."
279
+ status_updates.append(final_message)
280
 
281
  except Exception as e:
282
+ status_updates.append(f"Error finding or liking posts: {str(e)}")
283
 
284
+ except Exception as e:
285
+ status_updates.append(f"Error with login form: {str(e)}")
286
+
287
+ # Close the browser
288
+ driver.quit()
289
+ status_updates.append("Browser closed")
290
+
291
  except Exception as e:
292
  error_message = f"Error: {str(e)}"
293
  logger.error(error_message)
294
  status_updates.append(error_message)
295
+ status_updates.append(traceback.format_exc())
296
 
297
  return "\n".join(status_updates), image_path
298
 
299
+ def run_with_playwright(username, password, max_likes):
300
+ """Run the Instagram auto-liker with Playwright"""
301
+ status_updates = ["Starting Instagram Auto-Liker with Playwright..."]
302
+ image_path = save_placeholder_image("start")
303
+
304
+ try:
305
+ from playwright.sync_api import sync_playwright
306
+
307
+ with sync_playwright() as p:
308
+ browser = p.chromium.launch(
309
+ headless=True,
310
+ args=['--no-sandbox', '--disable-dev-shm-usage']
311
+ )
312
+
313
+ # Rest of Playwright code...
314
+ # (Similar to previous implementation but with better error handling)
315
+
316
+ except ImportError:
317
+ status_updates.append("Playwright not available. Using Selenium instead.")
318
+ return run_with_selenium(username, password, max_likes)
319
+ except Exception as e:
320
+ error_message = f"Error with Playwright: {str(e)}"
321
+ logger.error(error_message)
322
+ status_updates.append(error_message)
323
+ status_updates.append("Falling back to Selenium...")
324
+ return run_with_selenium(username, password, max_likes)
325
+
326
+ def login_and_like_posts(username, password, max_likes):
327
+ """Main entry point - tries Playwright first, falls back to Selenium"""
328
+ # Install dependencies first
329
+ install_msg = install_playwright()
330
+
331
+ # First try with Selenium which tends to be more reliable on Hugging Face
332
+ return run_with_selenium(username, password, max_likes)
333
+
334
  # Gradio Interface
335
  def create_interface():
336
  with gr.Blocks(title="Instagram Auto-Liker") as app:
 
358
 
359
  # Launch the app
360
  if __name__ == "__main__":
361
+ # Install dependencies first
362
+ print("Installing dependencies...")
363
+ install_msg = install_playwright()
364
+ print(install_msg)
365
+
366
+ # Start the app
367
+ print("Starting the application...")
368
  app = create_interface()
369
  app.launch(server_name="0.0.0.0", server_port=7860, share=True)