1、日常工作中,登录内部系统往往需要输入用户名、密码、短信验证码,但是如果30分钟不操作,会自动退出,为避免频繁登录,可以使用c#写一个自动刷新指定网址页面的程序。找来找去,这个最好用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Net.WebSockets;
using Newtonsoft.Json;
///用这个命令行打开谷歌,然后在进入自己的地址 "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="C:\temp\chrome_debug"
namespace shuxin
{
public class TabInfo
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("webSocketDebuggerUrl")]
public string WebSocketUrl { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
}
class Program
{
private const string TARGET_URL = "sd4a.com"; // 支持部分匹配,如包含 baidu.com
private const int REFRESH_INTERVAL_MINUTES = 19;
private static readonly HttpClient httpClient = new();
static async Task Main(string[] args)
{
Console.WriteLine("Auto-refresh for browser tabs started...");
Console.WriteLine($"Target URL pattern: {TARGET_URL}");
Console.WriteLine($"Refresh every {REFRESH_INTERVAL_MINUTES} minutes.\n");
while (true)
{
try
{
await RefreshTargetTabAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
await Task.Delay(TimeSpan.FromMinutes(REFRESH_INTERVAL_MINUTES));
}
}
static async Task RefreshTargetTabAsync()
{
// Step 1: 获取所有标签页
var tabsJson = await httpClient.GetStringAsync("http://localhost:9222/json");
var tabs = JsonConvert.DeserializeObject<List<TabInfo>>(tabsJson);
// Step 2: 查找目标 URL(支持子路径)
var targetTab = tabs.FirstOrDefault(t =>
t.Url != null && t.Url.Contains(TARGET_URL, StringComparison.OrdinalIgnoreCase));
if (targetTab == null)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Target tab not found.");
return;
}
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Found tab: {targetTab.Title} - {targetTab.Url}");
// Step 3: 通过 WebSocket 发送 Page.reload 命令
await ReloadPageViaCDP(targetTab.WebSocketUrl);
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Page refreshed successfully.");
}
static async Task ReloadPageViaCDP(string webSocketUrl)
{
using var ws = new ClientWebSocket();
await ws.ConnectAsync(new Uri(webSocketUrl), CancellationToken.None);
// 构造 CDP Page.reload 命令
var command = new
{
id = 1,
method = "Page.reload",
@params = new { }
};
string json = JsonConvert.SerializeObject(command);
var buffer = Encoding.UTF8.GetBytes(json);
await ws.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
// 可选:读取响应(非必须)
var receiveBuffer = new byte[1024];
await ws.ReceiveAsync(receiveBuffer, CancellationToken.None);
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
}
}
2、如果想增加日志,可以这样写:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.WebSockets;
using Newtonsoft.Json;
/// 启动Chrome命令:"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="C:\temp\chrome_debug"
namespace shuxin
{
public class TabInfo
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("webSocketDebuggerUrl")]
public string WebSocketUrl { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
}
class Program
{
private const string TARGET_URL = "sd4a.com";
private const int REFRESH_INTERVAL_MINUTES = 19;
private static readonly HttpClient httpClient = new();
private const string LogFilePath = @"c:\log.txt";
static async Task Main(string[] args)
{
// 初始化信息
LogAndPrint("Auto-refresh for browser tabs started...");
LogAndPrint($"Target URL pattern: {TARGET_URL}");
LogAndPrint($"Refresh every {REFRESH_INTERVAL_MINUTES} minutes.\n");
while (true)
{
try
{
await RefreshTargetTabAsync();
}
catch (Exception ex)
{
LogAndPrint($"Error: {ex.Message}");
}
await Task.Delay(TimeSpan.FromMinutes(REFRESH_INTERVAL_MINUTES));
}
}
static async Task RefreshTargetTabAsync()
{
// 获取所有标签页
var tabsJson = await httpClient.GetStringAsync("http://localhost:9222/json");
var tabs = JsonConvert.DeserializeObject<List<TabInfo>>(tabsJson);
// 查找目标标签页
var targetTab = tabs.FirstOrDefault(t => t.Url != null && t.Url.Contains(TARGET_URL, StringComparison.OrdinalIgnoreCase));
if (targetTab == null)
{
LogAndPrint($"[{DateTime.Now:HH:mm:ss}] Target tab not found.");
return;
}
LogAndPrint($"[{DateTime.Now:HH:mm:ss}] Found tab: {targetTab.Title} - {targetTab.Url}");
// 刷新页面
await ReloadPageViaCDP(targetTab.WebSocketUrl);
LogAndPrint($"[{DateTime.Now:HH:mm:ss}] Page refreshed successfully.");
}
static async Task ReloadPageViaCDP(string webSocketUrl)
{
using var ws = new ClientWebSocket();
await ws.ConnectAsync(new Uri(webSocketUrl), CancellationToken.None);
// 构造刷新命令
var command = new { id = 1, method = "Page.reload", @params = new { } };
var buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(command));
await ws.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
// 读取响应(可选)
var receiveBuffer = new byte[1024];
await ws.ReceiveAsync(receiveBuffer, CancellationToken.None);
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
/// <summary>
/// 统一处理:控制台输出 + 写入日志
/// </summary>
private static void LogAndPrint(string message)
{
Console.WriteLine(message);
try
{
// 追加写入日志,带完整时间戳
var logContent = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}";
File.AppendAllText(LogFilePath, logContent, Encoding.UTF8);
}
catch (Exception ex)
{
// 日志写入失败时仅提示,不影响主程序
Console.WriteLine($"Failed to write log: {ex.Message}");
}
}
}
}
3、可以通过 VBS 脚本调用 exe 程序并不弹出控制台窗口
创建一个 .vbs 文件,比如 run_hidden.vbs,内容如下:然后双击执行即可。也可以设置成开机启动
' run_hidden.vbs
' 注意:替换为你实际的exe文件路径
Set WshShell = CreateObject("WScript.Shell")
' 写法1:三重双引号包裹路径(推荐,处理路径含空格的情况)
WshShell.Run """C:\your\actual\path\shuxin.exe""", 0, False
' 写法2:如果路径没有空格,也可以直接写(不推荐,兼容性差)
' WshShell.Run "C:\your\actual\path\shuxin.exe", 0, False
' 释放对象(可选,VBS会自动回收,但显式释放更规范)
Set WshShell = Nothing
代码解析:
这是一个基于 Chrome DevTools Protocol (CDP) 实现自动刷新特定浏览器标签页的 C# 程序。让我详细分析其工作原理和用途:
主要功能
程序会定期(每19分钟)检查并刷新包含特定URL(如baidu.com)的Chrome标签页,防止网页因长时间不活动而过期或超时。
代码结构分析
1. 核心组件
-
TabInfo类:定义了浏览器标签页的数据结构
-
Main方法:程序主循环,定时执行刷新任务
-
RefreshTargetTabAsync方法:查找并刷新目标标签页
-
ReloadPageViaCDP方法:通过WebSocket发送刷新命令
2. 工作流程
-
启动要求:需要先用特定命令启动Chrome,启用远程调试
-
获取标签页列表 :通过HTTP请求
http://localhost:9222/json获取所有标签页信息 -
查找目标标签页 :匹配包含
TARGET_URL的URL -
发送刷新命令 :通过WebSocket连接发送
Page.reloadCDP命令 -
循环执行:每19分钟重复上述过程
3. 关键技术点
Chrome远程调试:
bash
复制
下载
# 使用9222端口开启调试模式
chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\temp\chrome_debug"
CDP通信:
-
通过WebSocket连接到
webSocketDebuggerUrl -
发送JSON格式的CDP命令
-
Page.reload命令会触发页面刷新
4. 潜在用途
-
保持登录状态:防止需要登录的网页会话过期
-
数据监控:保持监控页面实时更新
-
避免超时:防止长时间不操作导致的连接断开
5. 注意事项和潜在问题
安全问题:
csharp
复制
下载
// 远程调试端口暴露了浏览器控制权限
// 建议添加访问控制或身份验证
资源管理:
csharp
复制
下载
// HttpClient 是静态的,但未正确配置重试和超时
// 建议添加适当的异常处理和资源清理
private static readonly HttpClient httpClient = new();
改进建议:
-
错误处理增强:当前异常处理较简单,可能需要对特定异常做不同处理
-
配置灵活性:可将目标URL和间隔时间改为可配置参数
-
多个标签页支持:目前只处理第一个匹配的标签页
-
连接状态检查:添加WebSocket连接状态的验证
6. 依赖项
-
Newtonsoft.Json (JSON.NET) - 用于JSON序列化
-
System.Net.WebSockets - WebSocket通信
-
System.Text.Json - .NET内置JSON支持(虽然代码中使用了Newtonsoft)
这个程序实际上是一个简单的"防休眠"工具,通过模拟用户活动来保持网页的活跃状态。