import gradio as gr import time import os import subprocess import sys from PIL import Image import io import base64 import logging from datetime import datetime from playwright.sync_api import sync_playwright # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # Create screenshots directory if it doesn't exist os.makedirs('screenshots', exist_ok=True) def install_playwright_browsers(): """Install required Playwright browsers""" try: # Check if browsers are already installed if not os.path.exists(os.path.expanduser('~/.cache/ms-playwright')): logger.info("Installing Playwright browsers...") result = subprocess.run( [sys.executable, "-m", "playwright", "install", "chromium"], check=True, capture_output=True, text=True ) logger.info(f"Playwright browsers installed successfully") return "Playwright browsers installed successfully." else: logger.info("Playwright browsers already installed") return "Playwright browsers already installed." except Exception as e: error_msg = f"Error installing browsers: {e}" logger.error(error_msg) return error_msg def encode_image_to_base64(image_path): """Convert an image to base64 for display in Gradio""" try: with open(image_path, "rb") as img_file: return base64.b64encode(img_file.read()).decode('utf-8') except Exception as e: logger.error(f"Error encoding image: {e}") return None def save_screenshot(page, name): """Save a screenshot and return path""" try: timestamp = int(time.time()) filename = f"screenshots/{name}_{timestamp}.png" page.screenshot(path=filename) logger.info(f"Saved screenshot: {filename}") return filename except Exception as e: logger.error(f"Error taking screenshot: {e}") return None def login_and_like_posts(username, password, max_likes): """Main function to login to Instagram and like posts""" status_updates = [] image_path = None # First run browser installation if needed install_msg = install_playwright_browsers() status_updates.append(install_msg) with sync_playwright() as p: status_updates.append("Launching browser...") browser = p.chromium.launch( headless=True, args=['--no-sandbox', '--disable-dev-shm-usage'] ) # Create a context with realistic user agent context = browser.new_context( 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', viewport={'width': 1280, 'height': 720} ) # Create a new page page = context.new_page() try: # First test browser by visiting a simple site status_updates.append("Testing browser connection...") page.goto("https://www.google.com") page.wait_for_load_state("networkidle") status_updates.append(f"Browser working. Title: {page.title()}") # Take test screenshot test_screenshot = save_screenshot(page, "browser_test") image_path = test_screenshot status_updates.append(f"Browser test screenshot saved") # Instagram login status_updates.append("Navigating to Instagram...") page.goto("https://www.instagram.com/") page.wait_for_load_state("networkidle") # Take screenshot of Instagram landing landing_screenshot = save_screenshot(page, "instagram_landing") image_path = landing_screenshot status_updates.append("Instagram home page loaded") # Handle cookie consent if present if page.query_selector('text=Accept All') or page.query_selector('text=Allow All Cookies'): status_updates.append("Handling cookie consent...") # Try different button text variants for button_text in ["Accept All", "Allow All Cookies", "Accept"]: try: if page.query_selector(f'text="{button_text}"'): page.click(f'text="{button_text}"') status_updates.append(f"Clicked '{button_text}' button") page.wait_for_timeout(2000) break except: continue # Wait for and fill login form status_updates.append("Looking for login form...") page.wait_for_selector('input[name="username"]', state="visible", timeout=15000) # Take pre-login screenshot pre_login_screenshot = save_screenshot(page, "pre_login") image_path = pre_login_screenshot # Enter credentials status_updates.append(f"Entering username: {username}") page.fill('input[name="username"]', username) page.fill('input[name="password"]', password) status_updates.append("Credentials entered") # Take post-credentials screenshot creds_screenshot = save_screenshot(page, "credentials_entered") image_path = creds_screenshot # Click login button status_updates.append("Clicking login button...") page.click('button[type="submit"]') # Wait for navigation page.wait_for_load_state("networkidle") page.wait_for_timeout(5000) # Additional wait for elements # Take post-login screenshot post_login_screenshot = save_screenshot(page, "post_login") image_path = post_login_screenshot # Check login status if page.url == "https://www.instagram.com/accounts/login/": # Still on login page - check for error messages error_message = None for error_selector in ['#slfErrorAlert', 'text=incorrect password', 'text=Please try again']: try: error_elem = page.query_selector(error_selector) if error_elem: error_message = error_elem.text_content().strip() break except: pass if error_message: status_updates.append(f"Login failed: {error_message}") return "\n".join(status_updates), image_path else: status_updates.append("Login failed: Reason unknown") return "\n".join(status_updates), image_path # Handle "Save Login Info" popup if it appears try: if page.query_selector('text="Not Now"'): page.click('text="Not Now"') status_updates.append("Dismissed 'Save Login Info' popup") page.wait_for_timeout(2000) except: pass # Handle notifications popup if it appears try: if page.query_selector('text="Not Now"'): page.click('text="Not Now"') status_updates.append("Dismissed notifications popup") page.wait_for_timeout(2000) except: pass # Verify we're on the feed feed_screenshot = save_screenshot(page, "feed") image_path = feed_screenshot status_updates.append("Successfully logged in! On Instagram feed now.") # Start liking posts status_updates.append(f"Starting to like posts (target: {max_likes})...") # Check for presence of articles (posts) try: page.wait_for_selector('article', timeout=10000) status_updates.append("Found posts on feed") except: status_updates.append("Could not find any posts on feed") return "\n".join(status_updates), image_path # Like posts likes_count = 0 scroll_count = 0 max_scrolls = 30 while likes_count < max_likes and scroll_count < max_scrolls: # Find all like buttons (heart icons) that aren't already liked like_buttons = page.query_selector_all('article svg[aria-label="Like"]') status_updates.append(f"Found {len(like_buttons)} like buttons on scroll {scroll_count}") # Take screenshot after finding buttons if scroll_count % 3 == 0: # Every 3rd scroll scroll_screenshot = save_screenshot(page, f"scroll_{scroll_count}") image_path = scroll_screenshot if len(like_buttons) == 0 and scroll_count > 5: status_updates.append("No more like buttons found. Stopping.") break # Click like buttons for button in like_buttons: if likes_count >= max_likes: break try: # Scroll to button button.scroll_into_view_if_needed() page.wait_for_timeout(500) # Click like button.click() likes_count += 1 status_updates.append(f"Liked post {likes_count}/{max_likes}") # Take screenshot occasionally if likes_count % 5 == 0: like_screenshot = save_screenshot(page, f"like_{likes_count}") image_path = like_screenshot # Wait between likes to avoid rate limiting page.wait_for_timeout(2000) except Exception as e: status_updates.append(f"Error liking post: {str(e)}") continue # Scroll down to load more page.evaluate("window.scrollBy(0, 1000)") status_updates.append(f"Scrolled down to load more posts") page.wait_for_timeout(3000) # Wait for content to load scroll_count += 1 # Final status and screenshot final_message = f"Finished! Liked {likes_count} posts." status_updates.append(final_message) final_screenshot = save_screenshot(page, "final") image_path = final_screenshot return "\n".join(status_updates), image_path except Exception as e: error_message = f"Error occurred: {str(e)}" logger.error(error_message) status_updates.append(error_message) # Try to take error screenshot try: error_screenshot = save_screenshot(page, "error") image_path = error_screenshot except: pass return "\n".join(status_updates), image_path finally: try: browser.close() status_updates.append("Browser closed") except: pass # Gradio Interface def create_interface(): with gr.Blocks(title="Instagram Auto-Liker") as app: gr.Markdown("# Instagram Auto-Liker") gr.Markdown("Enter your Instagram credentials and the number of posts to like.") with gr.Row(): with gr.Column(scale=1): username = gr.Textbox(label="Instagram Username") password = gr.Textbox(label="Instagram Password", type="password") max_likes = gr.Slider(minimum=1, maximum=100, value=10, step=1, label="Number of Posts to Like") submit_btn = gr.Button("Start Liking Posts") with gr.Column(scale=2): status_output = gr.Textbox(label="Status Log", lines=15) image_output = gr.Image(label="Latest Screenshot", type="filepath") submit_btn.click( fn=login_and_like_posts, inputs=[username, password, max_likes], outputs=[status_output, image_output] ) # Installation check on startup gr.HTML(f"

Checking Playwright installation...

") return app # Launch the app if __name__ == "__main__": app = create_interface() app.launch()