using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Chrome;
using System;
using System.Drawing;
using System.Threading;
using System.Text.RegularExpressions;
namespace QQ_LoginTest
{
/*
* nuget
<package id="Selenium.Chrome.WebDriver" version="2.35" targetFramework="net452" />
<package id="Selenium.WebDriver" version="3.8.0" targetFramework="net452" />
*/
class Program
{
static void Main(string[] args)
{
ChromeDriver driver = new ChromeDriver();
//(Iframe中拖动元素无效的问题)https://stackoverflow.com/questions/46271789/drag-and-drop-doesnt-work-inside-iframe-with-selenium-webdriver-with-java
driver.Navigate().GoToUrl("https://qzone.qq.com/");
driver.Manage().Window.Maximize();//窗口最大化,便于脚本执行
//设置超时等待(隐式等待)时间设置10秒
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
IWebDriver login = driver.SwitchTo().Frame(driver.FindElementById("login_frame"));
login.FindElement(By.Id("switcher_plogin")).Click();
login.FindElement(By.Id("u")).SendKeys("592955699");//QQ号码
login.FindElement(By.Id("p")).SendKeys("******");//QQ密码
if (login.FindElement(By.Id("err_m")).Text.Trim() == "请输入正确的帐号!")
{
Console.WriteLine("账号错误");
}
else
{
//登陆QQ
login.FindElement(By.Id("login_button")).Click();
}
//获取到验证区域
IWebDriver validate = login.SwitchTo().Frame(login.FindElement(By.TagName("iframe")));
Thread.Sleep(2000);
var slideBkg = validate.FindElement(By.Id("slideBlock"));//获取滑动验证图片
var tcOperationBkg = validate.FindElement(By.Id("tcOperation"));//获取整个验证图层
Console.WriteLine("Width "+slideBkg.Size.Width);
Console.WriteLine("Height " + slideBkg.Size.Height);
//例如(带阴影)地址:https://hy.captcha.qq.com/hycdn_1_1585770526512857856_0
//阴影小图
string yinyingUrl = slideBkg.GetAttribute("src");
//原图地址:https://hy.captcha.qq.com/hycdn_0_1585770526512857856_0
//用正则匹配并替换
//新大图
var newUrl= new Regex(@"hycdn_\d_", RegexOptions.Multiline).Replace(yinyingUrl, "hycdn_1_");
//原始大图
string oldUrl = new Regex(@"hycdn_\d_", RegexOptions.Multiline).Replace(yinyingUrl, "hycdn_0_");
//根据地址获取到图像
Console.WriteLine($"原始验证图地址:{oldUrl}");
Bitmap oldBmp = (Bitmap)LoginHelper.GetImg(oldUrl);
Console.WriteLine($"阴影验证图地址:{newUrl}");
Bitmap newBmp = (Bitmap)LoginHelper.GetImg(newUrl);
driver.GetScreenshot().SaveAsFile("原图.png");
oldBmp.Save("原始验证图.png");
newBmp.Save("阴影验证图.png");
int left = LoginHelper.GetArgb(oldBmp, newBmp);//得到阴影到图片左边界的像素
Console.WriteLine($"原始验证图起点:{left}");
var leftCount = (double)tcOperationBkg.Size.Width / (double)newBmp.Width * left;
Console.WriteLine($"浏览器验证图起点:{leftCount}");
int leftShift = (int)leftCount - 30;
Console.WriteLine($"实际移动:{leftShift}");
//int leftShift = (int)(left * ((double)slideBkg.Size.Width / (double)newBmp.Width) - 18);//得到真实的偏移值
//validate.SwitchTo();
var slideBlock = validate.FindElement(By.Id("slideBlock"));//获取到滑块
Console.WriteLine($"开始位置:{slideBlock.Location.X}");
Actions actions = new Actions(driver);
//actions.ClickAndHold(slideBlock).Build().Perform();
//actions.DragAndDropToOffset(slideBlock, 50, 0).Perform();
//actions.Click(tcaptcha_drag_button).Perform();
//actions.ClickAndHold(tcaptcha_drag_button).Release().Perform();
actions.DragAndDropToOffset(slideBlock, leftShift, 0).Build().Perform();//单击并在指定的元素上按下鼠标按钮,然后移动到指定位置
//Thread.Sleep(2000);
//Console.WriteLine($"移动后位置:{slideBlock.Location.X}");
//actions.DragAndDropToOffset(slideBlock,leftShift, 0).Perform();//移动滑块到阴影处
//Thread.Sleep(2000);
driver.GetScreenshot().SaveAsFile("移动后图片.png");
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace QQ_LoginTest
{
class LoginHelper
{
/// <summary>
/// 截图
/// </summary>
/// <param name="fromImagePath"></param>
/// <param name="offsetX"></param>
/// <param name="offsetY"></param>
/// <param name="toImagePath"></param>
/// <param name="width"></param>
/// <param name="height"></param>
public static void CaptureImage(byte[] fromImageByte, int offsetX, int offsetY, string toImagePath, int width, int height)
{
//原图片文件
MemoryStream ms = new MemoryStream(fromImageByte);
Image fromImage = Image.FromStream(ms);
//创建新图位图
Bitmap bitmap = new Bitmap(width, height);
//创建作图区域
Graphics graphic = Graphics.FromImage(bitmap);
//截取原图相应区域写入作图区
graphic.DrawImage(fromImage, 0, 0, new Rectangle(offsetX, offsetY, width, height), GraphicsUnit.Pixel);
//从作图区生成新图
Image saveImage = Image.FromHbitmap(bitmap.GetHbitmap());
//保存图片
saveImage.Save(toImagePath, ImageFormat.Png);
//释放资源
saveImage.Dispose();
graphic.Dispose();
bitmap.Dispose();
}
/// <summary>
/// 比较两张图片的像素,确定阴影图片位置
/// </summary>
/// <param name="oldBmp"></param>
/// <param name="newBmp"></param>
/// <returns></returns>
public static int GetArgb(Bitmap oldBmp, Bitmap newBmp)
{
//由于阴影图片四个角存在黑点(矩形1*1)
for (int i = 0; i < newBmp.Width; i++)
{
for (int j = 0; j < newBmp.Height; j++)
{
if ((i>=0&&i<=1)&&((j>=0&&j<=1)||(j>= (newBmp.Height-2)&&j<=(newBmp.Height - 1))))
{
continue;
}
if ((i >= (newBmp.Width-2) && i <= (newBmp.Width - 1)) && ((j >= 0 && j <= 1) || (j >= (newBmp.Height - 2) && j <= (newBmp.Height - 1))))
{
continue;
}
//获取该点的像素的RGB的颜色
Color oldColor = oldBmp.GetPixel(i, j);
Color newColor = newBmp.GetPixel(i, j);
if (Math.Abs(oldColor.R - newColor.R) > 60 || Math.Abs(oldColor.G - newColor.G) > 60 || Math.Abs(oldColor.B - newColor.B) > 60)
{
return i;
}
}
}
return 0;
}
/// <summary>
/// 根据图片地址,得到图片对象
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static Image GetImg(string url)
{
WebRequest webreq = WebRequest.Create(url);
WebResponse webres = webreq.GetResponse();
Image img;
using (System.IO.Stream stream = webres.GetResponseStream())
{
img = Image.FromStream(stream);
}
return img;
}
}
}