Tìm kiếm


    Tự động gửi tin nhắn Zalo bằng C# và Selenium


    Giới thiệu

    Trong bài viết này, mình sẽ chia sẻ về một công cụ tự động gửi tin nhắn Zalo bằng C# kết hợp với Selenium.

    Với công cụ này, bạn có thể tự động hóa việc gửi tin nhắn trên Zalo mà không cần phải thao tác thủ công.

    Tại sao chọn Zalo?

    Zalo là ứng dụng nhắn tin phổ biến ở Việt Nam, không chỉ hỗ trợ nhắn tin, gọi video, mà còn cung cấp nhiều tính năng hữu ích khác.

    Sử dụng Zalo để gửi tin nhắn tự động có thể phục vụ cho nhiều mục đích khác nhau.

    Với tool này các bạn có thể chình sửa nó để thay thế cho Zalo OA trong việc gửi tin nhắn tự động cho khách hàng.

    Code Zalo

    Để tạo ra một công cụ tự động gửi tin nhắn Zalo, bạn cần thực hiện các bước sau:

    1. Chuẩn bị môi trường

    Đầu tiên, bạn cần cài đặt một số công cụ sau:

    • Cài đặt Visual Studio

    • Cài đặt Selenium WebDriver

      Install-Package Selenium.WebDriver 
      Install-Package Selenium.WebDriver.ChromeDriver
      Install-Package Selenium.WebDriver
    • Cài đặt ChromeDriver: Để Selenium có thể tương tác với trình duyệt Google Chrome, bạn cần tải và cài đặt ChromeDriver phù hợp với phiên bản trình duyệt của mình. Trong bài viết này mình sử dụng version 131.0.6778.85. Các bạn có thể xem tại đây.

    2. Cấu hình Selenium và ChromeDriver

    Về cơ bản tool sẽ có các chức năng Kiểm tra trạng thái đăng nhập, Tìm kiếm và chọn người dùng và Gửi tin nhắn

    public class ZaloLibrary
    {
        public bool QRCodeLoginExpired(IWebDriver driver)
        {
            try
            {
                var ele = driver.FindElement(By.ClassName(AppConst.QrcodeExpiredClass));
                var qrTitle = ele.FindElement(By.TagName("p")).Text;
    
                if (qrTitle.Equals("Mã QR hết hạn")) return true;
    
                return false;
            }
            catch
            {
                Console.WriteLine("ERROR: Not found qr code expired");
                return false;
            }
        }
    
        public async Task ReGenerateQRCodeLogin(IWebDriver driver)
        {
            await Task.Delay(3 * 1000);
    
            try
            {
                var ele = driver.FindElement(By.ClassName(AppConst.QrcodeExpiredClass));
                var btnReGenerate = ele.FindElement(By.ClassName("btn--s"));
                btnReGenerate.Click();
    
                Console.WriteLine("INFO: Re-generate qr code login");
            }
            catch
            {
                Console.WriteLine("ERROR: Not found qr code expired");
            }
        }
    
        public async Task SearchAndSelectUser(IWebDriver driver, string text)
        {
            try
            {
                var input = driver.FindElement(By.Id(AppConst.ContactSearchInputId));
                input.SendKeys("");
                input.SendKeys(text);
    
                Console.WriteLine($"INFO: Search user {text}");
    
                await Task.Delay(3 * 1000);
    
                var user = driver.FindElement(By.CssSelector(AppConst.DivFriendItem));
                user.Click();
    
                await Task.Delay(3 * 1000);
    
                Console.WriteLine($"INFO: Selected user {text}");
            }
            catch
            {
                Console.WriteLine("ERROR: Not found user");
                await SearchAndSelectUser(driver, text);
            }
        }
    
        private async Task<bool> ChatBoxIsVisiable(IWebDriver driver)
        {
            await Task.Delay(3 * 1000);
    
            try
            {
                var chatBox = driver.FindElement(By.Id(AppConst.AvaChatBoxViewId));
                return true;
            }
            catch
            {
                return await ChatBoxIsVisiable(driver);
            }
        }
    
        public async Task SendMessage(IWebDriver driver, string text)
        {
            try
            {
                if (await ChatBoxIsVisiable(driver))
                {
                    var chatInput = driver.FindElement(By.Id(AppConst.ChatInputContentId));
                    chatInput.Click();
    
                    await Task.Delay(3 * 1000);
    
                    var richInput = driver.FindElement(By.Id(AppConst.RichInputId));
                    richInput.SendKeys(text);
                    
                    await Task.Delay(3 * 1000);
    
                    var btnSend = driver.FindElement(By.CssSelector(AppConst.ButtonSend));
                    btnSend.Click();
    
                    Console.WriteLine($"INFO: Sent message {text}");
                }
            }
            catch
            {
                Console.WriteLine("ERROR: Send message fail");
                await SendMessage(driver, text);
            }
        }
    }
    
    string path = Directory.GetCurrentDirectory().Replace("\\bin\\Debug\\net8.0", string.Empty);
    
    var driver = new ChromeDriver(path + @"\Drivers"); // Tạo thư mục Drivers và chứa file chromedriver.exe
    
    driver.Navigate().GoToUrl("https://chat.zalo.me/");
    
    await Task.Delay(20 * 1000);
    
    var zaloLib = new ZaloLibrary();
    
    while (true)
    {
        var currentUrl = driver.Url;
        var isCurrentUrl = currentUrl.StartsWith("https://id.zalo.me/");
        var qrCodeLoginExpired = zaloLib.QRCodeLoginExpired(driver);
    
        if (qrCodeLoginExpired)
        {
            await zaloLib.ReGenerateQRCodeLogin(driver);
        }
    
        if (!isCurrentUrl) break;
    
        await Task.Delay(15 * 1000);
    }
    
    await zaloLib.SearchAndSelectUser(driver, "0399059205");
    
    await zaloLib.SendMessage(driver, "Hello! I am ProG Coder");
    
    

    Mình sử dụng khá nhiều Task.Delay để cho Browser có thời gian load và cũng giảm thiểu tình trạng bị Stackoverflow do dùng đệ quy để check element.

    3. Đăng nhập vào Zalo

    Khi chạy lên bạn sẽ thấy màn hình đăng nhập của Zalo. Và bạn cần quét mã để đăng nhập trước khi tool có tự động gửi tin nhắn.

    Tự động hóa quá trình gửi tin nhắn

    Để cho tool có thể tự động gửi bạn có thể thêm điều kiện lắp mãi mãi kết hợp với các điều kiện khác như kiểm tra thêm thời gian cho việc gửi. Tùy vào nhu cầu của bạn.

    Và một điều quan trọng là nếu bạn làm điều đó thì không nên chạy nó trong Visual Studio vì sẽ rất tốn RAM và CPU. Nên Build nó ra file exe và chạy nhé.

    Ví dụ bạn muốn gửi tin nhắn đó hàng ngày thì mình có một trick lỏ như sau:

    public void DelayUntilNextDay()
    {
        DateTime now = DateTime.Now;
        DateTime nextRunTime = now.Date.AddDays(1).AddHours(8);
        TimeSpan timeToWait = nextRunTime - now;
    
        if (timeToWait.TotalMilliseconds < 0)
        {
            nextRunTime = nextRunTime.AddDays(1);
            timeToWait = nextRunTime - now;
        }
    
        Console.WriteLine($"Waiting for {timeToWait.TotalHours} hours until next execution...");
    
        Thread.Sleep(timeToWait);
    }

    Tạo một hàm lỏ để kiểm tra thời gian chạy sắp tới sau đó thêm vào tool

    while (true)
    {
        await zaloLib.SearchAndSelectUser(driver, "0967325687");
    
        await zaloLib.SendMessage(driver, "Hello! I am ProG Coder");
    
        DelayUntilNextDay();
    }

    Lưu ý quan trọng

    Các bạn cần kiểm tra xem ChromeDriver và Google Chrome có đúng version với nhau không nhé.

    Kết luận

    Với công cụ này, bạn có thể tự động gửi tin nhắn trên Zalo một cách dễ dàng. Nó có thể giúp bạn tiết kiệm thời gian khi cần gửi tin nhắn cho nhiều người, nhưng cũng cần lưu ý sử dụng công cụ này một cách hợp lý để tránh việc tài khoản bị khóa hoặc bị xem là spam.

    Hy vọng bài viết này sẽ giúp ích cho bạn trong việc phát triển các ứng dụng tự động hóa Zalo bằng C# và Selenium.


    Tiểu sử
    Are you one or zero?


    Bình luận