自动抓取cpolar远程服务器端口脚本

前言

由于实验室服务器的端口每天都在变化,每次连接服务器都要登录网页查看端口,再在配置文件中修改,有些繁琐。突发奇想,用ai写了一个python脚本并用批处理指令一键执行。

python脚本

这段代码的核心功能是自动获取cpolar内网穿透隧道的动态端口,并更新本地SSH配置文件

  • 需要的库
    • requests:用于发送HTTP请求,模拟浏览器访问cpolar的登录页面和隧道状态接口。
      • 提交登录表单(如用户名和密码)
      • 获取隧道状态页面的HTML内容
      • 处理会话保持(如登录后的Cookie管理)
    • python-dotenv:从 .env 文件中加载环境变量,避免敏感信息(如用户名、密码)硬编码到脚本中。
      • .env 文件存储cpolar的用户名和密码
    • re:正则表达式,python内置库,在这里用于从HTML中解析动态端口号
  • 思路
    • 最主要的是用了正则表达式,ai生成的还蛮好用,也可能是任务比较简单。
    1. 从本地.env文件加载用户名和密码、确定目标URL
      • 敏感信息与代码分离
      • 使用 os.environ.get() 避免硬编码
    2. 登录网页
    3. 用正则表达式解析在线隧道
    4. SSH配置更新
      • 精准匹配Host块(避免误修改)
      • 保留原始缩进格式
      • 仅更新指定Host的Port行
      • 动创建 .bak 备份文件
      • 原子性操作(先读后写)

代码

  • 保存的文件名:get_cpolar_port.py
import requests
import os
from dotenv import load_dotenv
import shutil
import re

# 加载 .env 文件(需要修改成自己的)
dotenv_path = 'path/to/.env' 
load_dotenv(dotenv_path=dotenv_path)

USERNAME = os.environ.get("CPOLAR_USER")  # 加载.env文件中的用户名
PASSWORD = os.environ.get("CPOLAR_PASS")  # 加载.env文件中的密码

LOGIN_URL = "https://dashboard.cpolar.com/login"
TARGET_URL = "https://dashboard.cpolar.com/status"
# --- 配置结束 ---


def fetch_logged_in_page(username, password):
    """
    模拟登录并获取登录后页面的源代码。
    优化点:统一捕获所有网络请求异常,避免程序因网络问题崩溃
    """
    with requests.Session() as session:
        # 1. 获取登录页面(确保初始cookies)
        try:
            session.get(LOGIN_URL)
        except requests.RequestException as e:
            print(f"访问登录页面失败: {e}")
            return None

        # 2. 构造登录表单数据
        login_payload = {'login': username, 'password': password}
        
        # 3. 发送登录请求(统一异常捕获)
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Referer': LOGIN_URL
        }
        print("正在尝试登录...")
        try:
            response = session.post(LOGIN_URL, data=login_payload, headers=headers)
        except requests.RequestException as e:
            print(f"登录请求失败: {e}")
            return None

        # 4. 检查登录状态
        if response.status_code != 200 or "dashboard" not in response.url:
            print(f"登录失败! 状态码: {response.status_code}")
            print("响应内容:", response.text[:200])  # 保留调试信息
            return None
        print("登录成功!")

        # 5. 获取目标页面(统一异常捕获)
        print(f"正在获取目标页面: {TARGET_URL}")
        try:
            target_response = session.get(TARGET_URL, headers=headers)
        except requests.RequestException as e:
            print(f"获取目标页面失败: {e}")
            return None

        if target_response.status_code == 200:
            print("成功获取登录后的页面源代码!")
            return target_response.text
        print(f"获取目标页面失败,状态码: {target_response.status_code}")
        return None

html_source = fetch_logged_in_page(USERNAME, PASSWORD)

# 1. 定义目标隧道名称(需要修改成自己的)
target_tunnel_name = "your tunnel name"

# 2. 编写正则表达式(保持原逻辑,仅优化注释)
pattern = rf'<tr>.*?<td>{target_tunnel_name}</td>.*?<a[^>]*>(.*?)</a>.*?</tr>'
match = re.search(pattern, html_source, re.DOTALL)

# 3. 处理匹配结果(保持原逻辑)
if match:
    extracted_url = match.group(1)
    print(f"隧道名称 '{target_tunnel_name}' 对应的 URL 是: {extracted_url}")
else:
    print(f"未找到隧道名称为 '{target_tunnel_name}' 的信息。")
    exit(1)  # 明确退出避免后续错误

# --- 配置区 ---(可能需要修改成自己的)
TARGET_HOST = extracted_url[6:-6]  # 提取主机名部分(原逻辑不变)
NEW_PORT = extracted_url[-5:]  # 获取后五位端口(原逻辑不变)
# vscode中ssh插件的配置文件位置(需要修改成自己的)
SSH_CONFIG_PATH = os.path.expanduser("path/to/.ssh/config")

def update_ssh_port_regex(host, new_port):
    """
    使用正则表达式更新SSH配置文件。
    优化点:
    - 明确文件存在性检查
    - 优化正则表达式注释
    - 保持原逻辑不变
    """
    if not os.path.exists(SSH_CONFIG_PATH):
        print(f"错误: SSH配置文件未找到于 {SSH_CONFIG_PATH}")
        return

    # 创建备份
    backup_path = f"{SSH_CONFIG_PATH}.bak"
    shutil.copy2(SSH_CONFIG_PATH, backup_path)
    print(f"已创建备份文件: {backup_path}")

    try:
        # 读取配置文件
        with open(SSH_CONFIG_PATH, 'r') as f:
            content = f.read()

        # 匹配Host块的正则(优化注释说明)
        # 说明:匹配以 "Host [host]" 开头的块,直到下一个Host或文件末尾
        host_block_pattern = re.compile(
            rf"(^Host\s+{re.escape(host)}\b.*?)(?=\s*^Host|\Z)", 
            re.MULTILINE | re.DOTALL
        )
        
        # 替换Port行的正则
        port_pattern = re.compile(r"^(?P<indent>\s*)Port\s+\d+", re.MULTILINE)

        def replacer(match):
            block = match.group(1)
            # 在块内替换Port行(保留缩进)
            updated_block = port_pattern.sub(f"\g<indent>Port {new_port}", block)
            return updated_block

        # 执行替换
        updated_content, count = host_block_pattern.subn(replacer, content, count=1)
        if count > 0:
            with open(SSH_CONFIG_PATH, 'w') as f:
                f.write(updated_content)
            print(f"在Host '{host}'中找到Port行,已更新为 {new_port}。")
        else:
            print(f"警告: 未找到Host '{host}' 或该Host下没有Port行。")
    except Exception as e:
        print(f"发生错误: {e}")
        print("请检查备份文件并手动恢复。")


update_ssh_port_regex(TARGET_HOST, NEW_PORT)

bat批处理指令

由于电脑上没有安装python,遂用miniconda的python环境代替。

在这一阶段需要设置miniconda的安装路径,并需要将miniconda添加到系统的环境变量中。
此外,还需要指定conda的环境,该环境需要包含python脚本中用到的库。
最后,需要设置python脚本的位置,这使得py文件和bat文件可以不在同一目录下。

bat基本命令

  • :::两个英文冒号是注释的标记
  • @echo off:在执行下面的命令时,不要把命令本身显示在屏幕上,保持界面干净整洁。
  • setlocal enabledelayedexpansion:开启一个‘临时工作区’,并启用一个特殊功能。
    • setlocal:创建一个“临时工作区”。在这个区域里设置的所有变量(比如后面要说的路径),等脚本执行完后都会自动消失,不会影响电脑的全局环境。
      • 结尾有endlocal
    • enabledelayedexpansion:开启“延迟变量扩展”。简单说,普通变量用 %变量名%,电脑在读取命令时就会立刻替换成它的值。但有时候,我们需要在一段代码(比如 if 判断块)执行之后,再获取变量的最新值。这时就需要用 !变量名! 的形式,并开启这个功能。你可以把它理解为“等我用到的时候再去看这个变量里是什么,而不是现在就看”。
  • set "变量名=值":设置变量,文件路径也是变量,canda环境也是变量
  • exit /b 1:退出脚本,并返回一个错误代码 1。表示“任务失败”。
  • pause:暂停脚本,屏幕上会显示“请按任意键继续…”,让你有时间看清错误信息。
  • if not exist "路径":这是一个安全检查。电脑会去指定的路径看一看文件夹在不在。如果不在(not exist),就执行括号 () 里的命令。
  • echo string:在屏幕上显示echo后的string,不需要引号。
  • | :管道符,意思是把前一个命令的结果,传给后一个命令处理。
  • findstr :在结果里查找指定的字符串。
    • /C:string:使用指定字符串作为文字搜索字符串。
    • 如果 findstr 找到了,errorlevel 就是 0;否则是1或非零数字。
  • >nul:把 前面的结果扔进“黑洞”(nul),不让它显示在屏幕上。
  • call :“调用”另一个程序或脚本。

基本思路

  1. 设置miniconda、python脚本位置以及使用的conda环境
  2. 检查1中的设置是否存在问题,使用if语句
  3. 调用miniconda自带的activate.bat激活所选环境
  4. 执行python脚本
  5. 退出
  6. 增加必要的文字输出以增强交互

代码

  • bat代码中的中文输出可能乱码,保存成ANSI格式
@echo off
setlocal enabledelayedexpansion

:: ===================================================================
::                           用户配置区域
:: ===================================================================

:: 1. 设置你的 Miniconda 安装路径。
::    如果你的路径不同,请手动修改下面的值。(anaconda也可以)
set "MINICONDA_PATH=path\to\miniconda3"

:: 2. 设置你为这个项目创建的 Conda 环境名称。
set "CONDA_ENV_NAME=base"

:: 3. 设置你的 Python 脚本的完整路径。
::    现在批处理文件和Python脚本可以不在同一个目录了。
set "PYTHON_SCRIPT_PATH=path\to\get_cpolar_port.py"

:: ===================================================================
::                           脚本执行区域
:: ===================================================================

:: 检查 Miniconda 路径是否存在
if not exist "%MINICONDA_PATH%" (
    echo 错误: 在以下位置未找到 Miniconda 安装:
    echo %MINICONDA_PATH%
    echo.
    echo 请编辑此文件并正确设置 MINICONDA_PATH 变量。
    pause
    exit /b 1
)

:: 【修改】检查 Python 脚本是否存在
if not exist "%PYTHON_SCRIPT_PATH%" (
    echo 错误: 在以下位置未找到 Python 脚本:
    echo %PYTHON_SCRIPT_PATH%
    echo.
    echo 请编辑此文件并正确设置 PYTHON_SCRIPT_PATH 变量。
    pause
    exit /b 1
)

:: 检查 Conda 环境是否存在
echo 正在检查 Conda 环境 "%CONDA_ENV_NAME%"...
conda info --envs | findstr /C:"%CONDA_ENV_NAME%" >nul
if !errorlevel! neq 0 (
    echo.
    echo 错误: 未找到名为 "%CONDA_ENV_NAME%" 的 Conda 环境。
    echo.
    echo 请先打开 "Anaconda Prompt" 并运行以下命令来创建环境:
    echo conda create -n %CONDA_ENV_NAME% python requests python-dotenv -c conda-forge
    pause
    exit /b 1
)

:: 激活 Conda 环境并运行脚本
echo 正在激活 Conda 环境...
call "%MINICONDA_PATH%\Scripts\activate.bat" %CONDA_ENV_NAME%

if !errorlevel! neq 0 (
    echo.
    echo 错误: 激活环境失败。请检查 MINICONDA_PATH 是否正确。
    pause
    exit /b 1
)

echo.
echo 环境已激活。正在运行 Python 脚本...
echo -------------------------------------------------
:: 【修改】使用变量来运行 Python 脚本
python "%PYTHON_SCRIPT_PATH%"
echo -------------------------------------------------

:: 检查 Python 脚本执行结果
if !errorlevel! equ 0 (
    echo.
    echo 脚本执行成功!
) else (
    echo.
    echo 脚本执行失败,错误代码: !errorlevel!
)

echo.
echo 操作完成。
pause
endlocal

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值