阅读 393

掘金大大们,抽奖发中秋礼盒,我想抽奖碰碰运气!

我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛

没有做梦

事情的开头是这样的,睡觉到凌晨可能被热醒了,作者习惯性的打开掘金APP,日常惯例,签到然后免费抽奖1次;
作者已经在掘金累积签到61次,连续打卡58次了,但是今天看见转盘的奖品不对啊,几个大奖都换成了中秋礼盒,
而且还不用解锁哦;这下作者懵了,掘金还能这么干。作者除去已消费的2w+钻,还有4.8+w钻呢,能不能抽中呢,
想想还有点小激动呢!
复制代码

要干大事

梦该醒了,怎么说作者也有4.8+w钻,就算是用手点,粗略算过200钻/次,都需要点200+次,OMG,手指都得断了,放弃吗?
但是中秋礼盒好诱人啊;突然想起了之前活动,各位掘友写过各种抽奖的文章,但是我想来点不一样的,我就静静的守着电脑,
它能够自动的抽奖,享受这个过程,尽管...咳咳...抽不中,那也无所谓了,希望掘金大大们高抬贵手,给个月饼盒子?
复制代码

准备工作

想法需要付诸行动,才能得到结果,不能空想!

环境部署(略)
这次作者使用java+selenium来实现这个有点刺激的自动化脚本;安装过程略了,它太基础了,不好意思拿出来凑字数^-^。
复制代码
脚本设计

本来想直接写成线性脚本,毕竟是一次性的嘛,不想花太多时间;不过最近在回顾java+selenium设计UI自动化测试框架;顺带来练练手,帮助自己提升和巩固记忆;所以采用PageFactory设计模式;为什么不用PO呢?因为它只是测试设计模式,它没有在任何工具和框架中有交互,纯粹的是selenium对业务的二次封装。

在开始写脚本之前,先抛出两个问题:

  • 登录状态怎么解决,这一步要怎么绕过去?
  • 业务逻辑的处理,比如动态计算抽取次数?
编码思路
第一个问题有多种解决办法,因为登录需要滑块验证码,所以可以写复杂的java代码来计算出图片凹凸的位置进行拖动,这个太麻烦,果断抛弃;
第二种,就是手动登录,然后把cookies信息保存下来;这个听起来so cool,但实现却有点繁琐<对比python而言>;所以思路是:自动获取cookie保存自动读取cookie
复制代码

第一步:自动打开浏览器获取cookie并保存到txt文件中,

第二步:读取txt中的cookie信息,再添加到driver的cookie中去并刷新页面即可。

  • 代码实现:
public class IndexPage {

	// 初始化驱动对象
	private WebDriver driver;

	// 初始化页面元素
	public IndexPage(WebDriver driver) {
		this.driver = driver;
		PageFactory.initElements(driver, this);
		// PageFactory.initElements(new AjaxElementLocatorFactory(driver,
		// TIMEOUT), this);
	}

	@FindBy(css = ".first-line>button")
	@CacheLookup
	// 缓存
	WebElement signIn;

	@FindBy(xpath = "//div[@id='juejin']//div[contains(text(),'幸运抽奖')]")
	@CacheLookup
	List<WebElement> luckyLottery;

	@FindBy(xpath = "//div[contains(text(),'次')]")
	@CacheLookup
	WebElement cost;

	@FindBy(css = "span.value")
	@CacheLookup
	WebElement value;

	@FindBy(xpath = "//button[text()='去看看']")
	@CacheLookup
	WebElement toSee;

	@FindBy(xpath = "//button[text()='跳过']")
	@CacheLookup
	WebElement jumping;

	/**
	 * 打开浏览器,中间有cookie操作,然后在刷新页面
	 * 
	 * @throws Exception
	 */
	public void OpenBrowser() throws Exception {
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
		driver.get(Constants.JjinUrl);
		ReadCookieFromText();
		driver.navigate().refresh();
	}

	public void CloseBrowser() {
		if (driver != null) {
			driver.quit();
		}
	}

	/**
	 * 这一步比较复杂,就是需要判断是否有toast弹窗;然后在一步步的点击
	 */
	public void ClickSignIn() {
		if (toSee.isDisplayed()) {
			toSee.click();
			jumping.click();
			signIn.click();
		} else {
			signIn.click();
		}
	}

	/**
	 * 点击幸运抽奖,因为它有一个隐藏元素,所以是list返回,然后再判断点击显示的那个元素
	 */
	public void ClickLottery() {
		for (WebElement el : luckyLottery) {
			if (el.isDisplayed()) {
				el.click();
			}
		}
	}

	/**
	 * 需要判断,没有钻石则关闭浏览器
	 */
	public void ClickCostLottery() {
		if (CheckIsLottery()) {
			waitForClickable(cost);
			cost.click();
		} else {
			driver.quit();
			System.out.println("没有钻石抽奖了,关闭浏览器");
		}
	}

	/**
	 * 写一个通用的等待元素方法
	 * 
	 * @param element
	 * @throws Error
	 */
	private void waitForVisibility(WebElement element) throws Error {
		new WebDriverWait(driver, 30).until(ExpectedConditions
				.visibilityOf(element));
	}

	/**
	 * 可点击元素
	 * 
	 * @param element
	 * @throws Error
	 */
	private void waitForClickable(WebElement element) throws Error {
		new WebDriverWait(driver, 10).until(ExpectedConditions
				.elementToBeClickable(element));
	}

	/**
	 * 检查是否够钻石抽奖
	 * 
	 * @return
	 */
	public boolean CheckIsLottery() {
		waitForVisibility(value);
		int v = Integer.parseInt(value.getText());
		System.out.println(v);
		if (v < 200) {
			return false;
		}
		return true;
	}

	/**
	 * 这个方法用来手动登录获取cookies
	 * 
	 * @throws Exception
	 */
	public void WriteCookieToText() throws Exception {
		driver.get(Constants.JjinUrl);
		Thread.sleep(20000);
		Set<Cookie> cookies = driver.manage().getCookies();
		File cookieFile = new File("cookie.txt");
		cookieFile.delete();
		cookieFile.createNewFile();
		FileWriter fileWriter = new FileWriter(cookieFile);
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
		for (Cookie cookie : cookies) {
			bufferedWriter.write(cookie.getDomain() + ";" + cookie.getName()
					+ ";" + cookie.getValue() + ";" + cookie.getExpiry() + ";"
					+ cookie.getPath());
			bufferedWriter.newLine();
		}
		bufferedWriter.flush();
		bufferedWriter.close();
		fileWriter.close();
		driver.quit();
	}

	/**
	 * 用来读取txt中的cookie信息并加入driver
	 * 
	 * @throws Exception
	 */
	@SuppressWarnings({ "resource", "deprecation" })
	public void ReadCookieFromText() throws Exception {
		BufferedReader bufferedReader;
		File cookieFile = new File("cookie.txt");
		FileReader fileReader = new FileReader(cookieFile);
		bufferedReader = new BufferedReader(fileReader);
		String line;
		while ((line = bufferedReader.readLine()) != null) {
			StringTokenizer stringTokenizer = new StringTokenizer(line, ";");
			while (stringTokenizer.hasMoreTokens()) {
				String domain = stringTokenizer.nextToken();
				String name = stringTokenizer.nextToken();
				String value = stringTokenizer.nextToken();
				Date expiry = null;
				String dt;
				if (!(dt = stringTokenizer.nextToken()).equals("null")) {
					expiry = new Date(dt);
				}
				String path = stringTokenizer.nextToken();
				Cookie cookie = new Cookie(name, value, domain, path, expiry);
				driver.manage().addCookie(cookie);
			}
		}
	}

	/**
	 * 抽奖业务流:想抽取几次都可以在这里控制
	 * 
	 * @throws Exception
	 */
	public void Lottery() throws Exception {
		OpenBrowser();
		ClickSignIn();
		ClickLottery();
		ClickCostLottery();
		Thread.sleep(10000);
		CloseBrowser();
	}

	/**
	 * 程序执行入口,没有再去另起测试用例了
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		System.setProperty("webdriver.chrome.driver", Constants.driverUrl);
		WebDriver driver = new ChromeDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

		IndexPage index = new IndexPage(driver);
		index.Lottery();
	}
}
复制代码

总结

同志们需要注意了:在手动获取登录cookie信息时,写入的位置和读取的cookie位置一定要匹配,不要在写入时path在domain前面,读取时domain却在path前面,这样读出来的数据是错的,即addcookie中取都是错误的,更何况还有一个date类型的参数,所以所保存cookie信息的位置很重要。

  • 关于第二个问题,由于时间关系,没有引入testng测试框架去写用例了,而是在当前类中添加main方法简单实现;思路:可以获取钻石总数然后/200得到抽奖次数,先不管抽奖过程中获取66钻石,后面再去抽就是了<但是作者还是留了两个坑,需要各位同学去奇思妙想了>;
  • 关键的点:有一个小技术点,在由于操作速度过快,有些元素还没加载出来就操作了,执行可能会失败<没处理异常>,直接就pass过去关闭浏览器了<所以按条件加入了显示等待机制!>
  • 最后,希望中奖,中秋礼盒,预祝各位大佬高中!!!掘金大大们,发给礼盒吧!!!
文章分类
后端
文章标签