C#使用Selenium开发WhatsApp自动化的号码封禁与页面重载问题求解
问题概述
基于Selenium + C#开发个人用途的网页版WhatsApp自动化工具,目标发送号码从数据库动态读取,现存两个待解决问题:
- 已在两次消息发送请求间设置10-15秒延迟,使用的发送账号仍被平台封禁
- 现有实现每次执行发送操作都会触发页面全量重载,需要实现无页面刷新的直接发送逻辑,阻断不必要的重载行为
原有实现代码:
private void msgnew(string number, string message, int len, string oldnumber) { driver.Navigate().GoToUrl("https://web.whatsapp.com/send?phone=" + number + "&text=" + Uri.EscapeDataString(message) + "&lang=en&app_absent=1"); driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30); driver.FindElement(By.CssSelector("button._4sWnG>span")).Click();//点击发送箭头按钮 }
解决方案
账号封禁问题优化
WhatsApp的反自动化检测不是仅靠发送间隔判定,现有实现的操作特征辨识度极高,即使加了延迟也很容易被识别,按以下规则调整:
- 废弃通过
send?phone=xxx带参数直接跳转聊天页的逻辑,正常用户极少通过这种方式进入聊天窗口,属于自动化工具的典型特征,是触发封号的核心原因之一 - 替换固定窄区间延迟,将两次消息发送的间隔调整为20-60秒随机值,每一步DOM操作前加300ms-3s的随机停顿,模拟真人操作的反应间隔;每发送8-12条消息增加3-5分钟的长暂停,模拟用户中途离开、切换其他应用的行为
- 新账号不要直接跑自动化:刚登录网页版的账号先手动使用3-7天,完成加好友、发日常消息、浏览状态等正常用户操作,养号后再用于自动化发送
- 隐藏Selenium自动化特征:启动ChromeDriver时添加参数禁用
navigator.webdriver标识,关闭自动化受控提示,不要使用默认的裸Selenium配置,否则页面加载时平台就能直接识别到自动化环境 - 不要直接预填文本就点发送:模拟真人输入逻辑,逐字符或者逐段输入消息内容,过程中随机加入短停顿,不要一步到位填完内容立刻点击发送。
页面重复加载问题修复
每次触发重载的根本原因是代码里调用了driver.Navigate().GoToUrl()做整页跳转,只要废弃全页跳转逻辑,所有操作基于已加载完成的页面DOM执行即可实现无刷新发送,核心逻辑如下:
- 工具启动时仅加载一次WhatsApp网页版主页,等待用户扫码登录完成后,后续所有发送操作都不再做整页跳转
- 发送消息时优先在左侧最近聊天列表查找目标号码对应的会话,存在则直接点击打开聊天窗口
- 若最近列表不存在对应会话,点击页面的「新建聊天」按钮,在搜索框输入目标号码,等待搜索结果加载完成后点击匹配的联系人打开聊天窗口
- 找到聊天窗口内的可编辑输入框,输入待发送消息内容,定位发送按钮完成点击即可
- 不要使用类似
_4sWnG这类随机生成的class名做元素定位,WhatsApp每次前端发版都会变更这类哈希class,选择器极易失效,优先使用aria-label、角色属性、data-tab这类稳定属性定位元素。
核心逻辑参考代码:
// 全局仅执行一次主页加载 private void InitWhatsAppPage() { if (driver.Url != "https://web.whatsapp.com/") { driver.Navigate().GoToUrl("https://web.whatsapp.com/"); driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60); // 此处添加等待扫码登录成功的判断逻辑 } } private void msgnew(string number, string message) { Random rnd = new Random(); // 点击新建聊天按钮 var newChatBtn = driver.FindElement(By.CssSelector("button[aria-label='New chat']")); newChatBtn.Click(); Thread.Sleep(rnd.Next(500, 1500)); // 搜索框输入目标号码 var searchInput = driver.FindElement(By.CssSelector("div[contenteditable='true'][role='textbox']")); searchInput.Clear(); foreach (char c in number) { searchInput.SendKeys(c.ToString()); Thread.Sleep(rnd.Next(50, 150)); } Thread.Sleep(rnd.Next(1000, 2500)); // 点击匹配的联系人 var contact = driver.FindElement(By.CssSelector($"div[role='button'] span[title*='{number.Substring(number.Length - 4)}']")); contact.Click(); Thread.Sleep(rnd.Next(600, 1300)); // 输入消息内容 var msgInput = driver.FindElement(By.CssSelector("div[contenteditable='true'][data-tab='10']")); foreach (char c in message) { msgInput.SendKeys(c.ToString()); // 模拟真人输入的随机停顿 if (rnd.Next(0,10) > 7) Thread.Sleep(rnd.Next(200, 800)); } Thread.Sleep(rnd.Next(800, 2000)); // 点击发送按钮 var sendBtn = driver.FindElement(By.CssSelector("button[aria-label='Send']")); sendBtn.Click(); }
代码中
aria-label属性值如果使用中文界面,替换为对应的中文文案即可,元素定位路径可以根据当前页面实际DOM结构微调,核心是全程不触发整页跳转。
内容的提问来源于stack exchange,提问作者user5803928
相关产品推荐
相关产品推荐

