使用Selenium实现直播平台的自动刷屏

本文项目Github地址:https://github.com/zhouhuanghua/auto-flood-screen

最近,电竞圈LOL届最大的瓜非"蓝公主"莫属。本来,我也只是一名吃瓜群众,感觉都无所谓。但是,后面Baolan的亲妈粉闪现开团:嘲讽皇族官宣香锅退役是蹭热度,抢走了宝蓝生日的风头。这就不能忍了,作为RNG的忠实铁粉,而且还是香锅退役这么隆重的事情。怎么办呢?只能去最多人可以看到的网络直播平台刷"蓝公主"来过瘾一下了。不过,手动去刷的话太慢了没啥效果,作为一名码农,时刻要想到利用程序去处理问题。废话不多说哈,开始搞事情了。

这里以某牙为例,其它的大家可以举一反三。发弹幕最大的问题就是账号登录问题,网站设计者想尽一切办法来阻止机器人行为。但是,道高一尺,魔高一丈,现在连滑动解锁的方式都已经有了解决方案。不过,Huya还没那么复杂,相对来说算比较简单的了。

这里示范了两种实现方式:第一种,自动登录-->用户直接执行程序自动打开浏览器并进入指定的直播间,然后根据配置的账号密码或者手机号实现自动登录,最后开始刷指定的弹幕;第二种,手动登录-->用户首先执行一条cmd命令(或者封装成一段程序)打开浏览器,然后自己手动打开一个直播间登录,最后执行一段程序开始刷指定的弹幕。

老规矩,上镇楼图

首先,有必要给大家介绍一点前置知识。

1、什么是Selenium?

Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

这是摘自百度百科的说法,一句话来说就是:通过写代码让程序像人一样去操作浏览器。它依赖具体的浏览器驱动。

2、怎么去定位元素?

Selenium提供了很多方式去定位一个元素,就跟JQuery一样,什么根据id呀class呀tag呀应有尽有,还有css选择器。不过,我最喜欢用的是xpath,为啥呢,因为简单,有手就行。下面来示范一下

首先打开你的Chrome浏览器,进入一个网页,选中指定元素右击,然后点击检查。或者按F12像下面这样操作

这样子之后就会定位到对应得HTML。接着,鼠标放到这一行上面,右击后选择Copy。最后在显示出来的界面点击最后一个Copy XPath,就复制了对应的值了。小伙伴们学会了吗?代码里面都是基于这种方式。

3、驱动和jar包去哪里下载?

驱动:http://npm.taobao.org/mirrors/chromedriver/,下载跟你浏览器一样或者接近的版本。

jar包:http://npm.taobao.org/mirrors/selenium/,我喜欢最新的。

然后,就开始进入今天的主题了。

一、自动登录

talk is cheap,show me the code。

1、(完整代码)自动打开浏览器,进入到指定网页,根据账号密码自动登录。

/**
 * 自动登录刷弹幕
 *
 * @author z_hh
 */
public class Auto {

	public static void main(String[] args) throws Throwable {
		// 设置驱动位置
		System.setProperty("webdriver.chrome.driver", "./driver/chromedriver.exe");

		// 创建一个驱动对象
		WebDriver driver = new ChromeDriver();

		// 打开指定网页
		String url = "https://www.huya.com/17859972";
		driver.navigate().to(url);

		// 智能等待一下子
		driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);

		// 窗口最大化
		driver.manage().window().maximize();

		// 等待,直到登录元素可以点击
		WebElement loginElement = driver.findElement(By.xpath(".//*[@id=\"nav-login\"]"));
		WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
		wait.until(ExpectedConditions.elementToBeClickable(loginElement));

		//点击登录
		loginElement.click();

		driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
		
		// 切换到登录框里面
		driver.switchTo().frame("UDBSdkLgn_iframe");
		
		// 账号登录
		accountLogin(driver);
		
		// 手机验证码登录
//		mobileLogin(driver);

		// 发弹幕
		Utils.send(driver);
	}
	
	private static void accountLogin(WebDriver driver) {
		// 输入账号
		driver.findElement(By.xpath(".//*[@id=\"account-login-form\"]/div[1]/input")).sendKeys("13800138000");
		// 输入密码
		driver.findElement(By.xpath(".//*[@id=\"account-login-form\"]/div[2]/input")).sendKeys("xx00");
		// 登录
		driver.findElement(By.xpath(".//*[@id=\"login-btn\"]")).click();					
	}
	
	private static void mobileLogin(WebDriver driver) {
		// 切换到手机验证码登录
        driver.findElement(By.xpath(".//*[@id=\"login-head-nav\"]/ul/li[2]")).click();

        // 输入手机号
        driver.findElement(By.xpath(".//*[@id=\"phone-login-form\"]/div[1]/input")).sendKeys("13800138000");
        
        // 发送验证码
        driver.findElement(By.xpath(".//*[@id=\"phone-login-form\"]/div[2]/span")).click();
        
        // 获取验证码输入框的值,直到够了6位数
        for (;;) {
        	String text = driver.findElement(By.xpath(".//*[@id=\"phone-login-form\"]/div[2]/input")).getAttribute("value") ; 
        	if (Objects.nonNull(text) && Objects.equals(text.length(), 6)) {
				break;
			}
		}

        // 点击登录
        driver.findElement(By.xpath(".//*[@id=\"phone-login-btn\"]")).click();
	}
}

2、(完整代码)定时循环发送弹幕。

/**
 * 通用工具类
 *
 * @author z_hh
 */
public class Utils {

    /**
     * 无限循环发送弹幕
     * 
     * @param driver 驱动
     */
    public static void send(WebDriver driver) {
        // 弹幕内容
        String msg = "蓝公主";
        // 输入框元素
        WebElement inputElement = driver.findElement(By.xpath(".//*[@id=\"pub_msg_input\"]"));
        // 发送按钮元素
        WebElement sendElement = driver.findElement(By.xpath(".//*[@id=\"msg_send_bt\"]"));
        for (int i = 1; ; i++) {
            try {
                // 找到输入框并写入内容(为了不重复,后面拼上次数)
                inputElement.sendKeys(msg + i);

                // 点击发送
                sendElement.click();

                // 等待10秒钟,并清空输入框
                TimeUnit.SECONDS.sleep(10);
                inputElement.clear();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

简单补充说明一下

1)驱动的位置,我放在项目的一个文件夹里面,代码写的是相对路径。

2)切换到登录框。这个很关键,要不然定位不到填写账号密码的元素。

3)这里两种登录方式选其一即可。手机验证码登录需要手动配合输入验证码,这里只是为了提供多一种选择以备不时之需。

二、手动登录

既然有了自动登录,为啥还要手动登录呢?有三点原因:(1)自由度比较高;(2)以备不时之需;(3)最重要,分享一个重要的知识点。

打起精神来,这个知识点就是:

有时候我们需要手动打开浏览器,进入到所需的页面,执行一些手动任务,如输入表单、输入验证码,登录成功后,才开始运行自动化脚本。这种情况下如何使用Selenium来接管先前已经打开的浏览器呢?

其实就是,使用Selenium控制已打开的浏览器。针对谷歌浏览器,我们可以利用Chrome DevTools协议:它允许客户检查和调试Chrome浏览器。

怎么使用呢?

1、将Chrome程序添加到计算机的环境变量Path里面。

如图,桌面选中Google Chrome,右击,打开文件所在的位置。

2、在cmd命令窗口输入chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\AutomationProfile"之后回车,在浏览器自动打开之后,手动进入到指定的直播间并进行登录。

  • remote-debugging-port:可以指定任何打开的端口。
  • user-data-dir:指定创建新Chrome配置文件的目录。它是为了确保在单独的配置文件中启动chrome,不会污染你的默认配置文件。

作为一名程序员,这个操作你也可以用代码完成。

/**
 * Debug模式打开浏览器
 *
 * @author z_hh
 */
public class OpenChrome {

    public static void main(String[] args) {
        try{
            Runtime.getRuntime().exec("chrome.exe --remote-debugging-port=9527 --user-data-dir=\"C:/selenum/AutomationProfile\"");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

3、(完整代码)创建一个控制已打开浏览器的WebDriver对象。

之后,就可以去刷弹幕了(同第一种方式)。

/**
 * 刷屏
 *
 * @author
 */
public class Flood {

	public static void main(String[] args) throws Throwable {
        // 设置驱动位置
        System.setProperty("webdriver.chrome.driver", "./driver/chromedriver.exe");

        // 配置选项(端口跟打开浏览器时设置的要一样)。还有其它的,此处不做介绍
        ChromeOptions options = new ChromeOptions();
        options.setExperimentalOption("debuggerAddress", "127.0.0.1:9527");


        // 创建一个驱动对象
        WebDriver driver = new ChromeDriver(options);

        System.out.println(driver.getTitle());

        Utils.send(driver);
    }
}

主体部分讲解完了。最后,送给大家一点补习资料。

三、(完整代码)附上Selenium的一些其它操作

这段代码网上找来的,我写的没这么烂~~~

public class Demo {
	public static void main(String[] args) {

        System.setProperty("webdriver.chrome.driver", "D:/eclipse_workspace/automation/driver/chromedriver.exe");// chromedriver服务地址
        WebDriver driver = new ChromeDriver(); // 新建一个WebDriver 的对象,但是new 的是谷歌的驱动
        String url = "http://www.baidu.com";
        driver.get(url); // 打开指定的网站
        
        //driver.navigate().to(url); // 打开指定的网站        
        
        /*
         * 
         * driver.findElement(By.id("kw")).sendKeys(new String[] { "hello" });//
         * 找到kw元素的id,然后输入hello driver.findElement(By.id("su")).click(); // 点击按扭
         */
        try {
            /**
             * WebDriver自带了一个智能等待的方法。 dr.manage().timeouts().implicitlyWait(arg0, arg1);
             * Arg0:等待的时间长度,int 类型 ; Arg1:等待时间的单位 TimeUnit.SECONDS 一般用秒作为单位。
             */
            driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //获取当前浏览器的信息
        System.out.println("Title:" + driver.getTitle());
        System.out.println("currentUrl:" + driver.getCurrentUrl());

        //执行js脚本
        String jString = "alert('122')";
        ((JavascriptExecutor) driver).executeScript(jString);

        //获取单个元素
        WebElement element = driver.findElement(By.id("wrapper"));
        System.out.println(element.getAttribute("class"));

        //获取多个元素
        List<WebElement> elList = driver.findElements(By.tagName("input"));
        for (WebElement e : elList) {
            System.out.println("获取多个元素:"+e.getAttribute("name"));
        }
        
        //定位层级元素
        WebElement e = driver.findElement(By.cssSelector("#qrcode-item qrcode-item-1"));
        List<WebElement> list = e.findElements(By.tagName("div"));
        for (WebElement e1 : list) {
            System.out.println("定位层级元素:"+e1.getAttribute("class"));
        }
        
        
        
        //获取当前的窗口
        String currentWindow = driver.getWindowHandle();
        
        //获取所有的窗口
        Set<String>  handles = driver.getWindowHandles();
        
        //遍历窗口
        Iterator<String> iterator = handles.iterator();
        while (iterator.hasNext()) {
            if (currentWindow == iterator.next())
                continue;
            //跳转到弹出的窗口
            WebDriver driver2 = driver.switchTo().window(iterator.next());
            driver2.getTitle();
            
        }
        
        
        //处理弹出框
        Alert alert = driver.switchTo().alert();
        alert.getText();
        alert.dismiss();//相当于点击取消
        
        
        Alert confirm = driver.switchTo().alert();
        confirm.getText();
        confirm.accept();//相当于点击确认
        
        
        Alert prompt = driver.switchTo().alert();
        prompt.getText();
        prompt.accept();
        prompt.sendKeys("测试1");//输入值
        
        //处理下拉列表
        Select select = new Select(driver.findElement(By.id("select")));
        select.selectByIndex(1);
        select.selectByValue("西安");
        select.selectByVisibleText("咸阳");
        //获取下拉框的全部选项
        List<WebElement> list2 = select.getOptions();
        for (WebElement webElement : list2) {
            webElement.click();//点击下拉框
        }
        
        //处理cookie
        //添加一个cookie
        Cookie cookie = new Cookie("COOKIE", "NAME","D://COOKIES");
        driver.manage().addCookie(cookie);
        
        //获取cookies
        Set<Cookie> set = driver.manage().getCookies();
        Iterator<Cookie> iterator2 = set.iterator();
        while (iterator2.hasNext()) {
            Cookie c = iterator2.next();
            c.getName();
            c.getValue();
            c.getPath();
            
        }
        
        driver.manage().deleteAllCookies();
        driver.manage().deleteCookie(cookie);
        driver.manage().deleteCookieNamed("COOKIE");
        
        
        //等待加载完页面
        try {
            driver.manage().timeouts().wait(1);
            driver.manage().timeouts().implicitlyWait(1,TimeUnit.SECONDS);//等待界面加载完
        } catch (InterruptedException e2) {
        
            e2.printStackTrace();
        }
        
        //模拟鼠标和键盘操作
        Actions action = new Actions(driver); 
        action.click();
        action.dragAndDrop(element, e);
        action.sendKeys(element,"12222").perform();
        action.click(element);
        action.keyDown(currentWindow);
        
        
    
        
        // driver.quit();// 退出浏览器

        /**
         * dr.quit()和dr.close()都可以退出浏览器,简单的说一下两者的区别:第一个close,
         * 如果打开了多个页面是关不干净的,它只关闭当前的一个页面。第二个quit,
         * 是退出了所有Webdriver所有的窗口,退的非常干净,所以推荐使用quit最为一个case退出的方法。
         */

    }
}

四、结语

看到香锅被说蹭热度之后气不打一处来,于是写了这段代码。不过,文明社会,人人有责,我们要做一个高尚的喷子,弹幕只发"蓝公主"就好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值