# /// script # requires-python = ">=3.12" # dependencies = [ # "playwright", # ] # /// import asyncio import os import sys from playwright.async_api import async_playwright async def download_twitter_photo(url, output_dir="downloads"): if not os.path.exists(output_dir): os.makedirs(output_dir) async with async_playwright() as p: print("💡 正在启动浏览器补丁并安装内核 (如果是第一次运行可能会慢一点)...") # 确保安装浏览器内核 os.system("uv run playwright install chromium") browser = await p.chromium.launch(headless=True) context = await browser.new_context( viewport={'width': 1920, 'height': 1080}, 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" ) page = await context.new_page() print(f"🚀 正在访问推文地址: {url}") try: # 访问页面 await page.goto(url, wait_until="networkidle", timeout=60000) # 尝试定位图片 # Twitter 的图片通常在 article 里的 img 标签 print("📸 正在寻找图片元素...") images = await page.query_selector_all("img[src*='format=jpg'], img[src*='format=png']") if not images: print("❌ 未能找到有效的图片元素,推文可能涉及权限或加载失败。") await browser.close() return # 获取当前 URL 中指定的 photo/X 对应的图片,或者全部下载 for i, img in enumerate(images): src = await img.get_attribute("src") if "profile_images" in src or "emoji" in src: continue # 转换成原图链接 if "name=" in src: large_url = src.split("name=")[0] + "name=large" else: large_url = src + "&name=large" filename = f"twitter_image_{i}.jpg" save_path = os.path.join(output_dir, filename) print(f"📥 正在下载原图: {large_url}") img_response = await page.request.get(large_url) if img_response.status == 200: with open(save_path, "wb") as f: f.write(await img_response.body()) print(f"✅ 已保存至: {save_path}") except Exception as e: print(f"💥 运行出错: {e}") finally: await browser.close() if __name__ == "__main__": if len(sys.argv) < 2: print("用法: uv run scripts/twitter_browser_dl.py ") else: asyncio.run(download_twitter_photo(sys.argv[1]))