你的位置:首页 > ASP.net教程

[ASP.net教程]C#使用tesseract3.02识别验证码模拟登录


一、前言

使用tesseract3.02识别有验证码的网站 安装tesseract3.02 在VS nuget 搜索Tesseract即可。

二、项目结构图

三、项目主要代码

 1 using System; 2 using System.Collections.Concurrent; 3 using System.Collections.Generic; 4 using System.Diagnostics; 5 using System.Drawing; 6 using System.IO; 7 using System.Net; 8 using System.Net.Cache; 9 using System.Text; 10  11 namespace Tesseract.Test.Tools 12 { 13   /// <summary> 14   /// http帮助类 15   /// </summary> 16   public class HttpHelper 17   { 18     /// <summary> 19     /// 异步事件 20     /// </summary> 21     public HttpHelper() 22     { 23       CookieContainer = new CookieContainer(); 24       Encoding = Encoding.UTF8; 25     } 26  27     /// <summary> 28     /// 访问次数字典 29     /// </summary> 30     private ConcurrentDictionary<String, int> urlTryList = new ConcurrentDictionary<string, int>(); 31  32     /// <summary> 33     /// Cookie 容器 34     /// </summary> 35     public CookieContainer CookieContainer { set; get; } 36  37     /// <summary> 38     /// Post数据 39     /// </summary> 40     public String PostData { set; private get; } 41  42     /// <summary> 43     /// 页面语言 44     /// </summary> 45     public Encoding Encoding { set; private get; } 46  47     /// <summary> 48     /// 验证码路径 49     /// </summary> 50     public string CodePath { get; set; } 51  52     /// <summary> 53     /// 文件保存路径 54     /// </summary> 55     public String FileSavePath { set; private get; } 56  57     /// <summary> 58     /// 回调时间 59     /// </summary> 60     public Action<String, String> CallBackAction; 61  62  63     /// <summary> 64     /// 异步请求 65     /// </summary> 66     /// <param name="url">请求地址</param> 67     /// <param name="tryTimes">错误重试次数</param> 68     public void AsynRequest(String url, int tryTimes = 3) 69     { 70       Trace.TraceInformation(String.Concat("开始异步请求:", url)); 71       urlTryList.TryAdd(url, tryTimes); 72       var request = WebRequest.Create(url) as HttpWebRequest; 73       if (request == null) return; 74       request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch"); 75       request.Headers.Add("Accept-Language", "zh-CN,zh;q=0.8"); 76       request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | 77                        DecompressionMethods.None; 78       request.Credentials = CredentialCache.DefaultNetworkCredentials; 79       request.UseDefaultCredentials = false; 80       request.KeepAlive = false; 81       request.PreAuthenticate = false; 82       request.ProtocolVersion = HttpVersion.Version10; 83       request.UserAgent = 84         "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"; 85       request.Accept = "text/html,application/xhtml+"; 86       //request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); 87       request.Timeout = 1000*60*3; 88       request.CookieContainer = CookieContainer; 89       //request.AllowAutoRedirect = false; 90  91       if (!String.IsNullOrEmpty(PostData)) 92       { 93         request.ContentType = "application/x-www-form-urlencoded"; 94         request.Method = "POST"; 95         request.BeginGetRequestStream(GetRequestStreamCallback, request); 96       } 97       else 98       { 99         //request.AllowReadStreamBuffering = false;100         request.AllowWriteStreamBuffering = false;101         request.BeginGetResponse(GetResponseCallback, request);102       }103     }104 105     /// <summary>106     /// 开始对用来写入数据的 Stream 对象的异步请求。107     /// </summary>108     /// <param name="ar"></param>109     private void GetRequestStreamCallback(IAsyncResult ar)110     {111       var request = ar.AsyncState as HttpWebRequest;112       if (request == null) return;113       var postStream = request.EndGetRequestStream(ar);114       var byteArray = Encoding.GetBytes(PostData);115       postStream.Write(byteArray, 0, PostData.Length);116       postStream.Close();117       request.BeginGetResponse(GetResponseCallback, request);118     }119 120     /// <summary>121     /// 开始对 Internet 资源的异步请求。 122     /// </summary>123     /// <param name="ar"></param>124     private void GetResponseCallback(IAsyncResult ar)125     {126       var request = ar.AsyncState as HttpWebRequest;127       if (request == null) return;128       try129       {130         using (var response = request.EndGetResponse(ar) as HttpWebResponse)131         {132           if (response != null)133           {134             //if (response.StatusCode == HttpStatusCode.Found)135             //{136             //  string redirect = response.Headers["Location"];137             //  if (!String.IsNullOrEmpty(redirect)) AsynRequest(redirect);138             //  return;139             //}140 141             if (response.StatusCode != HttpStatusCode.OK)142             {143               Trace.TraceError(String.Concat("请求地址:", request.RequestUri, " 失败,HttpStatusCode",144                 response.StatusCode));145               return;146             }147 148             using (var streamResponse = response.GetResponseStream())149             {150               if (streamResponse != null)151               {152                 if (!IsText(response.ContentType))153                 {154                   var contentEncodingStr = response.ContentEncoding;155                   var contentEncoding = Encoding;156                   if (!String.IsNullOrEmpty(contentEncodingStr))157                     contentEncoding = Encoding.GetEncoding(contentEncodingStr);158                   using (var streamRead = new StreamReader(streamResponse, contentEncoding))159                   {160                     var str = streamRead.ReadToEnd();161                     if (CallBackAction != null && !String.IsNullOrEmpty(str))162                       CallBackAction.BeginInvoke(str, request.RequestUri.ToString(), (s) => { },163                         null);164                   }165                 }166                 else167                 {168                   var fileName = String.Concat(DateTime.Now.ToString("yyyyMMdd"), "/",169                     DateTime.Now.ToString("yyyyMMddHHmmssffff"),170                     //Extensions.String_.Extensions.GetRnd(6, true, false, false, false, String.Empty),171                     ".jpg");172                   var fileDirectory = Path.Combine(FileSavePath, DateTime.Now.ToString("yyyyMMdd"));173                   CodePath = Path.Combine(FileSavePath, fileName);174                   if (!Directory.Exists(fileDirectory))175                     Directory.CreateDirectory(fileDirectory);176 177                   //下载文件178                   using (179                     var fileStream = new FileStream(Path.Combine(FileSavePath, fileName),180                       FileMode.Create))181                   {182                     var buffer = new byte[2048];183                     int readLength;184                     do185                     {186                       readLength = streamResponse.Read(buffer, 0, buffer.Length);187                       fileStream.Write(buffer, 0, readLength);188                     } while (readLength != 0);189                   }190                   if (CallBackAction != null && !String.IsNullOrEmpty(fileName))191                     CallBackAction.BeginInvoke(fileName, request.RequestUri.ToString(), (s) => { },192                       null);193                 }194               }195             }196             response.Close();197           }198         }199       }200       catch (WebException ex)201       {202         Trace.TraceError(String.Concat("请求地址:", request.RequestUri, " 失败信息:", ex.Message));203         var toUrl = request.RequestUri.ToString();204         int tryTimes;205         if (urlTryList.TryGetValue(toUrl, out tryTimes))206         {207           urlTryList.TryUpdate(toUrl, tryTimes, tryTimes - 1);208           if (tryTimes - 1 <= 0)209           {210             urlTryList.TryRemove(toUrl, out tryTimes);211             return;212           }213           AsynRequest(toUrl);214         }215       }216       finally217       {218         request.Abort();219       }220     }221 222 223     /// <summary>224     /// 同步请求225     /// </summary>226     /// <param name="url">请求地址</param>227     /// <param name="tryTimes">错误重试次数</param>228     public String SyncRequest(String url, int tryTimes = 3)229     {230       Trace.TraceInformation(String.Concat("开始同步请求:", url));231       urlTryList.TryAdd(url, tryTimes);232       var request = WebRequest.Create(url) as HttpWebRequest;233       if (request == null) return String.Empty;234       request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");235       request.Headers.Add("Accept-Language", "zh-CN,zh;q=0.8");236       request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate |237                        DecompressionMethods.None;238       request.Credentials = CredentialCache.DefaultNetworkCredentials;239       request.UseDefaultCredentials = false;240       request.KeepAlive = false;241       request.PreAuthenticate = false;242       request.ProtocolVersion = HttpVersion.Version10;243       request.UserAgent =244         "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36";245       request.Accept = "text/html,application/xhtml+";246       request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);247       request.Timeout = 1000*60*3;248       request.CookieContainer = CookieContainer;249       request.AllowAutoRedirect = true;250 251       if (!String.IsNullOrEmpty(PostData))252       {253         request.ContentType = "application/x-www-form-urlencoded";254         request.Method = "POST";255         using (var postStream = request.GetRequestStream())256         {257           var byteArray = Encoding.GetBytes(PostData);258           postStream.Write(byteArray, 0, PostData.Length);259           postStream.Close();260         }261       }262       else263       {264         //request.AllowReadStreamBuffering = false;265         request.AllowWriteStreamBuffering = false;266       }267       try268       {269         using (var response = request.GetResponse() as HttpWebResponse)270         {271           if (response != null)272           {273             if (response.StatusCode != HttpStatusCode.OK)274             {275               Trace.TraceError(String.Concat("请求地址:", request.RequestUri, " 失败,HttpStatusCode",276                 response.StatusCode));277               return String.Empty;278             }279             using (var streamResponse = response.GetResponseStream())280             {281               if (streamResponse != null)282               {283                 if (!IsText(response.ContentType))284                 {285                   var contentEncodingStr = response.ContentEncoding;286                   var contentEncoding = Encoding;287                   if (!String.IsNullOrEmpty(contentEncodingStr))288                     contentEncoding = Encoding.GetEncoding(contentEncodingStr);289                   var streamRead = new StreamReader(streamResponse, contentEncoding);290                   var str = streamRead.ReadToEnd();291                   if (CallBackAction != null && !String.IsNullOrEmpty(str))292                     CallBackAction.BeginInvoke(str, request.RequestUri.ToString(), (s) => { }, null);293                   return str;294                 }295 296                 var fileName = String.Concat(DateTime.Now.ToString("yyyyMMdd"), "/",297                   DateTime.Now.ToString("yyyyMMddHHmmssffff"),298                   //Extensions.String_.Extensions.GetRnd(6, true, false, false, false, String.Empty),299                   Path.GetExtension(request.RequestUri.AbsoluteUri));300                 var fileDirectory = Path.Combine(FileSavePath, DateTime.Now.ToString("yyyyMMdd"));301                 if (!Directory.Exists(fileDirectory))302                   Directory.CreateDirectory(fileDirectory);303 304                 //下载文件305                 using (306                   var fileStream = new FileStream(Path.Combine(FileSavePath, fileName),307                     FileMode.Create))308                 {309                   var buffer = new byte[2048];310                   int readLength;311                   do312                   {313                     readLength = streamResponse.Read(buffer, 0, buffer.Length);314                     fileStream.Write(buffer, 0, readLength);315                   } while (readLength != 0);316                 }317                 if (CallBackAction != null && !String.IsNullOrEmpty(fileName))318                   CallBackAction.BeginInvoke(fileName, request.RequestUri.ToString(), (s) => { }, null);319                 return fileName;320               }321             }322             response.Close();323           }324         }325       }326       catch (WebException ex)327       {328         Trace.TraceError(String.Concat("请求地址:", request.RequestUri, " 失败信息:", ex.Message));329         var toUrl = request.RequestUri.ToString();330         if (urlTryList.TryGetValue(toUrl, out tryTimes))331         {332           urlTryList.TryUpdate(toUrl, tryTimes, tryTimes - 1);333           if (tryTimes - 1 <= 0)334           {335             urlTryList.TryRemove(toUrl, out tryTimes);336             Trace.TraceError(String.Concat("请求地址重试失败:", request.RequestUri));337             return String.Empty;338           }339           SyncRequest(toUrl);340         }341       }342       finally343       {344         request.Abort();345       }346       return String.Empty;347     }348 349     /// <summary>350     /// 验证码获取351     /// </summary>352     /// <param name="url">请求地址</param>353     /// <param name="tryTimes">错误重试次数</param>354     public Bitmap GetCheckCode(String url, int tryTimes = 3)355     {356       Trace.TraceInformation(String.Concat("开始同步请求:", url));357       urlTryList.TryAdd(url, tryTimes);358       var request = WebRequest.Create(url) as HttpWebRequest;359       if (request == null) return null;360       request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");361       request.Headers.Add("Accept-Language", "zh-CN,zh;q=0.8");362       request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate |363                        DecompressionMethods.None;364       request.Credentials = CredentialCache.DefaultNetworkCredentials;365       request.UseDefaultCredentials = false;366       request.KeepAlive = false;367       request.PreAuthenticate = false;368       request.ProtocolVersion = HttpVersion.Version10;369       request.UserAgent =370         "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36";371       request.Accept = "text/html,application/xhtml+";372       request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);373       request.Timeout = 1000*60*3;374       request.CookieContainer = CookieContainer;375       request.AllowAutoRedirect = true;376 377       if (!String.IsNullOrEmpty(PostData))378       {379         request.ContentType = "application/x-www-form-urlencoded";380         request.Method = "POST";381         using (var postStream = request.GetRequestStream())382         {383           var byteArray = Encoding.GetBytes(PostData);384           postStream.Write(byteArray, 0, PostData.Length);385           postStream.Close();386         }387       }388       else389       {390         //request.AllowReadStreamBuffering = false;391         request.AllowWriteStreamBuffering = false;392       }393       try394       {395         using (var response = request.GetResponse() as HttpWebResponse)396         {397           if (response != null)398           {399             if (response.StatusCode != HttpStatusCode.OK)400             {401               Trace.TraceError(String.Concat("请求地址:", request.RequestUri, " 失败,HttpStatusCode",402                 response.StatusCode));403               return null;404             }405             using (var streamResponse = response.GetResponseStream())406             {407               if (streamResponse != null)408               {409                 return (Bitmap) Bitmap.FromStream(streamResponse);410               }411             }412             response.Close();413           }414         }415       }416       catch (WebException ex)417       {418         Trace.TraceError(String.Concat("请求地址:", request.RequestUri, " 失败信息:", ex.Message));419         var toUrl = request.RequestUri.ToString();420         if (urlTryList.TryGetValue(toUrl, out tryTimes))421         {422           urlTryList.TryUpdate(toUrl, tryTimes, tryTimes - 1);423           if (tryTimes - 1 <= 0)424           {425             urlTryList.TryRemove(toUrl, out tryTimes);426             Trace.TraceError(String.Concat("请求地址重试失败:", request.RequestUri));427             return null;428           }429           GetCheckCode(toUrl);430         }431       }432       finally433       {434         request.Abort();435       }436       return null;437     }438 439     /// <summary>440     /// 判断文件是否为文本类型441     /// </summary>442     /// <param name="contentType">内容类型</param>443     /// <returns></returns>444     private static bool IsText(String contentType)445     {446       var fileContentType = new List<string>447       {448         "image/Bmp",449         "image/gif",450         "image/jpeg",451         "image/png",452         "image/tiff",453         "application/octet-stream"454       };455       return fileContentType.Contains(contentType);456     }457   }458 }

HttpHepler
 1 using System; 2 using System.Drawing; 3 using System.Drawing.Drawing2D; 4 using System.Drawing.Imaging; 5 using System.Runtime.InteropServices; 6  7 namespace Tesseract.Test.Tools 8 { 9   public class UnCodebase 10   { 11     public Bitmap bmpobj; 12  13     public UnCodebase(Bitmap pic) 14     { 15       bmpobj = new Bitmap(pic); //转换为Format32bppRgb 16     } 17  18     /// <summary> 19     /// 根据RGB,计算灰度值 20     /// </summary> 21     /// <param name="posClr">Color值</param> 22     /// <returns>灰度值,整型</returns> 23     private int GetGrayNumColor(Color posClr) 24     { 25       return (posClr.R*19595 + posClr.G*38469 + posClr.B*7472) >> 16; 26     } 27  28     /// <summary> 29     /// 灰度转换,逐点方式 30     /// </summary> 31     public Bitmap GrayByPixels() 32     { 33       for (int i = 0; i < bmpobj.Height; i++) 34       { 35         for (int j = 0; j < bmpobj.Width; j++) 36         { 37           int tmpValue = GetGrayNumColor(bmpobj.GetPixel(j, i)); 38           bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue)); 39         } 40       } 41       return bmpobj; 42     } 43  44     /// <summary> 45     /// 去图形边框 46     /// </summary> 47     /// <param name="borderWidth"></param> 48     public Bitmap ClearPicBorder(int borderWidth) 49     { 50       for (int i = 0; i < bmpobj.Height; i++) 51       { 52         for (int j = 0; j < bmpobj.Width; j++) 53         { 54           if (i < borderWidth || j < borderWidth || j > bmpobj.Width - 1 - borderWidth || 55             i > bmpobj.Height - 1 - borderWidth) 56             bmpobj.SetPixel(j, i, Color.FromArgb(255, 255, 255)); 57         } 58       } 59       return bmpobj; 60     } 61  62     /// <summary> 63     /// 灰度转换,逐行方式 64     /// </summary> 65     public Bitmap GrayByLine() 66     { 67       Rectangle rec = new Rectangle(0, 0, bmpobj.Width, bmpobj.Height); 68       BitmapData bmpData = bmpobj.LockBits(rec, ImageLockMode.ReadWrite, bmpobj.PixelFormat); 69       // PixelFormat.Format32bppPArgb); 70       //  bmpData.PixelFormat = PixelFormat.Format24bppRgb; 71       IntPtr scan0 = bmpData.Scan0; 72       int len = bmpobj.Width*bmpobj.Height; 73       int[] pixels = new int[len]; 74       Marshal.Copy(scan0, pixels, 0, len); 75  76       //对图片进行处理 77       int GrayValue = 0; 78       for (int i = 0; i < len; i++) 79       { 80         GrayValue = GetGrayNumColor(Color.FromArgb(pixels[i])); 81         pixels[i] = (byte) (Color.FromArgb(GrayValue, GrayValue, GrayValue)).ToArgb(); //Color转byte 82       } 83  84       bmpobj.UnlockBits(bmpData); 85       return bmpobj; 86     } 87  88     /// <summary> 89     /// 得到有效图形并调整为可平均分割的大小 90     /// </summary> 91     /// <param name="dgGrayValue">灰度背景分界值</param> 92     /// <param name="CharsCount">有效字符数</param> 93     /// <returns></returns> 94     public void GetPicValidByValue(int dgGrayValue, int CharsCount) 95     { 96       int posx1 = bmpobj.Width; 97       int posy1 = bmpobj.Height; 98       int posx2 = 0; 99       int posy2 = 0;100       for (int i = 0; i < bmpobj.Height; i++) //找有效区101       {102         for (int j = 0; j < bmpobj.Width; j++)103         {104           int pixelValue = bmpobj.GetPixel(j, i).R;105           if (pixelValue < dgGrayValue) //根据灰度值106           {107             if (posx1 > j) posx1 = j;108             if (posy1 > i) posy1 = i;109 110             if (posx2 < j) posx2 = j;111             if (posy2 < i) posy2 = i;112           }113           ;114         }115         ;116       }117       ;118       // 确保能整除119       int Span = CharsCount - (posx2 - posx1 + 1)%CharsCount; //可整除的差额数120       if (Span < CharsCount)121       {122         int leftSpan = Span/2; //分配到左边的空列 ,如span为单数,则右边比左边大1123         if (posx1 > leftSpan)124           posx1 = posx1 - leftSpan;125         if (posx2 + Span - leftSpan < bmpobj.Width)126           posx2 = posx2 + Span - leftSpan;127       }128       //复制新图129       Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);130       bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);131     }132 133     /// <summary>134     /// 得到有效图形,图形为类变量135     /// </summary>136     /// <param name="dgGrayValue">灰度背景分界值</param>137     /// <param name="CharsCount">有效字符数</param>138     /// <returns></returns>139     public void GetPicValidByValue(int dgGrayValue)140     {141       int posx1 = bmpobj.Width;142       int posy1 = bmpobj.Height;143       int posx2 = 0;144       int posy2 = 0;145       for (int i = 0; i < bmpobj.Height; i++) //找有效区146       {147         for (int j = 0; j < bmpobj.Width; j++)148         {149           int pixelValue = bmpobj.GetPixel(j, i).R;150           if (pixelValue < dgGrayValue) //根据灰度值151           {152             if (posx1 > j) posx1 = j;153             if (posy1 > i) posy1 = i;154 155             if (posx2 < j) posx2 = j;156             if (posy2 < i) posy2 = i;157           }158           ;159         }160         ;161       }162       ;163       //复制新图164       Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);165       bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);166     }167 168     /// <summary>169     /// 得到有效图形,图形由外面传入170     /// </summary>171     /// <param name="dgGrayValue">灰度背景分界值</param>172     /// <param name="CharsCount">有效字符数</param>173     /// <returns></returns>174     public Bitmap GetPicValidByValue(Bitmap singlepic, int dgGrayValue)175     {176       int posx1 = singlepic.Width;177       int posy1 = singlepic.Height;178       int posx2 = 0;179       int posy2 = 0;180       for (int i = 0; i < singlepic.Height; i++) //找有效区181       {182         for (int j = 0; j < singlepic.Width; j++)183         {184           int pixelValue = singlepic.GetPixel(j, i).R;185           if (pixelValue < dgGrayValue) //根据灰度值186           {187             if (posx1 > j) posx1 = j;188             if (posy1 > i) posy1 = i;189 190             if (posx2 < j) posx2 = j;191             if (posy2 < i) posy2 = i;192           }193           ;194         }195         ;196       }197       ;198       //复制新图199       Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);200       return singlepic.Clone(cloneRect, singlepic.PixelFormat);201     }202 203     /// <summary>204     /// 平均分割图片205     /// </summary>206     /// <param name="RowNum">水平上分割数</param>207     /// <param name="ColNum">垂直上分割数</param>208     /// <returns>分割好的图片数组</returns>209     public Bitmap[] GetSplitPics(int RowNum, int ColNum)210     {211       if (RowNum == 0 || ColNum == 0)212         return null;213       int singW = bmpobj.Width/RowNum;214       int singH = bmpobj.Height/ColNum;215       Bitmap[] PicArray = new Bitmap[RowNum*ColNum];216 217       Rectangle cloneRect;218       for (int i = 0; i < ColNum; i++) //找有效区219       {220         for (int j = 0; j < RowNum; j++)221         {222           cloneRect = new Rectangle(j*singW, i*singH, singW, singH);223           PicArray[i*RowNum + j] = bmpobj.Clone(cloneRect, bmpobj.PixelFormat); //复制小块图224         }225       }226       return PicArray;227     }228 229     /// <summary>230     /// 返回灰度图片的点阵描述字串,1表示灰点,0表示背景231     /// </summary>232     /// <param name="singlepic">灰度图</param>233     /// <param name="dgGrayValue">背前景灰色界限</param>234     /// <returns></returns>235     public string GetSingleBmpCode(Bitmap singlepic, int dgGrayValue)236     {237       Color piexl;238       string code = "";239       for (int posy = 0; posy < singlepic.Height; posy++)240         for (int posx = 0; posx < singlepic.Width; posx++)241         {242           piexl = singlepic.GetPixel(posx, posy);243           if (piexl.R < dgGrayValue) // Color.Black )244             code = code + "1";245           else246             code = code + "0";247         }248       return code;249     }250 251     /// <summary>252     /// 去掉噪点253     /// </summary>254     /// <param name="dgGrayValue"></param>255     /// <param name="MaxNearPoints"></param>256     public Bitmap ClearNoise(int dgGrayValue, int MaxNearPoints)257     {258       Color piexl;259       int nearDots = 0;260       int XSpan, YSpan, tmpX, tmpY;261       //逐点判断262       for (int i = 0; i < bmpobj.Width; i++)263         for (int j = 0; j < bmpobj.Height; j++)264         {265           piexl = bmpobj.GetPixel(i, j);266           if (piexl.R < dgGrayValue)267           {268             nearDots = 0;269             //判断周围8个点是否全为空270             if (i == 0 || i == bmpobj.Width - 1 || j == 0 || j == bmpobj.Height - 1) //边框全去掉271             {272               bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255));273             }274             else275             {276               if (bmpobj.GetPixel(i - 1, j - 1).R < dgGrayValue) nearDots++;277               if (bmpobj.GetPixel(i, j - 1).R < dgGrayValue) nearDots++;278               if (bmpobj.GetPixel(i + 1, j - 1).R < dgGrayValue) nearDots++;279               if (bmpobj.GetPixel(i - 1, j).R < dgGrayValue) nearDots++;280               if (bmpobj.GetPixel(i + 1, j).R < dgGrayValue) nearDots++;281               if (bmpobj.GetPixel(i - 1, j + 1).R < dgGrayValue) nearDots++;282               if (bmpobj.GetPixel(i, j + 1).R < dgGrayValue) nearDots++;283               if (bmpobj.GetPixel(i + 1, j + 1).R < dgGrayValue) nearDots++;284             }285 286             if (nearDots < MaxNearPoints)287               bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255)); //去掉单点 && 粗细小3邻边点288           }289           else //背景290             bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255));291         }292       return bmpobj;293     }294 295     /// <summary>296     /// 扭曲图片校正297     /// </summary>298     public Bitmap ReSetBitMap()299     {300       Graphics g = Graphics.FromImage(bmpobj);301       Matrix X = new Matrix();302       // X.Rotate(30);303       X.Shear((float) 0.16666666667, 0); // 2/12304       g.Transform = X;305       // Draw image306       //Rectangle cloneRect = GetPicValidByValue(128); //Get Valid Pic Rectangle307       Rectangle cloneRect = new Rectangle(0, 0, bmpobj.Width, bmpobj.Height);308       Bitmap tmpBmp = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);309       g.DrawImage(tmpBmp,310         new Rectangle(0, 0, bmpobj.Width, bmpobj.Height),311         0, 0, tmpBmp.Width,312         tmpBmp.Height,313         GraphicsUnit.Pixel);314 315       return tmpBmp;316     }317   }318 }

UnCodebase
 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Tesseract.Test.Tools; 7  8 namespace Tesseract.Test 9 {10   /// <summary>11   /// 网站用户12   /// </summary>13   public class WebUser14   {15     /// <summary>16     /// 用户名17     /// </summary>18     private string _userName = string.Empty;19 20     /// <summary>21     /// 密码22     /// </summary>23     private string _password = string.Empty;24 25     /// <summary>26     /// 验证码27     /// </summary>28     private string _checkCode = string.Empty;29 30     private HttpHelper _httpHelper = new HttpHelper();31 32     /// <summary>33     /// 构造函数34     /// </summary>35     public WebUser()36     {37       _userName = "admin"; //初始化用户38       _password = "password"; //初始化密码39       Login();40     }41 42 43     /// <summary>44     /// 登录45     /// </summary>46     private void Login()47     {48       //登录页49       _httpHelper.SyncRequest("Login.html");50 51       //获取验证码图片52       var bitmap = _httpHelper.GetCheckCode("CheckCode.html");53 54       //解析验证码55       using (var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default))56       {57         using (var entity = engine.Process(bitmap))58         {59           _checkCode = entity.GetText();60         }61       }62 63       //登录验证64       _httpHelper.PostData = string.Format("userName={0}&password={1}&checkcode={2}",65         _userName, _password, _checkCode);66       _httpHelper.SyncRequest("CheckLogin.html");67     }68   }69 }

WebUser

四、代码解释

1、模拟登录的过程基本都是访问登录页面获取相关的cookie。

2、访问验证码页面这样就不用将验证码下载到本地再解析。直接在程序内解析。减少验证码本地图片文件增加。

3、使用tesseract来解析验证码。(需要看验证码的干扰是否严重,使用UnCodebase对验证码图片适当的处理可以增加识别正确率)

4、访问登录验证页面将用户名密码验证码POST过去。

5、登录成功。