如何提取PHP游戏网站动态HTML中的地雷位置?
获取PHP地雷游戏实时地雷位置并模拟点击
问题背景
- 目标为PHP开发的地雷游戏,页面HTML随用户操作动态更新
- 点击方块触发POST请求,地雷位置仅在提现或踩中地雷时才会显示
- 需要在点击方块前实时获取地雷位置的tile id,并模拟安全方块点击
- 代码需适配游戏胜负后HTML结构变化的情况
- 此前使用
requests编写的代码无效,核心原因是无法处理动态渲染的HTML(仅能处理静态网络请求)
无效的requests尝试代码
import requests import time def configure_game_params(): game_params = { "access-token": "39fa080b862e50c48c11a5a5f5a8034f53e1f7d76fb9fa5c4675fed1f1f482450c", "fp-userSeed": "SnuPVeYLOWKNACMDK12dyoEIooUuXm4iCLSwDprUta3FuRtHST74O3HRrz4qA0J7", "gameAccess": "true", "isClientSeedSet": "false", # Set to "true" or "false" as needed "user-email": "njongomagagula@gmail.com", "mines_bet": "0.00074249", # Replace with your actual value "color-scheme": "dark", "selectedCurrency": "DGB", } return game_params def construct_request_headers(): headers = { "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Bearer ae1ece19d806d9e6630429bac2cfb2f4a406b6ddc0a37af0856635880cb73d7e", } return headers def make_api_request(url, payload, headers, retries=3): for _ in range(retries): try: response = requests.post(url, json=payload, headers=headers) if response.status_code == 200: return response elif response.status_code == 429: print("Rate limit exceeded. Retrying after backoff.") time.sleep(2 ** _) else: print(f"Error: {response.status_code} - {response.text}") except requests.RequestException as e: print(f"Error: {e}") return None # Configure game parameters game_params = configure_game_params() # Construct the request headers headers = construct_request_headers() # Mock the "busted" status in the request payload request_payload = { "status": "BUSTED", **game_params, } # Make the API request with retries and backoff response = make_api_request("https://api.faucetpay.io/mines/sweep", request_payload, headers) # Handle response if response: mine_locations = response.json().get("data", {}).get("mine_locations") if mine_locations: print("Mine locations:", mine_locations) else: print("No mine locations found.") else: print("Failed to retrieve mine locations.")
解决方案:使用动态浏览器自动化工具
由于页面依赖JavaScript动态渲染内容,requests这类HTTP库无法执行JS,必须使用能模拟真实浏览器行为的工具(如Selenium、Playwright),它们可以加载完整页面、执行JS并获取动态更新的DOM内容。
基于Selenium的实现示例
安装依赖
pip install selenium webdriver-manager
代码实现
from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time # 初始化Chrome浏览器,规避反爬检测 options = webdriver.ChromeOptions() # 可选:启用无头模式(不显示浏览器窗口) # options.add_argument("--headless=new") options.add_argument("--disable-blink-features=AutomationControlled") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) # 加载游戏页面并设置会话Cookie(从浏览器开发者工具复制真实Cookie) driver.get("https://你的游戏页面URL") # 替换为实际游戏地址 # 添加会话必要Cookie cookies = [ {"name": "access-token", "value": "39fa080b862e50c48c11a5a5f5a8034f53e1f7d76fb9fa5c4675fed1f1f482450c"}, {"name": "fp-userSeed", "value": "SnuPVeYLOWKNACMDK12dyoEIooUuXm4iCLSwDprUta3FuRtHST74O3HRrz4qA0J7"}, # 补充其他从浏览器复制的必要Cookie ] for cookie in cookies: driver.add_cookie(cookie) # 刷新页面以应用Cookie driver.refresh() def get_mine_locations(): """从动态DOM或全局JS变量中提取地雷位置的tile id""" try: # 尝试从隐藏DOM元素获取(示例:带data-mine属性的元素) mine_tiles = WebDriverWait(driver, 10).until( EC.presence_of_all_elements_located((By.CSS_SELECTOR, "[data-mine='true']")) ) return [tile.get_attribute("id") for tile in mine_tiles] except: # 若隐藏元素不可用,尝试读取全局JS变量(需替换为游戏实际变量名) return driver.execute_script("return window.mineLocations;") def click_safe_tiles(mine_ids): """点击所有非地雷的方块,中途检测游戏是否结束""" all_tiles = WebDriverWait(driver, 10).until( EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".game-tile")) # 替换为实际tile选择器 ) for tile in all_tiles: tile_id = tile.get_attribute("id") if tile_id not in mine_ids: try: tile.click() time.sleep(0.2) # 控制点击速度,避免触发反爬 if check_game_end(): break except: continue def check_game_end(): """检测游戏是否因胜负结束""" try: # 替换为实际胜负提示元素的选择器 WebDriverWait(driver, 3).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".game-over, .game-success")) ) return True except: return False def reset_game(): """游戏结束后重置,开始新一局""" try: # 替换为实际重置按钮的选择器 reset_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, ".btn-reset-game")) ) reset_btn.click() # 等待新一局界面加载完成 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".game-tile")) ) except: # 重置按钮不可用时,刷新页面 driver.refresh() # 主循环:持续进行游戏 while True: # 等待游戏界面加载完成 WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".game-tile")) ) # 获取地雷位置 mine_ids = get_mine_locations() if not mine_ids: print("未获取到地雷位置,2秒后重试...") time.sleep(2) continue print(f"已获取地雷位置:{mine_ids}") # 点击安全方块 click_safe_tiles(mine_ids) # 游戏结束则重置 if check_game_end(): print("游戏结束,正在重置...") reset_game() time.sleep(3)
关键注意事项
- 元素选择器替换:使用浏览器开发者工具(F12)查看游戏页面的tile、胜负提示、重置按钮的实际CSS选择器或XPath,替换代码中的占位符
- 全局JS变量提取:多数游戏会将地雷位置等关键数据存储在全局JS变量中,可在浏览器控制台输入
window查看变量名,替换代码中的window.mineLocations - 反爬规避:代码中已添加禁用自动化检测的配置,若仍被识别,可尝试添加随机等待时间、模拟人类点击轨迹
- 会话保持:确保Cookie与浏览器中的一致,否则无法维持登录状态进入游戏
为什么之前的requests代码无效
游戏的地雷位置大概率是在客户端通过JavaScript生成或渲染的,并不会提前通过API接口返回;或者接口需要特定的游戏状态(如正在进行中)才会返回数据,模拟"BUSTED"状态的请求不符合服务器的校验逻辑,因此无法获取有效数据。
内容的提问来源于stack exchange,提问作者Njongo Magagula
相关产品推荐
相关产品推荐

