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+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
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 try
129 {
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 else
167 {
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 do
185 {
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 finally
217 {
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+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
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 else
263 {
264 //request.AllowReadStreamBuffering = false;
265 request.AllowWriteStreamBuffering = false;
266 }
267 try
268 {
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 do
312 {
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 finally
343 {
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+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
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 else
389 {
390 //request.AllowReadStreamBuffering = false;
391 request.AllowWriteStreamBuffering = false;
392 }
393 try
394 {
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 finally
433 {
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為單數,則右邊比左邊大1
123 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 else
246 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 else
275 {
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/12
304 g.Transform = X;
305 // Draw image
306 //Rectangle cloneRect = GetPicValidByValue(128); //Get Valid Pic Rectangle
307 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 WebUser
14 {
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、登錄成功。