Spaces:
Sleeping
Sleeping
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"<p>Checking Playwright installation...</p>") | |
return app | |
# Launch the app | |
if __name__ == "__main__": | |
app = create_interface() | |
app.launch() |