使用appium採集國家藥監局手機端資訊
一、環境安裝
1.概述
appium是一個開源的自動化測試工具,類似selenium,支援IOS與安卓平臺的原生的,基於移動瀏覽器的,混合的應用
可以用程式碼驅動Appium去驅動移動端的程式
架構:
- Node.js編寫的HTTP server,建立並管理多個文字driver session來和不同的平臺互動
環境:
Node.js——可以開發服務端程式(https://nodejs.org/zh-cn/) - JAVA JDK——JAVA環境(https://www.oracle.com/java/technologies/javase-jdk16-downloads.html)
- Android SDK——Android專屬的軟體開發工具包(
- Appium(https://github.com/appium/appium-desktop/releases/tag/v1.21.0)
2.JavaJDK/Android SDK環境配置
Java JDK:
下載:
安裝:
下一步下一步即可,路徑可修改
環境變數:
新增JAVA_HOME環境變數,再將JAVA_HOME的bin目錄新增至Path
Android SDK:
下載:
安裝:
以下四個工具必選
環境變數:
和Android SDK的環境新增是相似的,最後在Path中新增platform-tools和tools目錄
測試是否安裝成功:
.
二、測試步驟
1.移動端
手機:需要開啟USB除錯模式
模擬器:逍遙模擬器/夜神模擬器/雷電模擬器
可能出現的報錯:adb server version(36) doesn’t match this client(41)
原因:手機模擬器與Android SDK的adb工具不匹配,需要把Android SDK的adb.exe複製,放入模擬機的安裝目錄中,替換nox_adb.exe。
2.CMD命令
adb version 檢視版本
adb devices 檢視已連線的裝置,如果無裝置資訊,嘗試上一步替換adb.exe
C:\Users\Administrator>adb devices List of devices attached 127.0.0.1:21503 device
3.除錯
需要編寫自動化程式,首先就需要能夠定位元素
使用appium
Desired Capabilities:傳送給Appium伺服器的鍵值對集合(可以理解成傳送HTTP請求)
Saved Capability sets:可以儲存鍵值對配置資訊,方便下次開啟
{
"platformName": "Android", #作業系統型別
"platformVersion": "7", #作業系統版本
"deviceName": "127.0.0.1:21513", #連線的手機資訊
"appPackage": "com.hxzk.android.hxzksyjg_xj", #應用的包名
"appActivity": ".ui.activity.MainActivity", #activity
"udid": '127.0.0.1:21513' #指定哪一臺裝置(如果僅連線一臺裝置,可不帶此引數)
}
"appPackage"和"appActivity"通過以下指令檢視,在這之前關閉模擬器其他app,只打開需要測試的app:
C:\Users\Administrator>adb shell
MI 9:/ # dumpsys activity | grep mFocusedActivity
mFocusedActivity: ActivityRecord{bdbddca u0 com.hxzk.android.hxzksyjg_xj/.ui.activity.QueryActivity t294}
MI 9:/ #
可以拿到當前執行手機應用的package和activity
"appPackage": "com.hxzk.android.hxzksyjg_xj", #應用的包名
"appActivity": ".ui.activity.MainActivity", #activity
start session
滑動標錯了,是左邊的 ...
三、python操作
pip install Appium-Python-Client
1.配置資訊:
from appium import webdriver #這一項是appium特有的,其餘和selenium類似
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from industry_templete import RFPDupeFilter, ItemToPG
##################################
class Appium_yjj():
def __init__(self, tb_name="industry_info.國家藥監局_國產藥品"):
'''appium配置資訊'''
#設定表名
self.tb_name = tb_name
# 配置要控制的裝置和裡面的應用鍵值對資訊
self.caps={
"platformName": "Android",
"platformVersion": "7",
"deviceName": "127.0.0.1:21503",
"appPackage": "com.hxzk.android.hxzksyjg_xj",
"appActivity": ".ui.activity.MainActivity",
"udid": '127.0.0.1:21513'
}
# 驅動物件,Appium,ip地址和埠
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', self.caps)
# 顯示等待
self.wait = WebDriverWait(self.driver, 20)
2.點選確認:
通過appium啟動session,確認點選項的id或xpath
移植到python中來:
def skip(self):
'''許可權申請、隱私'''
# 關閉許可權申請,如果有
try:
close_1 = self.driver.find_element_by_id("com.hxzk.android.hxzksyjg_xj:id/dialog_confirm_btn")
except:
close_1 = None
if close_1:
close_1.click()
# 關閉隱私確認,如果有
try:
close_2 = self.driver.find_element_by_id("com.hxzk.android.hxzksyjg_xj:id/dialog_confirm_btn")
except:
close_2 = None
if close_2:
close_2.click()
3.列表頁解析
- 點選操作和上一步是類似的,區別在wait.上一步操作不需要wait,沒有就沒有,而這裡的“查詢”,“國產藥品”,是必須點選的按鈕,"值得"等待。
def select_dir(self,num):
'''選擇條目'''
#點選查詢
self.wait.until(EC.element_to_be_clickable((By.ID, 'com.hxzk.android.hxzksyjg_xj:id/tab_query'))).click()
#sleep(3)
#選擇一級目錄:國產藥品,點選
self.wait.until(EC.element_to_be_clickable((By.ID, 'com.hxzk.android.hxzksyjg_xj:id/tv_item_queryitem'))).click()
sleep(3)
#選擇二級目錄:藥品名稱,點選進入
for i in range(num):
#二級目錄去重,已採集則不點選進入
xpath = '/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.widget.LinearLayout[{}]/android.widget.TextView'
first = self.driver.find_element_by_xpath(xpath.format(1))
while True:
def all_page():
'''整頁篩選去重,12個標籤如果都重複則整個翻頁,否則逐條'''
for p in range(1, 12):
all_text = self.driver.find_element_by_xpath(xpath.format(p))
all_text = all_text.get_attribute('text')
rf_filter = RFPDupeFilter(tb_name=self.tb_name)
not_repet = rf_filter.add_title(all_text)
if p==11 and not not_repet:
last = self.driver.find_element_by_xpath(xpath.format(p))
self.driver.swipe(331, 377, 331, 278, 0)
return False, p
elif not_repet:
return True, p
else:
pass
a, b = all_page()
if a:
break
title = self.driver.find_element_by_xpath(xpath.format(b))
title_text = title.get_attribute('text')
title.click()
#解析欄位
try:
self.parse2()
except Exception as e:
logger.info(title_text)
logger.info(e)
sleep(0.3)
#返回上一級
self.driver.back()
sleep(0.3)
#滑動一格
self.driver.swipe(331, 377, 331, 278, 0)
四、動作鏈錄製
appium可錄製動作鏈,如滑動操作(不僅限於滑動),可按如下步驟錄製,即可得到動作鏈程式碼:
-
TouchAction(driver).press(x=322, y=1148).move_to(x=322, y=777).release().perform()
五、appium解析
如上圖所示,appium獲取的左邊,為當前頁面的xml程式碼,右邊為解析程式碼
右側解析程式碼分為兩部分,Find By 和 Attribute
1.Find By
find by 即為定位方式,從python程式碼可以粗略觀察:
故,可根據實際情況進行選擇,一般來說常用xpath,id,class_name,當然得看該元素有什麼定位方式,xpath一般很長。
title = self.driver.find_element_by_xpath('/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.view.ViewGroup/androidx.recyclerview.widget.RecyclerView/android.widget.LinearLayout[1]/android.widget.TextView')
close_2 = self.driver.find_element_by_id("com.hxzk.android.hxzksyjg_xj:id/dialog_confirm_btn")
2.Attribute
通過定位後的element,再通過get_attribute()方法,即可獲取該鍵值對資訊
title_text = title.get_attribute('text')