control_opened_browser_v2.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. 连接已打开的 AdsPower 浏览器,在新标签页执行搜索,不重新启动/断开 Playwright 连接,浏览器保持打开
  3. """
  4. import time
  5. import random
  6. import argparse
  7. from pathlib import Path
  8. from urllib.parse import urlencode
  9. from playwright.sync_api import sync_playwright
  10. try:
  11. from .ads_power_client import AdsPowerClient
  12. except ImportError:
  13. import sys
  14. sys.path.insert(0, str(Path(__file__).parent))
  15. from ads_power_client import AdsPowerClient
  16. def get_active_ws_endpoint(base_url: str, profile_id: str) -> str:
  17. """通过 AdsPower API 获取已打开浏览器的 ws endpoint"""
  18. import requests
  19. url = f"{base_url}/api/v1/browser/active"
  20. resp = requests.get(url, params={"user_id": profile_id}, timeout=10)
  21. resp.raise_for_status()
  22. data = resp.json()
  23. if data.get("code") != 0:
  24. raise RuntimeError(f"获取活动浏览器失败: {data}")
  25. ws = data["data"]["ws"]["puppeteer"]
  26. return ws
  27. def control_opened_browser(
  28. profile_id: str,
  29. query: str = "concessionnaire voiture Casablanca",
  30. ads_power_url: str = "http://127.0.0.1:50325",
  31. screenshot_path: str = "facebook_dealer_controlled.png",
  32. stay_seconds: int = 60
  33. ):
  34. """连接已打开的浏览器,在新标签页搜索摩洛哥汽车经销商"""
  35. ws_endpoint = get_active_ws_endpoint(ads_power_url, profile_id)
  36. print(f"连接到已打开的浏览器: {ws_endpoint}")
  37. playwright = sync_playwright().start()
  38. browser = playwright.chromium.connect_over_cdp(ws_endpoint)
  39. # 新建标签页,避免影响用户当前页面
  40. context = browser.contexts[0] if browser.contexts else browser.new_context()
  41. page = context.new_page()
  42. print("已新建标签页")
  43. try:
  44. # 构建 Facebook 搜索 URL
  45. encoded_query = urlencode({"q": query})
  46. search_url = f"https://www.facebook.com/search/pages/?{encoded_query}"
  47. print(f"在新标签页访问搜索页: {search_url}")
  48. page.goto(search_url, wait_until="domcontentloaded", timeout=60000)
  49. time.sleep(random.uniform(5, 8))
  50. # 截图搜索结果
  51. try:
  52. page.screenshot(path=f"{screenshot_path}_search.png", full_page=False, timeout=60000)
  53. print(f"搜索结果已截图: {screenshot_path}_search.png")
  54. except Exception as e:
  55. print(f"搜索结果截图失败: {e}")
  56. # 收集页面链接
  57. links = set()
  58. elements = page.query_selector_all('a[href*="/"]')
  59. for el in elements:
  60. href = el.get_attribute("href")
  61. if href and _is_valid_page_link(href):
  62. links.add(_normalize_url(href))
  63. links = list(links)
  64. print(f"找到 {len(links)} 个可能的主页链接")
  65. if not links:
  66. print("未找到任何主页链接")
  67. return
  68. # 访问第一个主页
  69. first_link = links[0]
  70. print(f"准备进入第一个主页: {first_link}")
  71. page.goto(first_link, wait_until="domcontentloaded", timeout=60000)
  72. time.sleep(random.uniform(4, 6))
  73. # 截图主页
  74. try:
  75. page.screenshot(path=screenshot_path, full_page=False, timeout=60000)
  76. print(f"主页已截图: {screenshot_path}")
  77. except Exception as e:
  78. print(f"主页截图失败: {e}")
  79. print(f"当前页面标题: {page.title()}")
  80. print(f"当前 URL: {page.url}")
  81. # 停留,不断开 Playwright 连接,浏览器保持打开
  82. print(f"浏览器将停留 {stay_seconds} 秒,不执行任何发送操作,也不断开 Playwright 连接,浏览器保持打开...")
  83. print("你可以在自己的电脑屏幕上看到这个窗口")
  84. time.sleep(stay_seconds)
  85. finally:
  86. # 不断开 Playwright 连接,浏览器保持打开,只停止 Playwright(保持浏览器窗口打开)
  87. print("停止 Playwright,浏览器窗口保持打开")
  88. playwright.stop()
  89. def _is_valid_page_link(href: str) -> bool:
  90. from urllib.parse import urlparse
  91. parsed = urlparse(href)
  92. if parsed.netloc not in ["www.facebook.com", "facebook.com", "m.facebook.com"]:
  93. return False
  94. excluded = ["/search/", "/watch", "/groups", "/marketplace",
  95. "/messages", "/notifications", "/settings",
  96. "/photo.php", "/videos", "/posts", "/reel",
  97. "/profile.php"] # 排除个人资料页
  98. for pattern in excluded:
  99. if pattern in parsed.path:
  100. return False
  101. path = parsed.path.strip("/")
  102. if not path or "/" in path:
  103. return False
  104. return True
  105. def _normalize_url(url: str) -> str:
  106. from urllib.parse import urlparse
  107. parsed = urlparse(url)
  108. path = parsed.path.strip("/").split("/")[0]
  109. return f"https://www.facebook.com/{path}/"
  110. def main():
  111. parser = argparse.ArgumentParser(description="控制已打开的 AdsPower 浏览器访问 Facebook 经销商主页")
  112. parser.add_argument("--profile-id", required=True, help="AdsPower profile ID")
  113. parser.add_argument("--query", default="concessionnaire voiture Casablanca", help="搜索关键词")
  114. parser.add_argument("--ads-power-url", default="http://127.0.0.1:50325", help="AdsPower API URL")
  115. parser.add_argument("--screenshot", default="D:/WEFANBOT/facebook_dealer_controlled.png", help="截图保存路径")
  116. parser.add_argument("--stay", type=int, default=60, help="停留秒数")
  117. args = parser.parse_args()
  118. control_opened_browser(
  119. profile_id=args.profile_id,
  120. query=args.query,
  121. ads_power_url=args.ads_power_url,
  122. screenshot_path=args.screenshot,
  123. stay_seconds=args.stay
  124. )
  125. if __name__ == "__main__":
  126. main()