单主机多进程模式获取5秒盾Cookie的解决方案

单主机多进程模式获取5秒盾Cookie的解决方案

背景
目标
实现方法

1. 初始化Driver
2. 获取driver的进程ID
3. 根据窗口hwnd点击坐标点
4. 调用方法
5. 完整代码如下
6. 输出结果

背景

在使用自动化获取 5秒盾Cookie cf_clearance和__cf_bm时,使用Windows操作系统自动化点击窗口中的坐标点,有以下几种方案

普通方案:前置窗口>点击坐标点
但这种方案如果需要同时操作多个窗口或者有其他自动化在同一台机器,那么就没有办法同时进行操作多个窗口
升级方案:窗口锁>前置窗口>点击坐标点
该方案比较复杂,且依赖第三方组件去实现进程锁。采用多个窗口使用锁竞争的方式,获取前置窗口的权利,但同时也只能有一个窗口进行点击。不过也基本实现了同一台主机多窗口运行。
hwnd方案:获取窗口hwnd>点击窗口内的坐标点
使用hwnd(窗口句柄)控制窗口,只操作当前窗口内的坐标点,可以做到多进程同时处理任务,且互不影响。理论上机器的硬件资源有多少,就可以开启多少个窗口进程。

目标

同一台主机,可以同时启动多个浏览器窗口获取5秒盾Cookie。并做到窗口之间环境隔离,独立运行,使单主机的硬件资源充分利用。

实现方法

使用 DrissionPage 作为5秒盾的自动化框架

1. 初始化Driver

def create_drissionpage_driver(browser_path=None, user_agent=None, window_x=1300, window_y=912):
    # 普通模式
    tmp_path = tempfile.mkdtemp()
    options = ChromiumOptions().auto_port(on_off=True).set_tmp_path(tmp_path)
    if user_agent is not None:
        options.set_user_agent(user_agent)
        # 这里如果给出userAgent,则使用无头模式加载url
        options.headless()
    window_size = f'{
              window_x},{
              window_y}'
    options.set_argument('--window-size', window_size)

    # 设置浏览器可执行文件路径
    if browser_path is not None and browser_path != '':
        options.set_browser_path(browser_path)
        print("createDriver - set_browser_path: " + browser_path)
    driver = ChromiumPage(addr_or_opts=options)
    return driver

2. 获取driver的进程ID

driver = create_drissionpage_driver("chrome路径", "代理IP串", user_agent, "窗口尺寸X", "窗口尺寸Y")
# 获取浏览器的pid
pid = driver.browser.process_id

3. 根据窗口hwnd点击坐标点


r"""
# 需要安装以下依赖包
pip install pywin32
pip install pygetwindow
"""
import time
import win32process
import pygetwindow
import win32api, win32con

def mouse_click(windowPid, x, y):
    """
    根据绝对坐标点击鼠标
    """
    # windowPid = driver.browser.process_id
    # x = 264
    # y = 378
    for window in pygetwindow.getAllWindows():
        hwnd = window._hWnd
        pid = get_process_id_from_window(hwnd)

        if (pid == windowPid):
            # window.maximize()  # 最大化窗口
            for i in range(3):
                print(f"点击鼠标,坐标[{
              x},{
              y}]")
                click_point(hwnd, x, y)

# 异步点击鼠标事件
def click_point(hwnd, x, y):
    # 左键按住
    win32api.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, 0, ((y) << 16 | (x)));
    # 等待
    time.sleep(0.5)
    # 左键松手
    win32api.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, ((y) << 16 | (x)));

def get_process_id_from_window(hwnd):
    # 通过句柄获取【线程ID 进程ID】
    thread_id, process_id = win32process.GetWindowThreadProcessId(hwnd)
    return process_id

def get_window_postation(hwnd):
    """
    获取窗口坐标
    :param hwnd: 窗口句柄
    :return:
    """
    # 获取窗口坐标
    import win32gui, win32con, win32api, win32print

    # 获取屏幕设备上下文
    hDC = win32gui.GetDC(0)

    # 获取屏幕的真实宽度和缩放后的宽度
    real_w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
    apparent_w = win32api.GetSystemMetrics(0)

    # 计算缩放比
    scale_radio = real_w / apparent_w

    # 获取原始窗口坐标
    origin_window_rect = win32gui.GetWindowRect(hwnd)

    # 根据缩放比修正窗口坐标
    fixed_window_rect = [item * scale_radio for item in origin_window_rect]
    print(fixed_window_rect)
    return fixed_window_rect

4. 调用方法

mouse_click(driver.browser.process_id, checkbox-X轴坐标, checkbox-Y轴坐标)

5. 完整代码如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2025/5/12 13:22
# @Author  : Guochengke
# @File    : 测试窗口句柄控制浏览器.py
# @Desc    : 描述信息
import tempfile

from DrissionPage import ChromiumPage, ChromiumOptions
r"""
# 需要安装以下依赖包
pip install pywin32
pip install pygetwindow
"""
import time
import win32process
import pygetwindow
import win32api, win32con

def mouse_click(windowPid, x, y):
    """
    根据绝对坐标点击鼠标
    """
    # windowPid = driver.browser.process_id
    # x = 264
    # y = 378
    for window in pygetwindow.getAllWindows():
        hwnd = window._hWnd
        pid = get_process_id_from_window(hwnd)

        if (pid == windowPid):
            # window.maximize()  # 最大化窗口
            for i in range(3):
                print(f"点击鼠标,坐标[{
              x},{
              y}]")
                click_point(hwnd, x, y)

# 异步点击鼠标事件
def click_point(hwnd, x, y):
    # 左键按住
    win32api.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, 0, ((y) << 16 | (x)));
    # 等待
    time.sleep(0.5)
    # 左键松手
    win32api.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, ((y) << 16 | (x)));

def get_process_id_from_window(hwnd):
    # 通过句柄获取【线程ID 进程ID】
    thread_id, process_id = win32process.GetWindowThreadProcessId(hwnd)
    return process_id

def get_window_postation(hwnd):
    """
    获取窗口坐标
    :param hwnd: 窗口句柄
    :return:
    """
    # 获取窗口坐标
    import win32gui, win32con, win32api, win32print

    # 获取屏幕设备上下文
    hDC = win32gui.GetDC(0)

    # 获取屏幕的真实宽度和缩放后的宽度
    real_w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
    apparent_w = win32api.GetSystemMetrics(0)

    # 计算缩放比
    scale_radio = real_w / apparent_w

    # 获取原始窗口坐标
    origin_window_rect = win32gui.GetWindowRect(hwnd)

    # 根据缩放比修正窗口坐标
    fixed_window_rect = [item * scale_radio for item in origin_window_rect]
    print(fixed_window_rect)
    return fixed_window_rect
def create_drissionpage_driver(browser_path=None, user_agent=None, window_x=1300, window_y=912):
    # 普通模式
    tmp_path = tempfile.mkdtemp()
    options = ChromiumOptions().auto_port(on_off=True).set_tmp_path(tmp_path)
    if user_agent is not None:
        options.set_user_agent(user_agent)
        # 这里如果给出userAgent,则使用无头模式加载url
        options.headless()
    window_size = f'{
              window_x},{
              window_y}'
    options.set_argument('--window-size', window_size)

    # 设置浏览器可执行文件路径
    if browser_path is not None and browser_path != '':
        options.set_browser_path(browser_path)
        print("createDriver - set_browser_path: " + browser_path)
    driver = ChromiumPage(addr_or_opts=options)
    return driver


if __name__ == '__main__':
    driver = create_drissionpage_driver()
    driver.get(
        'https://www.twayair.com/app/booking/chooseItinerary',
        timeout=60 * 1000
    )
    # 等待5秒盾checkbox加载完成
    time.sleep(20)
    # 获取浏览器的pid
    pid = driver.browser.process_id
    mouse_click(pid, 218, 379)
    print(driver.cookies().as_dict())
    driver.quit(
        del_data=True
    )

6. 输出结果

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容