nakas commited on
Commit
65eb2e7
·
verified ·
1 Parent(s): f5cec4d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +322 -0
app.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import time
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ from PIL import Image
7
+ import io
8
+ import base64
9
+ import logging
10
+ from datetime import datetime
11
+ from playwright.sync_api import sync_playwright
12
+
13
+ # Configure logging
14
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Create screenshots directory if it doesn't exist
18
+ os.makedirs('screenshots', exist_ok=True)
19
+
20
+ def install_playwright_browsers():
21
+ """Install required Playwright browsers"""
22
+ try:
23
+ # Check if browsers are already installed
24
+ if not os.path.exists(os.path.expanduser('~/.cache/ms-playwright')):
25
+ logger.info("Installing Playwright browsers...")
26
+ result = subprocess.run(
27
+ [sys.executable, "-m", "playwright", "install", "chromium"],
28
+ check=True,
29
+ capture_output=True,
30
+ text=True
31
+ )
32
+ logger.info(f"Playwright browsers installed successfully")
33
+ return "Playwright browsers installed successfully."
34
+ else:
35
+ logger.info("Playwright browsers already installed")
36
+ return "Playwright browsers already installed."
37
+ except Exception as e:
38
+ error_msg = f"Error installing browsers: {e}"
39
+ logger.error(error_msg)
40
+ return error_msg
41
+
42
+ def encode_image_to_base64(image_path):
43
+ """Convert an image to base64 for display in Gradio"""
44
+ try:
45
+ with open(image_path, "rb") as img_file:
46
+ return base64.b64encode(img_file.read()).decode('utf-8')
47
+ except Exception as e:
48
+ logger.error(f"Error encoding image: {e}")
49
+ return None
50
+
51
+ def save_screenshot(page, name):
52
+ """Save a screenshot and return path"""
53
+ try:
54
+ timestamp = int(time.time())
55
+ filename = f"screenshots/{name}_{timestamp}.png"
56
+ page.screenshot(path=filename)
57
+ logger.info(f"Saved screenshot: {filename}")
58
+ return filename
59
+ except Exception as e:
60
+ logger.error(f"Error taking screenshot: {e}")
61
+ return None
62
+
63
+ def login_and_like_posts(username, password, max_likes):
64
+ """Main function to login to Instagram and like posts"""
65
+ status_updates = []
66
+ image_path = None
67
+
68
+ # First run browser installation if needed
69
+ install_msg = install_playwright_browsers()
70
+ status_updates.append(install_msg)
71
+
72
+ with sync_playwright() as p:
73
+ status_updates.append("Launching browser...")
74
+ browser = p.chromium.launch(
75
+ headless=True,
76
+ args=['--no-sandbox', '--disable-dev-shm-usage']
77
+ )
78
+
79
+ # Create a context with realistic user agent
80
+ context = browser.new_context(
81
+ 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',
82
+ viewport={'width': 1280, 'height': 720}
83
+ )
84
+
85
+ # Create a new page
86
+ page = context.new_page()
87
+
88
+ try:
89
+ # First test browser by visiting a simple site
90
+ status_updates.append("Testing browser connection...")
91
+ page.goto("https://www.google.com")
92
+ page.wait_for_load_state("networkidle")
93
+ status_updates.append(f"Browser working. Title: {page.title()}")
94
+
95
+ # Take test screenshot
96
+ test_screenshot = save_screenshot(page, "browser_test")
97
+ image_path = test_screenshot
98
+ status_updates.append(f"Browser test screenshot saved")
99
+
100
+ # Instagram login
101
+ status_updates.append("Navigating to Instagram...")
102
+ page.goto("https://www.instagram.com/")
103
+ page.wait_for_load_state("networkidle")
104
+
105
+ # Take screenshot of Instagram landing
106
+ landing_screenshot = save_screenshot(page, "instagram_landing")
107
+ image_path = landing_screenshot
108
+ status_updates.append("Instagram home page loaded")
109
+
110
+ # Handle cookie consent if present
111
+ if page.query_selector('text=Accept All') or page.query_selector('text=Allow All Cookies'):
112
+ status_updates.append("Handling cookie consent...")
113
+
114
+ # Try different button text variants
115
+ for button_text in ["Accept All", "Allow All Cookies", "Accept"]:
116
+ try:
117
+ if page.query_selector(f'text="{button_text}"'):
118
+ page.click(f'text="{button_text}"')
119
+ status_updates.append(f"Clicked '{button_text}' button")
120
+ page.wait_for_timeout(2000)
121
+ break
122
+ except:
123
+ continue
124
+
125
+ # Wait for and fill login form
126
+ status_updates.append("Looking for login form...")
127
+ page.wait_for_selector('input[name="username"]', state="visible", timeout=15000)
128
+
129
+ # Take pre-login screenshot
130
+ pre_login_screenshot = save_screenshot(page, "pre_login")
131
+ image_path = pre_login_screenshot
132
+
133
+ # Enter credentials
134
+ status_updates.append(f"Entering username: {username}")
135
+ page.fill('input[name="username"]', username)
136
+ page.fill('input[name="password"]', password)
137
+ status_updates.append("Credentials entered")
138
+
139
+ # Take post-credentials screenshot
140
+ creds_screenshot = save_screenshot(page, "credentials_entered")
141
+ image_path = creds_screenshot
142
+
143
+ # Click login button
144
+ status_updates.append("Clicking login button...")
145
+ page.click('button[type="submit"]')
146
+
147
+ # Wait for navigation
148
+ page.wait_for_load_state("networkidle")
149
+ page.wait_for_timeout(5000) # Additional wait for elements
150
+
151
+ # Take post-login screenshot
152
+ post_login_screenshot = save_screenshot(page, "post_login")
153
+ image_path = post_login_screenshot
154
+
155
+ # Check login status
156
+ if page.url == "https://www.instagram.com/accounts/login/":
157
+ # Still on login page - check for error messages
158
+ error_message = None
159
+ for error_selector in ['#slfErrorAlert', 'text=incorrect password', 'text=Please try again']:
160
+ try:
161
+ error_elem = page.query_selector(error_selector)
162
+ if error_elem:
163
+ error_message = error_elem.text_content().strip()
164
+ break
165
+ except:
166
+ pass
167
+
168
+ if error_message:
169
+ status_updates.append(f"Login failed: {error_message}")
170
+ return "\n".join(status_updates), image_path
171
+ else:
172
+ status_updates.append("Login failed: Reason unknown")
173
+ return "\n".join(status_updates), image_path
174
+
175
+ # Handle "Save Login Info" popup if it appears
176
+ try:
177
+ if page.query_selector('text="Not Now"'):
178
+ page.click('text="Not Now"')
179
+ status_updates.append("Dismissed 'Save Login Info' popup")
180
+ page.wait_for_timeout(2000)
181
+ except:
182
+ pass
183
+
184
+ # Handle notifications popup if it appears
185
+ try:
186
+ if page.query_selector('text="Not Now"'):
187
+ page.click('text="Not Now"')
188
+ status_updates.append("Dismissed notifications popup")
189
+ page.wait_for_timeout(2000)
190
+ except:
191
+ pass
192
+
193
+ # Verify we're on the feed
194
+ feed_screenshot = save_screenshot(page, "feed")
195
+ image_path = feed_screenshot
196
+ status_updates.append("Successfully logged in! On Instagram feed now.")
197
+
198
+ # Start liking posts
199
+ status_updates.append(f"Starting to like posts (target: {max_likes})...")
200
+
201
+ # Check for presence of articles (posts)
202
+ try:
203
+ page.wait_for_selector('article', timeout=10000)
204
+ status_updates.append("Found posts on feed")
205
+ except:
206
+ status_updates.append("Could not find any posts on feed")
207
+ return "\n".join(status_updates), image_path
208
+
209
+ # Like posts
210
+ likes_count = 0
211
+ scroll_count = 0
212
+ max_scrolls = 30
213
+
214
+ while likes_count < max_likes and scroll_count < max_scrolls:
215
+ # Find all like buttons (heart icons) that aren't already liked
216
+ like_buttons = page.query_selector_all('article svg[aria-label="Like"]')
217
+
218
+ status_updates.append(f"Found {len(like_buttons)} like buttons on scroll {scroll_count}")
219
+
220
+ # Take screenshot after finding buttons
221
+ if scroll_count % 3 == 0: # Every 3rd scroll
222
+ scroll_screenshot = save_screenshot(page, f"scroll_{scroll_count}")
223
+ image_path = scroll_screenshot
224
+
225
+ if len(like_buttons) == 0 and scroll_count > 5:
226
+ status_updates.append("No more like buttons found. Stopping.")
227
+ break
228
+
229
+ # Click like buttons
230
+ for button in like_buttons:
231
+ if likes_count >= max_likes:
232
+ break
233
+
234
+ try:
235
+ # Scroll to button
236
+ button.scroll_into_view_if_needed()
237
+ page.wait_for_timeout(500)
238
+
239
+ # Click like
240
+ button.click()
241
+ likes_count += 1
242
+ status_updates.append(f"Liked post {likes_count}/{max_likes}")
243
+
244
+ # Take screenshot occasionally
245
+ if likes_count % 5 == 0:
246
+ like_screenshot = save_screenshot(page, f"like_{likes_count}")
247
+ image_path = like_screenshot
248
+
249
+ # Wait between likes to avoid rate limiting
250
+ page.wait_for_timeout(2000)
251
+ except Exception as e:
252
+ status_updates.append(f"Error liking post: {str(e)}")
253
+ continue
254
+
255
+ # Scroll down to load more
256
+ page.evaluate("window.scrollBy(0, 1000)")
257
+ status_updates.append(f"Scrolled down to load more posts")
258
+ page.wait_for_timeout(3000) # Wait for content to load
259
+ scroll_count += 1
260
+
261
+ # Final status and screenshot
262
+ final_message = f"Finished! Liked {likes_count} posts."
263
+ status_updates.append(final_message)
264
+
265
+ final_screenshot = save_screenshot(page, "final")
266
+ image_path = final_screenshot
267
+
268
+ return "\n".join(status_updates), image_path
269
+
270
+ except Exception as e:
271
+ error_message = f"Error occurred: {str(e)}"
272
+ logger.error(error_message)
273
+ status_updates.append(error_message)
274
+
275
+ # Try to take error screenshot
276
+ try:
277
+ error_screenshot = save_screenshot(page, "error")
278
+ image_path = error_screenshot
279
+ except:
280
+ pass
281
+
282
+ return "\n".join(status_updates), image_path
283
+
284
+ finally:
285
+ try:
286
+ browser.close()
287
+ status_updates.append("Browser closed")
288
+ except:
289
+ pass
290
+
291
+ # Gradio Interface
292
+ def create_interface():
293
+ with gr.Blocks(title="Instagram Auto-Liker") as app:
294
+ gr.Markdown("# Instagram Auto-Liker")
295
+ gr.Markdown("Enter your Instagram credentials and the number of posts to like.")
296
+
297
+ with gr.Row():
298
+ with gr.Column(scale=1):
299
+ username = gr.Textbox(label="Instagram Username")
300
+ password = gr.Textbox(label="Instagram Password", type="password")
301
+ max_likes = gr.Slider(minimum=1, maximum=100, value=10, step=1, label="Number of Posts to Like")
302
+ submit_btn = gr.Button("Start Liking Posts")
303
+
304
+ with gr.Column(scale=2):
305
+ status_output = gr.Textbox(label="Status Log", lines=15)
306
+ image_output = gr.Image(label="Latest Screenshot", type="filepath")
307
+
308
+ submit_btn.click(
309
+ fn=login_and_like_posts,
310
+ inputs=[username, password, max_likes],
311
+ outputs=[status_output, image_output]
312
+ )
313
+
314
+ # Installation check on startup
315
+ gr.HTML(f"<p>Checking Playwright installation...</p>")
316
+
317
+ return app
318
+
319
+ # Launch the app
320
+ if __name__ == "__main__":
321
+ app = create_interface()
322
+ app.launch()