如何用Python实现WalletConnect授权?Selenium连Metamask遇Shadow DOM问题
问题描述
我想通过WalletConnect将MetaMask连接到站点https://sendit.arcana.network/app/login,目前用Selenium做自动化操作,但页面存在Shadow DOM,无法点击MetaMask图标,希望通过已有的WalletConnect链接完成钱包连接。
WalletConnect链接:wc:5f83a3ccbac958c359d6d176df0cd3ee506fb1a849246688ffc6cc9ca399026c@2?relay-protocol=irn&symKey=00b35938bf6b10e8a11cd2efc6df4c24bfc50f5f297f6031d85fef6e3eaf26a1
我的代码:
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from multiprocessing import Pool from utils import proxy_utils from seleniumwire import webdriver import config from fake_useragent import UserAgent def main(thread): while True: try: def expand_shadow_element(element): shadow_root = driver.execute_script(f'return arguments[0].shadowRoot', element) return shadow_root # Driver Options options = webdriver.ChromeOptions() options.add_argument(f'user-agent={fake_useragent.UserAgent()}') options.add_extension('extensions/metamask.crx') options.add_argument('--disable-blink-features=AutomationControlled') options.add_argument('--log-level=3') options.add_experimental_option('excludeSwitches', ['enable-logging']) proxy_options = proxy_utils.proxy_options(config.use_proxys) s = Service('utils/chromedriver.exe') driver = webdriver.Chrome(service=s, seleniumwire_options=proxy_options, options=options) wait = WebDriverWait(driver, 30) driver.get("https://sendit.arcana.network/app/login") wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="app"]/main/main/div/div[2]/div[2]/div/section/section/section[2]/div/button'))) driver.find_element(By.XPATH, '//*[@id="app"]/main/main/div/div[2]/div[2]/div/section/section/section[2]/div/button').click() root1 = driver.find_element(By.XPATH, '/html/body/w3m-modal[2]') shadow_root1 = expand_shadow_element(root1) root2 = shadow_root1.find_element(By.XPATH, '/div/div/w3m-modal-router') shadow_root2 = expand_shadow_element(root2[0]) except Exception as error: print(f"Error: {error}") finally: try: driver.quit() except: pass if __name__ == '__main__': with Pool(processes=config.threads) as pool: pool.map(main, range(config.threads))
解决方案
针对Shadow DOM无法点击MetaMask图标的问题,直接用WalletConnect链接完成连接的核心思路是绕过前端UI交互,直接调用连接逻辑,以下是两种可行方案:
方案一:直接注入WalletConnect连接逻辑
页面加载完成后,通过Selenium执行JavaScript代码,直接用给定的WalletConnect链接发起连接请求:
# 页面加载完成后执行以下代码 wc_link = "wc:5f83a3ccbac958c359d6d176df0cd3ee506fb1a849246688ffc6cc9ca399026c@2?relay-protocol=irn&symKey=00b35938bf6b10e8a11cd2efc6df4c24bfc50f5f297f6031d85fef6e3eaf26a1" # 先动态引入WalletConnect SDK(如果页面未加载) inject_sdk = """ const script = document.createElement('script'); script.src = 'https://unpkg.com/@walletconnect/client@2.10.1/dist/umd/index.min.js'; document.head.appendChild(script); await new Promise(resolve => script.onload = resolve); """ driver.execute_script("async function loadSDK() {" + inject_sdk + "} loadSDK();") # 发起连接请求 connect_script = f""" const client = await window.WalletConnect.init({{ uri: "{wc_link}" }}); await client.connect(); """ driver.execute_script("async function connect() {" + connect_script + "} connect();")
方案二:利用MetaMask扩展API处理连接
通过Selenium切换到MetaMask扩展页面,直接处理连接授权:
- 先获取MetaMask的扩展ID(Chrome扩展管理页面可查,默认ID为
nkbihfbeogaeaoehlefnkodbefgpgknn) - 切换到扩展页面完成授权:
# 切换到MetaMask扩展弹窗 metamask_id = "nkbihfbeogaeaoehlefnkodbefgpgknn" driver.get(f"chrome-extension://{metamask_id}/popup.html") # 等待授权按钮加载并点击(需根据实际页面元素调整定位) wait.until(EC.element_to_be_clickable((By.XPATH, '//button[contains(text(), "确认")]'))).click()
注意:此方法需要提前确保MetaMask已解锁并配置好目标账户。
备选:修复原Shadow DOM定位逻辑
如果仍想通过原UI交互完成,可修正Shadow DOM的定位代码,避免依赖绝对XPATH:
# 等待w3m-modal加载 root1 = wait.until(EC.presence_of_element_located((By.TAG_NAME, 'w3m-modal'))) shadow_root1 = expand_shadow_element(root1) # 获取w3m-modal-router的shadow root root2 = shadow_root1.find_element(By.TAG_NAME, 'w3m-modal-router') shadow_root2 = expand_shadow_element(root2) # 定位并点击MetaMask按钮 metamask_btn = shadow_root2.find_element(By.XPATH, '//button[contains(@class, "w3m-wallet-button") and .//span[text()="MetaMask"]]') metamask_btn.click()
内容的提问来源于stack exchange,提问作者Axcent
相关产品推荐
相关产品推荐

