钉钉中有公司所有人的联系信息,可以查看。但是钉钉为了保护个人隐私,钉钉支持持个人把手机通讯录同步到钉钉,但是不允许普通用户把钉钉通讯录同步到手。只有部分管理员有权限从后台导入或导出所有人的联系方式和邮箱。
根据可见及可得的基本思想写下了下面主要代码。
遍历钉钉中组织架构下所有人的联系方式并组合成一个字符串。
主要使用appium自动化测试。夜神模拟器做测试机。
本来使用python编码,但是发现没有java严谨。java编码更加方便,都拼写要求比较低。
为了能正常运行可能要安装adb
启动夜神模拟器 使用命令
adb devices
查找模拟器调试接口 程序中会用到-
启动appium 配置一个调试(可以直接写代码)能够正常连接 模拟器
{ "platformName": "Android", "platformVersion": "4.4.4", "deviceName": "emulator-5554", "appPackage": "com.alibaba.android.rimet", "appActivity": "com.alibaba.android.rimet.biz.SplashActivity", "remoteAdbHost": "localhost" }
-
连接成功后,使用java程序连接并开始写代码。
public class Main { private AndroidDriver driver; @Before public void setUp() throws MalformedURLException { DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); desiredCapabilities.setCapability("platformName", "Android"); desiredCapabilities.setCapability("platformVersion", "4.4.4"); desiredCapabilities.setCapability("deviceName", "emulator-5554"); desiredCapabilities.setCapability("appPackage", "com.alibaba.android.rimet"); desiredCapabilities.setCapability("appActivity", "com.alibaba.android.rimet.biz.SplashActivity"); desiredCapabilities.setCapability("remoteAdbHost", "localhost"); URL remoteUrl = new URL("http://localhost:4723/wd/hub"); driver = new AndroidDriver(remoteUrl, desiredCapabilities); } @Test public void sampleTest() { try { java.lang.Thread.sleep(3000); MobileElement el1 = (MobileElement) Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/login_slide_btn",0); el1.click(); MobileElement el2 = (MobileElement) Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/et_phone_input",0); el2.sendKeys("<账号>"); MobileElement el3 = (MobileElement) Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/et_pwd_login",0); el3.sendKeys("<密码>"); MobileElement el4 = (MobileElement) Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/btn_next",0); el4.click(); MobileElement el5 = (MobileElement) Utils.waitForElementById(driver,"android:id/button1",0); el5.click(); MobileElement el6 = (MobileElement) Utils.waitForElementByAccessibilityId(driver,"同意",0); el6.click(); MobileElement el7 = (MobileElement) Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/home_bottom_tab_button_contact",0); el7.click(); List<MobileElement> el8s = driver.findElementsById("com.alibaba.android.rimet:id/cell_title"); for(MobileElement element : el8s){ if ("组织架构".equals(element.getText())){ element.click(); AllPages.start(driver); break; } } } catch (InterruptedException e) { e.printStackTrace(); } } @After public void tearDown() { driver.quit(); } }
setUp() 连接模拟器指定应用,并启动。
sampTest() 登录并找到组织架构
tearDown() 停止
-
遍历组织架构
public class AllPages { static String AllUser = ""; static public void start(AndroidDriver driver){ String source = driver.getPageSource(); System.out.println(source); MobileElement list_view = Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/list_view",0); List<MobileElement> contents = list_view.findElementsById("com.alibaba.android.rimet:id/rl_content"); for(MobileElement element : contents){ MobileElement titleEle = element.findElementById("com.alibaba.android.rimet:id/tv_dept_name"); System.out.println(titleEle.getText()); scanFromElement(driver,titleEle); } } static public void scanFromElement(AndroidDriver driver,MobileElement rootElement){ try { rootElement.click(); java.lang.Thread.sleep(3000);//等待页面加载 String source = driver.getPageSource(); System.out.println(source); MobileElement list_view = Utils.waitForElementById(driver,"com.alibaba.android.rimet:id/list_view",0); List<MobileElement> items = list_view.findElementsById("com.alibaba.android.rimet:id/tv_contact_name"); for (MobileElement item : items) { System.out.println(item.getText()); getPersenalInfoWithElement(driver,item); } List<MobileElement> contents = list_view.findElementsById("com.alibaba.android.rimet:id/rl_content"); for(MobileElement element : contents){ try { MobileElement titleEle = element.findElementById("com.alibaba.android.rimet:id/tv_dept_name"); System.out.println(titleEle.getText()); scanFromElement(driver,titleEle); }catch (Exception e){ e.printStackTrace(); } } MobileElement up = (MobileElement) driver.findElementByXPath("//android.widget.HorizontalScrollView/android.widget.LinearLayout/android.widget.LinearLayout[last()-1]"); up.click(); java.lang.Thread.sleep(3000);//等待页面加载 }catch (Exception e) { e.printStackTrace(); } } static public void getPersenalInfoWithElement(AndroidDriver driver,MobileElement element){ try { String fileName = element.getText(); element.click(); java.lang.Thread.sleep(3000);//等待页面加载 String source = driver.getPageSource(); writeFile(fileName,source); System.out.println(source); getUserInfo(driver); MobileElement back =(MobileElement) driver.findElementByXPath("//android.widget.ImageButton[@content-desc=\"返回\"]"); back.click(); }catch (Exception e){ e.printStackTrace(); } } static public void writeFile(String fileName,String content){ try{ FileWriter writer = new FileWriter("/Users/cai/Desktop/appium/_333/files/"+fileName+".xml"); writer.write(content); writer.flush(); writer.close(); }catch (IOException e){ e.printStackTrace(); } } static public void getUserInfo(AndroidDriver driver){ try{ String userInfo = ""; List<MobileElement> keys1 = driver.findElementsById("com.alibaba.android.rimet:id/cell_title"); List<MobileElement> values1 = driver.findElementsById("com.alibaba.android.rimet:id/cell_subTitle"); for (int i=0;i<keys1.size() && i<values1.size();i++){ try { MobileElement keyEle = keys1.get(i); MobileElement valueEle = values1.get(i); String key = keyEle.getText(); String value = valueEle.getText(); userInfo = userInfo+key+":"+value+","; }catch (Exception e){ e.printStackTrace(); } } try{ MobileElement mobileValueEle =(MobileElement) driver.findElementById("com.alibaba.android.rimet:id/user_mobile_info_content_tv"); String mobile = mobileValueEle.getText(); userInfo = userInfo+"mobile:"+mobile+","; }catch (Exception e){ e.printStackTrace(); } try{ MobileElement mailValueEle =(MobileElement) driver.findElementById("com.alibaba.android.rimet:id/user_mail_info_content_tv"); String email = mailValueEle.getText(); userInfo = userInfo+"email:"+email+","; }catch (Exception e){ e.printStackTrace(); } AllUser = AllUser + userInfo + "\n"; System.out.println(AllUser); }catch (Exception e){ e.printStackTrace(); } } }
start()开始遍历每个item
scanFromElement()点击进入每个item,这里分成两类,一类是人的信息,一类是组织信息。如果是组织信息继续进入深度优先遍历。
getPersenalInfoWithElement()获取个人信息
writeFile()所有个人信息页面信息保存
getUserInfo()提取关键信息
-
代码中使用到的工具类
public class Utils { static public MobileElement waitForElementById(AndroidDriver driver, String elementId, int timeout){ int cout = 0; while (timeout == 0 || timeout>0 && cout<timeout) { try { return (MobileElement) driver.findElementById(elementId); } catch (Exception e) { cout = cout + 1; System.out.println(elementId+":"+cout); } } return null; } static public MobileElement waitForElementByAccessibilityId(AndroidDriver driver, String AccessibilityId, int timeout){ int cout = 0; while (timeout == 0 || timeout>0 && cout<timeout) { try { return (MobileElement) driver.findElementById(AccessibilityId); } catch (Exception e) { cout = cout + 1; System.out.print(AccessibilityId+":"+cout); } } return null; } }
因为有这个程序中有很多延时,完整运行完程序可能会有很长时间。复制最后日志中打印的结果就可以保存成文件了。这里没有写保存文件的代码。
源码:https://github.com/caicai0/getDingDingAddressBook
iOS利用Contacts.framework导入表格通讯录: https://www.jianshu.com/p/279da431ce0d
ios 导入通讯录demo:https://github.com/caicai0/ios_demo/tree/master/contacts_demo