Bài 3 – Viết 1 plugin cơ bản hoàn chỉnh cho 1 site.

Chào mọi người, đây là bài thứ 3 trong loạt bài viết hướng dẫn tạo plugin cho All1Tool. Trong bài này, mình sẽ hướng dẫn hoàn chỉnh cách viết auto cho 1 site cơ bản. Khi bạn đã nắm vững các kĩ thuật trong bài này, thì bạn có thể áp dụng để viết cho hầu hết các site hiện nay.

Trước hết, bạn cần download những thứ sau đây:
– Trình duyệt chrome
– Fiddler: đây là tool để bắt tất cã những request ra vào máy tính. Link: http://fiddler2.com/

1. Theo dõi mục tiêu 😀

Như các bạn cũng biết để viết được auto cho 1 trang web hay game, thì ít nhất bạn phải vô trang web đó, dạo 1 vòng để tìm hiểu cơ chế hoạt động của trang web, khi bạn đã hiểu hầu hết luồng của trang web, thì lúc đó bạn mới tiến hành viết auto cho trang web đó được.

Bắt đầu:

– Bật Fiddler lên rồi để đó, bước này quan trọng.

– Mở chrome, và vào trang web :http://prom247.com/login.html để vào trang đăng nhập. (Nhớ là phải đăng kí trước :))

– Khi ở trang đăng nhập, thông thường bạn sẽ thấy các thông tin cần nhập bao gồm, Username, Password, và captcha.

– Trong chrome chuột phải lên hình captcha của trang web đó chọn Inspect Element.Capture_com 1

– Như bạn sẽ thấy, link của bức ảnh đó là: image2.php?$res, ghi nhớ link này để về sau viết auto :D.

– Ok, điền username,password và captcha để đăng nhập vào tool.

– Câu hỏi đặt ra là khi đăng nhập vào web, trình duyệt sẽ send 1 request tới server với thông tin đăng nhập,vậy thì làm sao mình có thể biết được dạng request đó là gì? Để trả lời câu hỏi đó, lúc này ta cần phải nhờ đến phần mềm Fiddler. Nếu như bạn đã mở phần mềm đó từ lúc đầu, thì bây giờ chuyển qua phần mềm đó, bạn sẽ thấy như sau.

Capture 10

-Khung bên trái là thông tin tất cả request, mà chương trình bắt được. (Nhấn cột host để tool sắp xếp cho dễ nhìn). Khung bên phải chọn tab Inspector, nó sẽ hiện thông tin chi tiết request mà mình đã chọn ở khung bên trái.

– Những request có màu xanh dương hoặc đen, là request chính cho trang web. Những màu khác là request cho hình ảnh hoặc file javascript.

– Khi nhìn vào, ta có thể thấy, request login.html được gửi trước, tiếp đến là request lấy hình ảnh captcha, tiếp đến chỗ mình khoanh tròn, là request để đăng nhập: /login.php.

– Nhìn qua bên phải strong tab Inspector, chọn tab Webform, bạn sẽ thấy thông tin mình cẩn gửi lên  server: username, password, và code.

Như bạn thấy với 2 dụng cụ chrome và fiddler, bạn có thể biết được tất cả các hành động trong trang web cũng như dựa trên đó để viết nên auto.

– Ok, giờ vào trang chính để tìm ads, thì khi điều tra ta dễ dàng biết được trang hiển thị ad là: http://prom247.com/sites.php

– Khi vào trang này, nó bắt bạn phải đếm sao mới hiện ra các ads, chuột phải lên captcha chọn inspect element, thì ta biết link của captcha là:

image.php?Array   – ghi nhớ link này

– Ok giờ nhấn vào số tương ứng với số ngôi sao để hiện ra ad, sau đó tất cả các ad cho bạn click sẽ được hiện ra.(Ta sẽ dùng fiddler để biết được những thông tin mà nó gửi lên khi click lên những con số)

– Với trang này, để xem được ad, thì bạn phải click vô hình tròn. Nhưng khoan, giờ bạn click chuột phải lên hình tròn, và chọn inspect element.

Bạn sẽ thấy được thẻ html như sau:

<a href=”/adview-93.html” target=”_blank” onclick=”javascript:goserf(93);”>r r</a>

Nếu làm tương tự với những ad khác bạn sẽ thấy, cùng 1 kiểu thẻ nhưng chỉ khác phần :adview-93.html có thể thành adview-94.html hay adview-95.html gì đó.

Capture_com 2

– Vậy ta có thể biết được rằng quy luật để lấy tất cả các ad trong trang này là: Kiếm tất cả thẻ a có attribute href bắt đầu với /adview-

– Tiếp tục ta nhấn vào 1 ad để tiến hành xem ad đó,

– Khi ta đã vào trang để xem ad, ta sẽ thấy thời gian chờ ad.

– Sau khi chờ ad xong, web lại bắt ta nhập captcha, may mắn là captcha vẫn là đếm sao. và link hình của captcha là: image.php?Resource id #5

Capture 9

Đến lúc này để biết được,  để biết được lúc chọn 1 số thì sẽ có những request nào, thì ta phải nhờ đến fiddle tiếp thôi, xem nào:

Capture 10

Khi nhìn vào hình trên ta sẽ thấy như sau:

Phần khoanh số 1: rõ ràng ta có thể thấy đó là request để vào trang xem ad

Phần số 2: gửi một request khác có link: vls.php. Và bắt đầu chờ xem ad

Phần số 3: Sau khi chờ xong, nó sẽ send 1 request khác tới link: vls.php?view=ok

Phần số 4: Ta có thể thấy request được send để lấy captcha.

Phần số 5: Gửi reqest thông báo kết qua của captcha mà người dùng nhập ở link: /vls.php?view=ok&ds=clicked

Ok. tới đây tạm thời, ta đã xác định được rõ ràng luồng của website, bắt đầu code thôi. 😀

——————

2. Phần viết code 

Bây giờ ta có thể định hình được rằng, auto của chúng ta cần được viết có luồng như sau:

a.Vào trang đăng nhập

a-1. Hiện hình ảnh captcha cho người dùng nhập.

a-2. Khi người dùng nhập xong, đi đến bước b

b. Giả request giống như ta nhấn ok để login.

c. Tìm đên trang hiện ra tất cả các ads

d. Nếu web có yêu cầu “đếm sao”, viết hàm đếm sao và giả request gửi đáp án đến web.

c. Tìm tất cả các ad có định dạng: “Là thẻ a và có attribute href bắt đầu với chuỗi /adview-”

d. Vòng lặp, cho mỗi ad tìm được, gửi request đến ad đó và tiến hành xử lý trang của ad đó

d-1 : Lấy thông tin thời gian chờ và tiến hành chờ ad.

d-2: Đếm sao, và gửi đáp án đến web

d-3: Tiếp tục xử lý ad kế tiếp

e. Kết thúc vòng lặp, ta vào trang profile để tìm thông tin số tiền hiện có

d. Kết thúc plugin.

Ok, bây giờ ta có thể viết code chính xác y như trên.

– Trước khi vào phần source code, Chúng ta cần thêm các thư viện sau:

+ HtmlAgilityPack.dll có trong thư mục chứa tool. Như mình đã nói đó là thư viện quan trọng, giúp ta làm việc với dữ liệu trả về từ trang web.

+ System.Drawing nằm trong phần NetFrameWork (Cách thêm thư việc mình đã nói ở bài 2).


[PluginInfo(PluginName = "All1Tool - Prom247")]
 [Export(typeof(All1PluginScript))]
 class Prom247PluginScript : All1PluginScript
 {

private Queue<string> _linkQueue;

public override All1ActionResult Begin(object arg)
 {
 // Gửi request tới server để login
 Client.GetRequest("login.html");
 //Lấy hình ảnh captcha bằng hàm GetBitmap và trả về hình ảnh kiểu bitmap.
 Bitmap bm = Client.GetBitmap("image2.php?$res");
 //Lúc này ta cần hiện captcha đó trên màn hình, và nhận thông tin mà người dùng nhập vào.
 // bạn có thể dễ dàng làm việc đó bằng cách, new 1 class kiểu All1WaitTextCaptResult, tham số Image truyền vào là
 //hình ảnh captcha bạn vừa lấy ở phía trên.
 // Chúng ta cần truyền phương thức tiếp theo sau khi ta đã thoát ra phương thức hiện tại, bằng cách truyền vào biến
 //NextMethod, ở đây phương thức tiếp theo của ta là SubmitLogin.
 return new All1WaitTextCaptResult { Image = bm, NextMethod = SubmitLogin };
 }

private All1ActionResult SubmitLogin(object arg)
 {
 // Chúng ta sẽ tạo một biến kiểu Dictionary để chứa thông tin data mình cần gửi đến server.
 Dictionary<string, string> dic = new Dictionary<string, string>();

dic.Add("logusername", Username); //Username của người dùng nhập
 dic.Add("logpassword", Password);// Password của người dùng nhập

//Lúc này biến CaptchaResultStr của lớp All1PluginScript đã chứa thông tin người dùng nhập
 // Để biết được những chuổi như là logusername,logpassword,code ở đâu ra, thì bạn phải dùng fiddler để nhận biết.
 dic.Add("code", CaptchaResultStr);

//Ok, Nào ta gửi request tới trang login.php với data mình vừa nhập vào dic.
 //Tham số đầu là link cần gửi, tham số thứ 2 là data cần gửi
 Client.PostRequest("login.php", dic);

//Lúc này ta có thể kiểm tra nội dung trang web trả về có chứa chuỗi prom247.com/exit.html hay không.
 // Biến ResponseStr sẽ chứa nội dung của trang web dưới dạng chuỗi.
 // Nếu có thì có nghĩa ta đã đăng nhập thành công, nếu không ta trả về biế kiểu All1StopingResult.
 // Khi tool thấy ta trả về kiểu này, có nghĩa rằng ta muốn dừng chạy plugin. Ta có thể thêm
 // lý do ta ngừng chạy thông qua biến Reason.
 if (!Client.ResponseStr.Contains("prom247.com/exit.html"))
 {
 return new All1StopingResult { Reason = "LoginFailed" };
 }
 // Đăng nhập thành công rồi, thì ta vào trang web chính chứa các ad.
 Client.GetRequest("sites.php");
 // Tới đây bạn sẽ để ý rằng có khi ta dùng hàm GetRequest và PostRequest, để biết được dùng hàm nào thì đó là dựa vào kiểu request
 // mà trang web đó thực sự cần. Bạn cần phải xem thông tin đó bằng cách dùng Fiddler.

// Chúng ta kiểm tra xem, trang này có cần ta nhập captcha trước khi hiện ra danh sách các ad hay không.
 if (Client.ResponseStr.Contains("specify the number of stars in the picture"))
 {
 // Nếu tới đây có nghĩa rằng ta cần nhập captcha.
 // Lấy hình ảnh của captcha.
 Bitmap captchaBm = Client.GetBitmap("image.php?Array");

//Lớp ColorStarRecognizer là 1 lớp do mình viết sẵn, mục đính là đếm số ngôi sao chứa trong captcha.
 int result = ColorStarRecognizer.Recognize(captchaBm);

//Sau khi đã biết được bao nhiêu ngôi sao, ta sẽ gửi request trả lời đáp an cho web.
 // Tham số đầu là link cần gửi, tham số 2 là data cần gửi, ở đây ta không cần dùng dạng dictionary để gửi data.
 // ta có thể truyền dưới dạng chuổi và có format như sau name=value.
 // Tham số cuối cùng là link hiện tại mà mình đang đứng để gửi request, tham số này ko thực sự quan trọng, nhưng
 // vài trang web đòi hỏi ta phải có thông tin này. Đó là thông tin tương ứng với Header referer của request.
 Client.PostRequest("sites.php", "code=" + result, Client.ResponseFullUrl);

//Ta giả sử kết quả ta gửi là chính xác, lúc này ta chỉ cần gửi request lại lần nữa cho trang xem danh sách các ad
 Client.GetRequest("sites.php");
 }

//Như bạn đã biết, khi lấy thông tin 1 trang web, ngoài trả về kiểu chuỗi, tool còn trả về một kiều cây DOM.
 //Kiểu này cho phép bạn duyệt, tìm kiếm thông tin các thẻ Html 1 cách nhanh chóng.
 // Để dùng được bạn cần add reference tới thư viện Agility Html, dll này có sẵn trong thư mục All1Tool, có tên là: HtmlAgilityPack.dll
 //ở đây câu trên có nghĩa rằng, tìm tất cả thẻ a trong trang web, có attribte href được bắt đầu bằng chuỗi '/adview'
 // thực chất chuổi bên trong hàm SelectNodes là cú pháp của XPath, được dùng để tìm thông tin của 1 node trong DOM tree.
 // Nếu bạn chưa biết XPath là gì, thì nên google về nó:D
 // Câu lệnh sẽ trả về một tập các node tìm được.
 HtmlNodeCollection nodes = Client.ResponseDoc.DocumentNode.SelectNodes("//a[starts-with(@href,'/adview')]");

 //Khởi tạo 1 queue, ta sẽ chứa thông tin các ad tìm được trong đây.
 _linkQueue = new Queue<string>();

if (nodes != null)
 {
 foreach (HtmlNode node in nodes)
 {
 //Dòng lệnh này đảm bảo rằng ta kiểm tra không có cheat text nào có trong ad đó.
 if (!IsCheatLink(node.ParentNode.InnerText))
 {
 // Nếu có vẻ ổn thỏa, lấy đường dẫn của ad đó, và thêm vào queue
 string url = node.Attributes["href"].Value;
 _linkQueue.Enqueue(url);
 }

}
 }

//ok, ta chuyển tới hàm kế tiếp.
 return new All1NextMethodResult { NextMethod = ProcessAdPage};
 }

private All1ActionResult ProcessAdPage(object arg)
 {
 //Ta kiểm tra queue còn ad không, nếu không còn ta sẽ chuyển ngay tới phương End.
 if (_linkQueue.Count <= 0)
 {
 return new All1NextMethodResult { NextMethod = End };
 }
 // lấy thông tin của ad, hàm peek lấy 1 phần tử, chưa thật sự lấy ra khỏi queue
 string currentAdLink = _linkQueue.Peek();

//Gửi request tới ad vừa lấy ra, truyển thêm tham số sites.php, để thông báo cho web rằng, ta đang đứng ở trang sites và gửi request.
 Client.GetRequest(currentAdLink, "sites.php");

//Dựa vào Fiddle, ta biết rằng ta phải gửi request tới link vls.php
 Client.GetRequest("vls.php", Client.ResponseFullUrl);

//Tới lú này, thông tin trang web từ link vls.php sẽ được trả về
 // Nhờ vào Fiddler, đọc nội dung được trả về, ta biết được rằng thời gian chờ nằm trong thẻ có id là sfbtimer.
 // Dùng hàm GetElementbyId ta có thể lấy được thông tin của node đó
 HtmlNode timerNode = Client.ResponseDoc.GetElementbyId("sfbtimer");

// chuyển từ kiểu chuổi sang int
 int timer = int.Parse(timerNode.InnerText);

//Ok, đây là hàm khá nhiều thứ trong đây.
 // Với lớp All1WaitingAdResult được trả về từ hàm nay, thì tool sẽ biết rằng tool cần chờ trong khoảng một thời gian, thời gian chờ
 // sẽ được biết thông qua Biến WaitingTime của lớp. Ví dụ nếu gán 10, thì tool sẽ chờ 10 giây, đồng thời hiện thông tin đếm thời gian trên giao diện.
 //Biến RemainAds chứa số lượng ad còn lại trong biến queue
 // Tiếp theo, tương tự như ở trên, ta cần truyển phương thức tiếp theo cho biến NextMethod.
 // Nhưng khác biệt ở đây là ta dùng dạng rút gọn, định nghĩa phương thức thẳng bên trong lúc new class. bạn có thể nghĩ thay vì định nghĩa
 // phương thức bên ngoài, thì nay ta định nghĩa thẳng bên trong.
 // Đây là lamda expression hỗ trợ bởi C#, nếu bạn chưa quen có thể google để biết thêm.
 return new All1WaitingAdResult
 {
 WaitingTime = timer,
 RemainAds = _linkQueue.Count,
 NextMethod = (o) =>
 {
 // Dựa vào fiddle ta biết được rằng, cần gửi request tới link vls.php?view=ok, để lấy thông tin captcha.
 Client.GetRequest("vls.php?view=ok", Client.ResponseFullUrl);

// Lấy thông tin hình ảnh captcha và đếm sao 😀
 Bitmap captchaImage = Client.GetBitmap("image.php?Resource id #5", Client.ResponseFullUrl);
 int result = ColorStarRecognizer.Recognize(captchaImage);

// Gửi thông tin số lượng sao đến server.
 Client.PostRequest("vls.php?view=ok&ds=clicked", "code=" + result, Client.ResponseFullUrl);

 //Cứ cho là ok, thì lúc này ta thực sự xóa 1 phần từ ra khỏi queue
 _linkQueue.Dequeue();
 //Ta gọi lại hàm ProcessAdPage
 return new All1NextMethodResult { NextMethod = ProcessAdPage };
 }
 };

}
 public override All1ActionResult End(object arg)
 {
 //Lúc này là hàm end, sau khi gọi hàm này, tool sẽ stop plugin luôn, vì vậy lúc này ta lấy thông tin số tiền ta hiện có của trang web.
 // Gửi request đến trang profile.html.
 Client.GetRequest("profile.html");

//Dùng XPath để kiếm node, có text là All you have earned:
 HtmlNode textNode = Client.ResponseDoc.DocumentNode.SelectSingleNode("//b[text()='All you have earned:']");
 // từ đó ta có thể lấy được số tiền, hàm dưới có thể lấy được con số xuất hiện đầu tiên trong chuỗi.
 Amount = ParseHelper.GetAmount(textNode.ParentNode.ParentNode.InnerText);

// Như vậy là đã xong, ta chỉ cần trả về lớp All1ActionResult, thực chất lớp này chính là lớp cha của tất cả các lớp Result mà các hàm trên trả về
 return new All1ActionResult { Message = "Finish" };
 }
 }

Đoạn code trên mình đã comment thông tin đầy đủ, và giải thích cho từng dòng code. Nếu bạn nghiên cứu kỹ sẽ thấy rất đơn giản để viết auto.

Bài sau, mình sẽ nói đến chi tiết những phần còn lại mà plugin sẽ hỗ trợ bạn để viết auto, ví dụ như nếu có 1 loại captcha khác, mà cần người dùng lựa chọn 1 trong các đáp án, thì lúc đó phải viết như thế nào.

6 comments

  1. Down VS Express 2012

    1/ Debug => không thấy phần Start Option chọn Start External program

    2/ Khi biên dịch => error

    Error 1 The type or namespace name ‘Bitmap’ could not be found (are you missing a using directive or an assembly reference?) D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 24 13 MyFirstPlugin
    Error 2 The type or namespace name ‘Bitmap’ could not be found (are you missing a using directive or an assembly reference?) D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 68 17 MyFirstPlugin
    Error 3 The name ‘ColorStarRecognizer’ does not exist in the current context D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 71 30 MyFirstPlugin
    Error 4 The type or namespace name ‘HtmlNodeCollection’ could not be found (are you missing a using directive or an assembly reference?) D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 91 13 MyFirstPlugin
    Error 5 The type or namespace name ‘HtmlNode’ could not be found (are you missing a using directive or an assembly reference?) D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 134 13 MyFirstPlugin
    Error 6 The type or namespace name ‘Bitmap’ could not be found (are you missing a using directive or an assembly reference?) D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 157 21 MyFirstPlugin
    Error 7 The name ‘ColorStarRecognizer’ does not exist in the current context D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 158 34 MyFirstPlugin
    Error 8 The type or namespace name ‘HtmlNode’ could not be found (are you missing a using directive or an assembly reference?) D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 178 13 MyFirstPlugin
    Error 9 The name ‘ParseHelper’ does not exist in the current context D:\Make Money\Cheat\Cheat\C#\MyFirstPlugin\MyFirstPlugin\HelloWorldPlugin.cs 180 22 MyFirstPlugin

    => Thớt xem thiếu thư viện nào vậy => nhờ thớt chỉ dùm

  2. 1. Mình có cập nhật lại bài 2 cho phần run external programe cho visual studio express. Nó như sau:

    (Lưu ý: Theo mình biết thì bản visual sutdio express, không hỗ trợ giao diện cho phần start external program. Vì vậy bạn cần phải edit file config của project như sau (những bạn ko dùng bản express thì ko cần làm bước này):

    Trong thư mục chứa project có file MyFirstPlugin.csproj.user, chuột phải chọn mở với Notepad (hoặc những trình edit text nào mà bạn có)

    Thêm các dòng sau vào tag PropertyGroup:

    <StartAction>Program</StartAction>
    <StartProgram>C:\Users\n.bui\Desktop\All1Tool 2.60\All1Tool.exe</StartProgram>
    <StartWorkingDirectory>C:\Users\n.bui\Desktop\All1Tool 2.60\</StartWorkingDirectory>

    Thay phần text trong StartProgram bằng đường dẫn tới file All1Tool.exe

    Thay phần text trong StartWorkingDirectory bằng đường dẫn tới thư mục chứa All1Tool.exe

    Thông thường ta được file như sau:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt;
    <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
    <StartAction>Program</StartAction>
    <StartProgram>C:\Users\n.bui\Desktop\All1Tool 2.60\All1Tool.exe</StartProgram>
    <StartWorkingDirectory>C:\Users\n.bui\Desktop\All1Tool 2.60\</StartWorkingDirectory>
    </PropertyGroup>
    </Project>

    2. Còn phần lỗi là do bạn chưa thêm thư viện (mình cũng đã cập nhật ở bài 3):

    – Trước khi vào phần source code, Chúng ta cần thêm các thư viện sau:

    + HtmlAgilityPack.dll có trong thư mục chứa tool. Như mình đã nói đó là thư viện quan trọng, giúp ta làm việc với dữ liệu trả về từ trang web.

    + System.Drawing nằm trong phần NetFrameWork (Cách thêm thư việc mình đã nói ở bài 2).

    Thanks

  3. Please help!
    Error 1 The type or namespace name ‘Bitmap’ could not be found (are you missing a using directive or an assembly reference?)

Leave a comment