import feedparser import time import random from playwright.sync_api import sync_playwright import os X_USERNAME = os.environ.get("X_USERNAME") X_PASSWORD = os.environ.get("X_PASSWORD") RSS_FEEDS = [ "https://feeds.feedburner.com/TechCrunch", "https://www.theverge.com/rss/index.xml", "https://hnrss.org/frontpage", ] def get_tech_news(): all_items = [] for feed_url in RSS_FEEDS: try: feed = feedparser.parse(feed_url) for entry in feed.entries[:5]: title = entry.get("title", "") link = entry.get("link", "") if title and link: all_items.append(f"{title} {link}") except: continue return random.choice(all_items) if all_items else "Check out the latest in tech!" def login(page): print("Navigating to X login...") page.goto("https://twitter.com/i/flow/login", wait_until="networkidle", timeout=60000) page.wait_for_timeout(5000) print("Page loaded, looking for input...") # Try multiple selectors selectors = [ 'input[autocomplete="username"]', 'input[name="text"]', 'input[type="text"]', '[data-testid="ocfEnterTextTextInput"]', ] username_filled = False for selector in selectors: try: if page.locator(selector).is_visible(timeout=5000): page.locator(selector).fill(X_USERNAME) username_filled = True print(f"Username filled using: {selector}") break except: continue if not username_filled: print("Could not find username field!") return False page.keyboard.press("Enter") page.wait_for_timeout(4000) # Handle possible verification step for selector in selectors: try: if page.locator(selector).is_visible(timeout=3000): print("Verification step detected!") page.locator(selector).fill(X_USERNAME) page.keyboard.press("Enter") page.wait_for_timeout(3000) break except: continue # Fill password password_selectors = [ 'input[name="password"]', 'input[type="password"]', 'input[autocomplete="current-password"]', ] password_filled = False for selector in password_selectors: try: if page.locator(selector).is_visible(timeout=8000): page.locator(selector).fill(X_PASSWORD) password_filled = True print(f"Password filled using: {selector}") break except: continue if not password_filled: print("Could not find password field!") return False page.keyboard.press("Enter") page.wait_for_timeout(6000) print("Login done!") return True def post_tweet(page): try: news = get_tech_news() page.goto("https://twitter.com/compose/tweet", wait_until="networkidle", timeout=30000) page.wait_for_timeout(3000) tweet_selectors = [ '[data-testid="tweetTextarea_0"]', '.public-DraftEditor-content', '[contenteditable="true"]', ] for selector in tweet_selectors: try: if page.locator(selector).is_visible(timeout=5000): page.locator(selector).click() page.keyboard.type(news[:280]) page.wait_for_timeout(1000) break except: continue # Click tweet button btn_selectors = [ '[data-testid="tweetButtonInline"]', '[data-testid="tweetButton"]', ] for selector in btn_selectors: try: if page.locator(selector).is_visible(timeout=5000): page.locator(selector).click() break except: continue page.wait_for_timeout(3000) print(f"Posted: {news[:50]}...") except Exception as e: print(f"Post failed: {e}") def run_bot(): with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=[ "--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-blink-features=AutomationControlled", ] ) context = browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", viewport={"width": 1280, "height": 720}, locale="en-US", ) page = context.new_page() # Hide automation flags page.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") logged_in = login(page) if not logged_in: print("Login failed, exiting.") return while True: print("--- Starting post session ---") for i in range(5): post_tweet(page) print(f"Tweet {i+1}/5 done") time.sleep(720) print("--- Sleeping for 2 hours ---") time.sleep(7200) run_bot()