""" AdsPower + Playwright CDP 集成测试 演示如何通过 CDP 连接到 AdsPower 指纹浏览器 """ from loguru import logger from adspower_client import AdsPowerClient from config import Config import sys # 配置日志 logger.remove() logger.add( sys.stdout, format="{time:HH:mm:ss} | {level: <8} | {message}", level="INFO" ) def test_adspower_connection(use_proxy: bool = False, proxy_info: dict = None, use_api_v1: bool = False): """测试 AdsPower + Playwright CDP 连接 Args: use_proxy: 是否使用大麦IP代理 proxy_info: 已获取的代理信息 use_api_v1: 是否使用API v1方式更新代理 """ # ==================== 配置区 ==================== # 访问的网页地址,在这里修改 TEST_URL = "https://health.baidu.com/m/detail/ar_2366617956693492811" # IP检测网站,可查看代理是否生效 # 其他可选项: # TEST_URL = "https://www.baidu.com" # 百度 # TEST_URL = "https://www.google.com" # Google # TEST_URL = "https://你的MIP页面地址" # 你的目标网页 # ===================================================== client = AdsPowerClient() try: # 0. 先查询 Profile 列表 logger.info("=" * 60) logger.info("步骤 0: 查询 Profile 列表") logger.info("=" * 60) result = client.list_profiles() if not result: logger.error("查询 Profile 失败") return False profiles = result.get('data', {}).get('list', []) if not profiles: logger.error("没有可用的 Profile,请先在 AdsPower 中创建 Profile") return False # 使用第一个 Profile first_profile = profiles[0] profile_id = first_profile.get('profile_id') profile_name = first_profile.get('name', 'N/A') logger.info(f"将使用 Profile: {profile_name} (ID: {profile_id})") logger.info("") # 1. 启动 AdsPower 浏览器(可选使用代理) logger.info("=" * 60) logger.info(f"步骤 1: {'[使用代理] ' if use_proxy else ''}启动 AdsPower 浏览器") if use_proxy: logger.info(f"代理更新方式: {'API v1 (直接传入proxy_config)' if use_api_v1 else 'API v2 (使用proxy_id引用)'}") logger.info("=" * 60) if use_proxy and proxy_info: if use_api_v1: # 使用 API v1 方式:直接传入 proxy_config logger.info("使用 API v1 方式更新代理...") proxy_config_v1 = { "proxy_type": "http", "proxy_host": proxy_info["host"], "proxy_port": proxy_info["port"], "proxy_user": client.DAMAI_USER, "proxy_password": client.DAMAI_PASSWORD, "proxy_soft": "other" } # 直接更新 Profile success = client.update_profile_proxy_v1(profile_id, proxy_config_v1) if not success: logger.warning("更新代理失败 (API v1),将不使用代理启动") else: # 使用 API v2 方式:先创建代理,再引用 logger.info("使用 API v2 方式更新代理...") proxy_config = { "type": "http", "host": proxy_info["host"], "port": proxy_info["port"], "user": client.DAMAI_USER, "password": client.DAMAI_PASSWORD, "ipchecker": "ip2location", "remark": "Damai Auto Proxy" } # 创建代理 proxy_id = client.create_proxy(proxy_config) if proxy_id: # 更新 Profile client.update_profile_proxy(profile_id, proxy_id) else: logger.warning("创建代理失败,将不使用代理启动") browser_info = client.start_browser(user_id=profile_id) else: browser_info = client.start_browser(user_id=profile_id) if not browser_info: logger.error("启动 AdsPower 浏览器失败") return False logger.info(f"浏览器信息: {browser_info}") # 2. 通过 CDP 连接到浏览器 logger.info("") logger.info("=" * 60) logger.info("步骤 2: 通过 CDP 连接到浏览器") logger.info("=" * 60) browser = client.connect_browser(browser_info) if not browser: logger.error("CDP 连接失败") return False logger.info(f"浏览器版本: {browser.version}") logger.info(f"上下文数量: {len(browser.contexts)}") # 3. 获取页面 logger.info("") logger.info("=" * 60) logger.info("步骤 3: 获取浏览器页面") logger.info("=" * 60) page = client.get_page(browser) if not page: logger.error("获取页面失败") return False logger.info(f"页面 URL: {page.url}") # 3.5. 关闭其他标签页,只保留AdsPower启动页 logger.info("") logger.info("=" * 60) logger.info("步骤 3.5: 清理多余标签页") logger.info("=" * 60) context = browser.contexts[0] all_pages = context.pages logger.info(f"当前打开的标签页数: {len(all_pages)}") # 遍历所有页面,关闭非 AdsPower 启动页 closed_count = 0 for p in all_pages: try: page_url = p.url # 保留 AdsPower 启动页 if 'start.adspower.net' in page_url: logger.info(f"保留启动页: {page_url}") else: logger.info(f"关闭标签页: {page_url}") p.close() closed_count += 1 except Exception as e: logger.warning(f"关闭页面失败: {str(e)}") logger.info(f"已关闭 {closed_count} 个标签页") # 重新获取当前页面列表 remaining_pages = context.pages logger.info(f"剩余标签页数: {len(remaining_pages)}") # 如果所有页面都被关闭了,创建一个新页面 if len(remaining_pages) == 0: logger.info("所有页面已关闭,创建新标签页") page = context.new_page() else: # 使用第一个剩余页面 page = remaining_pages[0] logger.info(f"使用剩余页面: {page.url}") # 4. 测试页面操作 logger.info("") logger.info("=" * 60) logger.info("步骤 4: 测试页面操作") logger.info("=" * 60) # 访问配置的网页 logger.info(f"访问测试页面: {TEST_URL}") page.goto(TEST_URL, wait_until='domcontentloaded') # 等待广告接口响应完成 logger.info("等待广告接口响应...") try: # 等待广告接口请求完成 response = page.wait_for_response( lambda r: 'getRefreshAdAssets' in r.url and r.status == 200, timeout=10000 # 10秒超时 ) logger.info(f"广告接口已响应: {response.url}") # 等待DOM更新 import time time.sleep(2) except Exception as e: logger.warning(f"等待广告接口超时或失败: {str(e)}") logger.info("继续执行...") import time time.sleep(2) # 获取页面标题 title = page.title() logger.info(f"页面标题: {title}") # 获取页面 URL current_url = page.url logger.info(f"当前 URL: {current_url}") # 截图测试(点击前) screenshot_path = "./test_screenshot_before.png" page.screenshot(path=screenshot_path) logger.info(f"截图已保存: {screenshot_path}") # 查找并点击广告 logger.info("") logger.info("-" * 60) logger.info("开始查找广告元素...") try: # 查找所有广告元素 ad_selector = 'span.ec-tuiguang.ecfc-tuiguang.xz81bbe' ad_elements = page.locator(ad_selector) ad_count = ad_elements.count() logger.info(f"找到 {ad_count} 个广告元素") if ad_count > 0: # 点击第一个广告 logger.info("准备点击第一个广告...") # 滚动到元素可见 first_ad = ad_elements.first first_ad.scroll_into_view_if_needed() time.sleep(1) # 点击广告 first_ad.click() logger.info("✅ 已点击第一个广告") # 等待页面跳转 time.sleep(3) # 获取点击后的页面信息 new_url = page.url new_title = page.title() logger.info(f"点击后 URL: {new_url}") logger.info(f"点击后标题: {new_title}") # 截图(点击后) screenshot_path_after = "./test_screenshot_after.png" page.screenshot(path=screenshot_path_after) logger.info(f"点击后截图已保存: {screenshot_path_after}") else: logger.warning("⚠ 未找到广告元素") except Exception as e: logger.error(f"查找/点击广告失败: {str(e)}") # 保存错误时的截图 page.screenshot(path="./test_screenshot_error.png") logger.info("错误截图已保存: ./test_screenshot_error.png") # 5. 清理资源 logger.info("") logger.info("=" * 60) logger.info("步骤 5: 测试完成") logger.info("=" * 60) # 注意:不停止浏览器,保持运行状态供手动操作 logger.info("浏览器保持运行状态,可继续手动操作") logger.info("如需停止浏览器,请在AdsPower中手动关闭") logger.info("") logger.info("=" * 60) logger.info("测试完成!浏览器未关闭") logger.info("=" * 60) return True except Exception as e: logger.error(f"测试异常: {str(e)}") return False finally: # 注意:不自动清理资源,保持浏览器运行 pass def test_multiple_pages(): """测试多页面操作""" client = AdsPowerClient() profile_id = None try: logger.info("=" * 60) logger.info("测试多页面操作") logger.info("=" * 60) # 查询 Profile result = client.list_profiles() if not result: return False profiles = result.get('data', {}).get('list', []) if not profiles: logger.error("没有可用的 Profile") return False profile_id = profiles[0].get('profile_id') # 启动并连接 browser_info = client.start_browser(user_id=profile_id) if not browser_info: return False browser = client.connect_browser(browser_info) if not browser: return False # 获取第一个页面 page1 = client.get_page(browser) logger.info("访问百度...") page1.goto("https://www.baidu.com") logger.info(f"页面1标题: {page1.title()}") # 创建新页面 context = browser.contexts[0] page2 = context.new_page() logger.info("访问必应...") page2.goto("https://www.bing.com") logger.info(f"页面2标题: {page2.title()}") logger.info(f"当前打开的页面数: {len(context.pages)}") # 关闭页面 page2.close() logger.info("已关闭页面2") return True except Exception as e: logger.error(f"测试异常: {str(e)}") return False finally: try: if profile_id: client.stop_browser(user_id=profile_id) else: client.stop_browser() except: pass if __name__ == "__main__": logger.info("开始测试 AdsPower + Playwright CDP 集成") logger.info("") logger.info(f"当前环境: {Config.ENV}") logger.info(f"AdsPower API: {Config.ADSPOWER_API_URL}") logger.info("") # 创建客户端 client = AdsPowerClient() # ==================== 配置区 ==================== # 默认使用代理,如不需要改为 False use_proxy = True # 默认使用 API v2 Direct 方式(0=v2 proxy_id, 1=v1, 2=v2 direct) use_api_v1 = True # True=API v1, False=API v2 # ===================================================== proxy_info = None # 如果使用代理,提前获取 if use_proxy: logger.info("") logger.info(f"使用代理模式: {'API v1 (直接传入proxy_config)' if use_api_v1 else 'API v2 (使用proxy_id引用)'}") logger.info("步骤 0: 提前获取大麦IP代理") proxy_info = client.get_damai_proxy() if not proxy_info: logger.error("获取代理失败,终止测试") sys.exit(1) logger.info(f"代理地址: {proxy_info['host']}:{proxy_info['port']}") logger.info("") # 测试基本连接 if test_adspower_connection(use_proxy=use_proxy, proxy_info=proxy_info, use_api_v1=use_api_v1): logger.info("\n基本连接测试通过\n") else: logger.error("\n基本连接测试失败\n") sys.exit(1) # 测试多页面操作 # if test_multiple_pages(): # logger.info("\n多页面操作测试通过\n") # else: # logger.error("\n多页面操作测试失败\n")