吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 989|回复: 7
收起左侧

[其他原创] c#和python通用,使用Selenium自动化测试库单点登录、自动修改密码等各种自动化操作

[复制链接]
52pjdana 发表于 2024-9-2 17:55
接上个帖子,之前使用的是油猴脚本tampermonkey+js代码,通过在浏览器安装插件执行js脚本的方式自动填充账号密码登录框,实现另类的单点登录。

后续实施起来比较麻烦,需要帮用户安装脚本文件,并且脚本更新比较麻烦,需要手动一个个替换js代码,另外油猴脚本插件存在浏览器不兼容或者被删除的可能。
于是便找到了Selenium这个库,通过学习和编写测试代码也比较完善的实现了这个功能,记录和分享一下代码和解决方案。

Selenium在Python和c#中均可直接引入并使用,由于我的业务是做来后台单点登录和一键修改密码的操作,所以通过后台API调用的方式来实现是最完美的,而.net程序
的打包和更新更方便,所以便从python更改成了c#程序

话不多说,上代码和实现步骤:
  • 使用vs或者Rider创建一个.net core解决方案(不需要写web api项目的话创建一个简单的桌面解决方案也行)
  • 引入Selenium库,大概就这些:
[C#] 纯文本查看 复制代码
using OpenQA.Selenium.Interactions;
using SSO.WEBAPI.Controllers;

namespace SSO.WEBAPI.Services;

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;

    3.使用这个库执行自动化测试。Selenium的大概功能就是可以控制打开浏览器服务窗口,然后这个浏览器窗口是完全由Selenium控制的,你可以通过代码来控制浏览器打开指定的web页面,然后获取页面上的所有元素,通过调试将需要的元素赋值、点击按钮、点击链接、前往新的页面、在新的页面继续控制各个元素的事件和值,很多网站很少会更新改这个代码,所以大概写好一次就能一直用了。我这边以登录修改密码为例:
[Asm] 纯文本查看 复制代码
try
        {
            // 配置ChromeDriver服务
            _service = ChromeDriverService.CreateDefaultService();
            // _service.HideCommandPromptWindow = true; // 隐藏命令行窗口

            // 启动Chrome浏览器
            _options = new ChromeOptions();
            _options.AddArgument("--start-maximized");
            _options.AddArgument("--headless"); // 无头模式

            // 启动ChromeDriver时传入service和options
            IWebDriver driver = new ChromeDriver(_service, _options, TimeSpan.FromSeconds(5));

            // 导航到GitLab登录页面
            driver.Navigate().GoToUrl(pwdRequest.Url);

            // 等待页面加载(可以使用显式等待,简化为线程休眠)
            Thread.Sleep(100);

            // 查找并填充用户名字段
            var usernameField = driver.FindElement(By.Id("user_login"));
            usernameField.SendKeys(pwdRequest.Username); // 替换为你的GitLab用户名

            // 查找并填充密码字段
            var passwordField = driver.FindElement(By.Id("user_password"));
            passwordField.SendKeys(pwdRequest.Password); // 替换为你的GitLab密码

            // 查找并点击登录按钮
            var loginButton = driver.FindElement(By.CssSelector("button[type='submit']"));
            loginButton.Click();

            // 等待登录过程完成(可以根据页面变化调整等待时间)
            // System.Threading.Thread.Sleep(1000);

            // 检查是否登录成功(可选,验证是否跳转到登录后的页面)
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(2));

            // 等待特定ID的元素出现
            var sidebarHeading = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("super-sidebar-heading")));

            //特定元素出现,前往新页面
            if (sidebarHeading.Displayed)
            {
                driver.Navigate().GoToUrl(pwdRequest.PwdUrl);
                Thread.Sleep(100);
                //找到元素并填充
                var oldPwd = driver.FindElement(By.Id("user_password"));
                oldPwd.SendKeys(pwdRequest.Password);
                var newPwd = driver.FindElement(By.Id("user_new_password"));
                newPwd.SendKeys(pwdRequest.NewPassword);
                var passPwd = driver.FindElement(By.Id("user_password_confirmation"));
                passPwd.SendKeys(pwdRequest.NewPassword);
                var saveButton = driver.FindElement(By.CssSelector("button[type='submit']"));
                saveButton.Click();
                return true;
            }

            return false;
        }
        catch (Exception e)
        {
            // Log.Error("An error occurred: " + e.Message);
            return false;
        }


代码看不清可以看图片附件,每一步都有注释分析的,查找页面的元素直接浏览器f12打开控制台找即可,演示图也在最后

另外调试获取页面元素的方式很多很多,通过id,class,name,甚至文本内容,这个如果有学前段的朋友应该挺了解的。
注意如果页面中有iframe标签的话,需要切换到iframe标签内才能获取iframe标签内的元素,我被这个坑了好久:
// 切换到 iframe
var iframeElement = driver.FindElement(By.ClassName("lui_widget_iframe"));
driver.SwitchTo().Frame(iframeElement);

gitlab代码1

gitlab代码1

gitlab代码2

gitlab代码2

调试

调试

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
wushaominkk + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 52pjdana 发表于 2024-9-2 17:59
如果需要调用源码的话我后续再整理分享一下
yanggo 发表于 2024-9-2 22:09
jellycici 发表于 2024-9-3 23:51
rsy1479 发表于 2024-9-6 08:07
学习中,希望自己越来越强大💪('ω'💪)!
tzq001 发表于 2024-9-6 10:00
求PYthon源码案例
 楼主| 52pjdana 发表于 2024-9-6 11:19
tzq001 发表于 2024-9-6 10:00
求PYthon源码案例

这是python的示例,用的djiango写的web案例
[Python] 纯文本查看 复制代码
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


# 初始化 WebDriver
def initialize_login_driver():
    chrome_options = Options()
    chrome_options.add_argument("--start-maximized")
    chrome_options.add_argument("--disable-extensions")
    chrome_options.add_argument("--disable-popup-blocking")
    chrome_options.add_argument("--disable-infobars")
    chrome_options.add_argument("--disable-notifications")
    chrome_options.add_experimental_option("useAutomationExtension", False)
    chrome_options.add_experimental_option("detach", True)  # 保持浏览器打开
    # chrome_options.add_argument("--headless")  # Uncomment if you want headless mode

    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
    return driver

def initialize_password_driver():
    chrome_options = Options()
    chrome_options.add_argument("--start-maximized")
    chrome_options.add_argument("--disable-extensions")
    chrome_options.add_argument("--disable-popup-blocking")
    chrome_options.add_argument("--disable-infobars")
    chrome_options.add_argument("--disable-notifications")
    chrome_options.add_experimental_option("useAutomationExtension", False)
    chrome_options.add_experimental_option("detach", True)  # 保持浏览器打开
    # chrome_options.add_argument("--headless")  # Uncomment if you want headless mode

    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
    return driver



def login_to_gitlab(driver, url, username, password):
    try:
        driver.get(url)
        wait = WebDriverWait(driver, 10)
        username_input = wait.until(EC.presence_of_element_located((By.ID, 'user_login')))
        password_input = wait.until(EC.presence_of_element_located((By.ID, 'user_password')))
        username_input.clear()
        username_input.send_keys(username)
        password_input.clear()
        password_input.send_keys(password)
        login_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[@type="submit"]')))
        login_button.click()
        wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'mobile-overlay')))
        return {"message": "Login successful"}
    except TimeoutException:
        return {"error": "Timeout waiting for elements"}
    except NoSuchElementException:
        return {"error": "Element not found"}
    except Exception as e:
        return {"error": str(e)}
    finally:
        return {"message": "Login successful"}
        # driver.quit()


@csrf_exempt
def login_view(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            login_type = data.get('type')
            url = data.get('url')
            username = data.get('username')
            password = data.get('password')

            if not url or not username or not password:
                return JsonResponse({"error": "Missing URL, username, or password"}, status=400)

            driver = initialize_login_driver()
            if login_type == "gitlab":
                result = login_to_gitlab(driver, url, username, password)
            return JsonResponse(result)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    else:
        return JsonResponse({"error": "Only POST method allowed"}, status=400)


@csrf_exempt
def reset_password(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            reset_type = data.get('type')
            login_url = data.get('url')
            update_password_url = data.get("password_url")
            username = data.get('username')
            password = data.get('password')
            new_password = data.get("new_password")

            if not login_url or not username or not password:
                return JsonResponse({"error": "Missing URL, username, or password"}, status=400)

            driver = initialize_password_driver()
            if reset_type == "gitlab":
                result = reset_to_gitlab(driver, login_url, username, password,update_password_url,new_password)

            return JsonResponse(result)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    else:
        return JsonResponse({"error": "Only POST method allowed"}, status=400)


def reset_to_gitlab(driver, url, username, password, update_url, new_pwd):
    try:
        print("Navigating to login page...")
        driver.get(url)
        wait = WebDriverWait(driver, 10)

        # 登录操作
        print("Looking for username input field...")
        username_input = wait.until(EC.presence_of_element_located((By.ID, 'user_login')))
        print("Found username input field.")
        print("Looking for password input field...")
        password_input = wait.until(EC.presence_of_element_located((By.ID, 'user_password')))
        print("Found password input field.")

        username_input.clear()
        username_input.send_keys(username)
        password_input.clear()
        password_input.send_keys(password)

        print("Looking for login button...")
        login_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[@type="submit"]')))
        print("Found login button, clicking...")
        login_button.click()

        print("Waiting for page to load after login...")
        wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'mobile-overlay')))
        print("Login successful, navigating to update password page...")

        # 跳转到修改密码页面
        driver.get(update_url)
        print(f"Navigated to {update_url}, waiting for password fields...")

        # 等待密码修改页面元素加载
        wait.until(EC.presence_of_element_located((By.ID, 'user_password')))
        print("Found old password field.")

        # 修改密码
        old_pwd_input = driver.find_element(By.ID, 'user_password')
        print("Found old password input field.")
        new_password_input = driver.find_element(By.ID, 'user_new_password')
        print("Found new password input field.")
        user_password_confirmation = driver.find_element(By.ID, 'user_password_confirmation')
        print("Found password confirmation input field.")

        old_pwd_input.clear()
        old_pwd_input.send_keys(password)
        new_password_input.clear()
        new_password_input.send_keys(new_pwd)
        user_password_confirmation.clear()
        user_password_confirmation.send_keys(new_pwd)

        print("Password updated successfully.")
        return {"message": "Password updated successfully"}

    except TimeoutException:
        print("Timeout waiting for elements")
        return {"error": "Timeout waiting for elements"}
    except NoSuchElementException:
        print("Element not found")
        return {"error": "Element not found"}
    except Exception as e:
        print(f"An error occurred: {str(e)}")
        return {"error": str(e)}
    # finally:
    #     driver.get(update_url)
        # driver.quit()
tzq001 发表于 2024-9-7 15:40
52pjdana 发表于 2024-9-6 11:19
这是python的示例,用的djiango写的web案例
[mw_shl_code=python,true]from django.http import JsonRes ...

十分感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-12 14:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表