package com.ybjdw.tool.test;
import com.alibaba.fastjson.JSONObject;
import com.ybjdw.tool.utils.SeleniumUtil;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class AppiumTest {
private static Logger logger = LoggerFactory.getLogger(AppiumTest.class);
public static void main(String[] args) {
// 设置驱动相关信息
DesiredCapabilities des = new DesiredCapabilities();
des.setCapability("platformName", "Android");
des.setCapability("platformVersion", "7.1.2");
des.setCapability("deviceName", "Android Emulator");
des.setCapability("noReset", true);
des.setCapability("appPackage", "com.yishouapp.fumi");
des.setCapability("appActivity", "com.yishouapp.fumi.activity.YishouMainActivity");
AndroidDriver androidDriver = null;
try {
androidDriver = new AndroidDriver(new URL("http://192.168.1.186:4723/wd/hub"),des);
androidDriver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
yiShouLogin(androidDriver);
yiShouHotCategory(androidDriver);
} catch (Exception e) {
logger.error("appium异常,测试用例不通过!", e);
}finally{
if(androidDriver != null){
// 停掉app
androidDriver.terminateApp("com.yishouapp.fumi.activity.YishouMainActivity");
androidDriver.quit();
}
}
}
private static void yiShouHotCategory(AndroidDriver androidDriver) throws Exception {
logger.debug("首页开始上滑!");
int windowHeight = androidDriver.manage().window().getSize().getHeight();
SeleniumUtil.swipe(androidDriver, 10,new BigDecimal(windowHeight*0.8).intValue(), 10, new BigDecimal(windowHeight*0.05).intValue(), 3);
// 进入一手热销
logger.debug("开始进入一手热销!");
WebElement webElement = SeleniumUtil.findElementAndWait(androidDriver, By.id("com.yishouapp.fumi:id/rv_list_ihtm"), 3);
if(webElement == null){
return;
}
webElement = SeleniumUtil.findElementAndWait(webElement, By.xpath(".//androidx.recyclerview.widget.RecyclerView/android.widget.LinearLayout[4]"), 3);
if(webElement == null ){
return;
}
webElement = SeleniumUtil.findElementAndWait(webElement, By.xpath(".//android.widget.ImageView[1]"), 3);
if(webElement == null ){
return;
}
webElement.click();
Thread.sleep(5000);
// 判断是否存在富文本区域
WebElement varyContent = SeleniumUtil.findElementAndWait(androidDriver, By.id("com.yishouapp.fumi:id/vary_content"), 3);
if(varyContent == null ){
return;
}
// 点击销量降序排序
logger.debug("开始点击销量排序!");
webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[4]/android.view.View/android.view.View[2]/android.view.View[1]/android.view.View[2]"), 3);
if(webElement == null ){
return;
}
webElement.click();
// 打开筛选条件面板
logger.debug("开始打开条件筛选面板!");
webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[4]/android.view.View/android.view.View[2]/android.view.View[1]/android.view.View[4]"), 3);
if(webElement == null ){
return;
}
webElement.click();
Thread.sleep(3000);
// 选择筛选条件 7日爆款
logger.debug("开始选择筛选面板中的7日爆款!");
webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[4]/android.view.View[3]/android.view.View[3]/android.widget.CheckBox[3]/android.widget.TextView"), 3);
if(webElement == null ){
return;
}
webElement.click();
// 确定筛选条件
logger.debug("开始确定筛选条件!");
webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[4]/android.view.View[3]/android.view.View[5]"), 3);
if(webElement == null ){
return;
}
webElement.click();
Thread.sleep(1000);
logger.debug("开始上滑app!");
SeleniumUtil.swipe(androidDriver, 10, windowHeight /2, 10, 10, 3);
searchYiShouCategory(androidDriver);
}
private static void searchYiShouCategory(AndroidDriver androidDriver) throws InterruptedException {
// 搜索所有品类
int searchItemIndex = 0;
int searchCategoryIndex = 0;
int lastCategoryY = 0;
List searchCategoryNameList = new ArrayList<>();
for(int i=0; i < 10; i++){
WebElement varyContent = SeleniumUtil.findElementAndWait(androidDriver, By.id("com.yishouapp.fumi:id/vary_content"), 2);
String searchCategory1 = ".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[3]/android.view.View/android.view.View[1]/android.view.View/android.widget.TabWidget/android.view.View";
String searchCategory2 = ".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[2]/android.view.View/android.view.View[1]/android.view.View/android.widget.TabWidget/android.view.View";
List categoryElements = SeleniumUtil.findElementList(varyContent, By.xpath(searchCategory1), 2);
if(categoryElements == null || categoryElements.size() ==0){
categoryElements = SeleniumUtil.findElementList(varyContent, By.xpath(searchCategory2), 2);
}
if(categoryElements == null || categoryElements.size() == 0){
continue;
}
// 第一个品类是精选,跳过,从第二个开始
for(int subCategoryIndex=2; subCategoryIndex < categoryElements.size() && subCategoryIndex < 5; subCategoryIndex++){
Point startPoint = new Point(3,0);
Point endPoint = new Point(3,0);
Point categoryFirstLocation = null; // 品类第一个元素的位置,用于纠正位置偏差
// 搜索品类目录
String categoryPath = searchCategory1 + "[" + subCategoryIndex + "]";
WebElement webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(categoryPath),2);
if(webElement == null){
categoryPath = searchCategory2 + "[" + subCategoryIndex + "]";
webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(categoryPath),2);
}
if(webElement == null || StringUtils.isBlank(webElement.getText())){
continue;
}
String categoryName = webElement.getText();
if(searchCategoryNameList.contains(categoryName)){
continue;
}
searchCategoryNameList.add(categoryName);
Point location = webElement.getLocation();
Dimension size = webElement.getSize();
lastCategoryY = location.getY() + 5;
webElement.click();
Thread.sleep(2000);
logger.debug("搜索品类顺序:{},定位到第{}个子品类:{},location:{},size:{}", searchCategoryIndex, subCategoryIndex, categoryName, location, size);
// 不断上滑app界面,每次获取完整展示的2个商品(1/2或3/4)
JSONObject productJson;
int categoryProductIndex = 0;
List productList = new ArrayList<>();
for(int pageSwipeNum = 0; pageSwipeNum < 25; pageSwipeNum++){
logger.trace("搜索品类顺序:{},子品类:{}商品页面第{}次上滑!", searchCategoryIndex, categoryName, pageSwipeNum);
if(pageSwipeNum == 0){ // 第一行2个商品
for(int productIndex=0; productIndex < 2; productIndex++){
String productXPath = ".//android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View/android.view.View[3]/android.view.View/android.view.View[2]/android.view.View[2]/android.view.View["+(productIndex+1)+"]";
webElement = SeleniumUtil.findElementAndWait(varyContent, By.xpath(productXPath), 2);
if(webElement != null){
if(categoryFirstLocation == null){
categoryFirstLocation = webElement.getLocation();
}
productJson = parseYiShouProductSmart(categoryName, webElement);
if(productJson != null){
productJson.put("categoryProductIndex", ++categoryProductIndex);
productList.add(productJson);
logger.debug("搜索品类顺序:{},品类:{},定位到第{}个商品:{},", searchCategoryIndex, categoryName, ++searchItemIndex, productJson);
}
// 重置移动轨迹
resetMovePoint(startPoint, endPoint, categoryFirstLocation, webElement);
}
}
// 搜索完品类前2个商品后下滑
SeleniumUtil.swipe(androidDriver, startPoint.getX(), startPoint.getY(), endPoint.getX(), endPoint.getY(), 2);
Thread.sleep(3000);
continue;
}
String productTotalViewPath = "//android.view.View[@resource-id="app"]/android.view.View/android.view.View[2]/android.view.View/android.view.View[2]/android.view.View/android.view.View";
if(searchCategoryIndex >= 2){
productTotalViewPath = "//android.view.View[@resource-id="app"]/android.view.View/android.view.View[2]/android.view.View/android.view.View[2]/android.view.View[2]/android.view.View";
}
logger.debug("品类:{}搜索商品列表定位路径:{}", categoryName, productTotalViewPath);
List elementList = SeleniumUtil.findElementList(androidDriver, By.xpath(productTotalViewPath), 2);
if(elementList == null){
break;
}
logger.debug("商品列表 elementList.size():{}", elementList.size());
if(elementList.size() >= 4){
// 第3个商品
webElement = elementList.get(2);
JSONObject thirdEleJson = parseYiShouProductSmart(categoryName, webElement);
if(thirdEleJson != null){
logger.debug("搜索品类顺序:{},品类:{},定位到第{}个商品:{},第3个元素", searchCategoryIndex, categoryName, ++searchItemIndex, thirdEleJson);
thirdEleJson.put("categoryProductIndex", ++categoryProductIndex);
productList.add(thirdEleJson);
// 重置移动轨迹
resetMovePoint(startPoint, endPoint, categoryFirstLocation, webElement);
}
// 第4个商品
webElement = elementList.get(3);
productJson = parseYiShouProductSmart(categoryName, webElement);
if(productJson != null){
logger.debug("搜索品类顺序:{},品类:{},定位到第{}个商品:{},第4个元素", searchCategoryIndex, categoryName, ++searchItemIndex, productJson);
productJson.put("categoryProductIndex", ++categoryProductIndex);
productList.add(productJson);
}
// 获取最后一个view的文字 没有更多了
webElement = elementList.get(elementList.size() - 1);
String text = webElement.getText();
if(text.contains("没有更多了")){
logger.debug("发现没有更多了,停止品类搜索!");
break;
}
}
// 搜索完品类商品后下滑
SeleniumUtil.swipe(androidDriver, startPoint.getX(), startPoint.getY(), endPoint.getX(), endPoint.getY(), 2);
Thread.sleep(3000);
}
logger.debug("第{}轮品类:{}遍历结束,已搜索品类:{},已搜索商品数量:{}", searchCategoryIndex, categoryName, searchCategoryNameList, productList.size());
searchCategoryIndex++;
}
// 每次搜索页面展示品类的第2 3 4,再左滑半个屏幕,注意品类展示会随着点击移动
int windowWidth = androidDriver.manage().window().getSize().getWidth();
logger.debug("开始第{}次左滑,屏幕宽带:{},品类顺序:{}!", i+1, windowWidth,searchCategoryIndex);
SeleniumUtil.swipe(androidDriver, windowWidth/2, lastCategoryY,5,lastCategoryY, 2);
Thread.sleep(3000);
}
logger.debug("搜索结束,遍历的品类集合:{}!", searchCategoryNameList);
}
private static void resetMovePoint(Point startPoint, Point endPoint, Point categoryFirstLocation, WebElement webElement) {
try{
logger.trace("重新定义上滑位置!");
if(webElement == null){
return;
}
startPoint.y = webElement.getLocation().getY() + webElement.getSize().getHeight();
endPoint.y = webElement.getLocation().getY() + 5;
if(categoryFirstLocation != null){
endPoint.y = categoryFirstLocation.getY() + 5;
}
}catch (Exception e){
logger.error("重置上滑位置异常!", e);
}
}
public static JSONObject parseYiShouProductSmart(String categoryName, WebElement productEle) {
JSONObject retJson = new JSONObject();
try {
if(productEle == null){
return null;
}
String saleText = "0";
String priceText = "0";
String productName = "未找到名称";
WebElement webElement = null;
// 商品名(长度超过10)、销量(含已拼)
List webElementList = SeleniumUtil.findElementList(productEle, By.xpath(".//android.widget.TextView"), 3);
if (webElementList == null || webElementList.size() == 0) {
logger.warn("未定位到商品名称和销量");
// while(true){
// Scanner scanner = new Scanner(System.in);
// logger.debug("请在下一行输入定位路径!");
// if(scanner.hasNext()){
// String input = scanner.next();
// if("q".equals(input)){
// break;
// }
// webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(input), 3);
// if(webElement != null){
// logger.debug("文本内容:{}", webElement.getText());
// }else{
// logger.debug("未找到!");
// }
// }
// }
return null;
}else{
for(WebElement textView:webElementList){
String viewText = textView.getText();
if(viewText.contains("已拼")){ // 销量
saleText = viewText;
saleText = saleText.replace("已拼", "").replace("今日","");
break;
}
if(viewText.length() > 10 && "未找到名称".equals(productName)){ // 商品名
productName = viewText;
}
logger.trace("商品名称:{}",productName);
}
}
// 价格(含¥ ¥)
webElementList = SeleniumUtil.findElementList(productEle, By.xpath(".//android.view.View"), 3);
if (webElementList == null || webElementList.size() == 0) {
logger.warn("未定位到商品价格");
return null;
}else{
for(WebElement textView:webElementList){
String viewText = textView.getText();
if(viewText.contains("¥") || viewText.contains("¥")){ // 商品价格
priceText = viewText;
priceText = priceText.replace("¥", "").replace("¥", "");
logger.trace("商品价格:{}", priceText);
break;
}
}
}
List elementList = SeleniumUtil.findElementList(productEle, By.xpath(".//android.widget.Image"), 2);
if(elementList!= null && elementList.size() >0){
for(WebElement subEle:elementList){
if(subEle.getSize().getHeight() > 100){
webElement = subEle;
logger.trace("找到图片元素{}", subEle.getSize());
break;
}
}
}
if(webElement == null){
logger.debug("未找到图片元素,使用这个商品元素!");
webElement = productEle;
}
File screenShotFile = webElement.getScreenshotAs(OutputType.FILE);
String picPath = "E:\tmp\yishou\" + productName + ".jpg";
FileUtils.copyFile(screenShotFile, new File(picPath));
logger.trace("品类:{},名称:{},价格:{},销量:{},图片路径:{}", categoryName, productName, priceText, saleText, picPath);
retJson.put("categoryName", categoryName);
retJson.put("productName", productName);
retJson.put("priceText", priceText);
retJson.put("saleText", saleText);
retJson.put("picPath", picPath);
}catch (Exception e){
logger.error("解析商品异常!", e);
}
return retJson;
}
private static void parseYiShouProduct(String categoryName, WebElement productEle) {
try {
String saleText = "";
String priceText = "";
WebElement webElement;
// 商品名 长度超过10
webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(".//android.widget.TextView[2]"), 3);
if (webElement == null) {
logger.warn("未定位到商品名称");
return;
}
String productName = webElement.getText();
logger.debug("开始解析商品:{}", webElement.getText());
// 价格 销量
webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(".//android.view.View[5]/android.view.View"), 3);
if (webElement != null) {
priceText = webElement.getText();
}
webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(".//android.view.View[5]/android.widget.TextView"), 3);
if (webElement != null) {
saleText = webElement.getText();
}
if (StringUtils.isBlank(priceText) || StringUtils.isBlank(saleText)) {
webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(".//android.view.View[4]/android.view.View"), 3);
if (webElement != null) {
priceText = webElement.getText();
}
webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(".//android.view.View[4]/android.widget.TextView"), 3);
if (webElement != null) {
saleText = webElement.getText();
}
}
// 下载图片
webElement = SeleniumUtil.findElementAndWait(productEle, By.xpath(".//android.view.View[1]/android.widget.Image"), 3);
if (webElement == null) {
logger.warn("未定位到商品图片");
return;
}
File screenShotFile = webElement.getScreenshotAs(OutputType.FILE);
String picName = "E:\tmp\yishou\" + productName + ".jpg";
FileUtils.copyFile(screenShotFile, new File(picName));
logger.debug("品类:{},名称:{},价格:{},销量:{},图片路径:{}", categoryName, productName, priceText, saleText, picName);
}catch (Exception e){
logger.error("解析商品异常!", e);
}
}
public static void yiShouLogin(AppiumDriver driver) throws Exception {
logger.debug("appium开始进行一手登录检测!");
// 允许app拨打电话
WebElement webElement = SeleniumUtil.findElementAndWait(driver, By.id("com.android.packageinstaller:id/permission_allow_button"), 1);
if(webElement != null) {
webElement.click();
}
// 切换到密码登录界面
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.yishouapp.fumi:id/tv_phonelogin_pwdlogin"),1);
if(webElement != null) {
logger.debug("一手未登录,开始切换到密码登录!");
webElement.click();
Thread.sleep(2000);
// 输入手机号
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.yishouapp.fumi:id/et_phonepwdlogin_phone"),1);
if(webElement != null){
webElement.sendKeys("15910761260");
Thread.sleep(500);
}
// 输入密码
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.yishouapp.fumi:id/et_phonepwdlogin_pwd"),1);
if(webElement != null){
webElement.sendKeys("a123456");
Thread.sleep(500);
}
// 同意隐私政策
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.yishouapp.fumi:id/cb_user_privacy"),1);
if(webElement != null){
webElement.click();
}
// 点击登录
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.yishouapp.fumi:id/btn_phonepwdlogin_confirm"),1);
if(webElement != null){
webElement.click();
Thread.sleep(2000);
}
}else{
logger.debug("一手已登录!");
}
// 允许app访问照片等媒体文件
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.android.packageinstaller:id/permission_allow_button"),1);
if(webElement != null){
webElement.click();
Thread.sleep(500);
}
// 新版本提示
logger.debug("开始搜索是否有新版本提示!");
webElement = SeleniumUtil.findElementAndWait(driver, By.id("com.yishouapp.fumi:id/common_multiple_layout_buttons"), 1);
if(webElement != null) {
webElement = SeleniumUtil.findElementAndWait(webElement, By.xpath(".//android.widget.TextView[1]"), 1);
if(webElement != null){
logger.debug("开始关闭新版本提示!");
webElement.click();
Thread.sleep(500);
}
}
// 关闭推荐
webElement = SeleniumUtil.findElementAndWait(driver,By.id("com.yishouapp.fumi:id/rl_close_container"),1);
if(webElement != null){
webElement.click();
Thread.sleep(500);
}
logger.debug("appium一手登录检测完成!");
}
public static void qqLiteTest(String[] args) {
//打包DesiredCapabilities这个类
DesiredCapabilities des = new DesiredCapabilities();
des.setCapability("platformName", "Android");
des.setCapability("platformVersion", "7.1.2");
des.setCapability("deviceName", "Android Emulator");
des.setCapability("noReset", true);
//获取包名及第一个页面的activity
des.setCapability("appPackage", "com.tencent.qqlite");
des.setCapability("appActivity", "com.tencent.mobileqq.activity.SplashActivity");
//创建AppiumDriver对象,连接上Appium服务器,并将相应的键值对传过去
AppiumDriver driver = null;
try {
driver = new AppiumDriver(new URL("http://192.168.1.186:4723/wd/hub"),des);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
// 步骤1:在登录页面用户名文本框中输入qq号码
driver.findElementByAccessibilityId("请输入QQ号码或手机或邮箱").clear();
driver.findElementByAccessibilityId("请输入QQ号码或手机或邮箱").sendKeys("xxxx");
Thread.sleep(1000);
// 步骤2:在登录页面密码文本框中输入密码
driver.findElementById("com.tencent.qqlite:id/password_eye").click(); // 显示密码
driver.findElementById("com.tencent.qqlite:id/password").click();
driver.findElementById("com.tencent.qqlite:id/password").clear();
driver.findElementById("com.tencent.qqlite:id/password").sendKeys("xxxx");
Thread.sleep(1000);
// 步骤3:点击登录按钮
driver.findElementByAccessibilityId("登录QQ").click();
// 滑动验证码的图标到相应的位置
//driver.swipe(169, 334, 347, 344, 3000);
Thread.sleep(10*1000);
Thread.sleep(30*1000);
} catch (Exception e) {
logger.error("appiium异常,测试用例不通过!", e);
}finally{
if(driver != null){
driver.quit();
}
}
}
}