๊ฒฐ๊ตญ์ ๋ชจ๋ฐ์ผ์์ python ๋๋ฆฌ๋ ๊ฒ์ด๋ผ๋ ๊ฑธ ์๊ฒ ๋์๋ต๋๋ค. ๋ค๋ง ์คํฌ๋กค์ด๋ ์ด๋ฐ ๋ถ๋ถ์ด ์น์ด๋ ๋ฌ๋ผ์ ๋ชจ๋ฐ์ผ ๊ธฐ๋ฅ๋ง ์ตํ๊ณ ์๋ค๋ฉด ๊ธ๋ฐฉ ๊ตฌํ ํ ์ ์์ต๋๋ค.
์ด๋ฒ ์๊ฐ์๋ ์นด๋ทฐ๋ฅผ ๋ชจ๋ฐ์ผ์์ ์๋์ผ๋ก ์คํํ์ฌ ๊ฒ์ ๊ธฐ๋ฅ์ ํตํด ์ฑ๋ ์ ์ ํ ๋ณด๋ ์ ๋ณด ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ ์ ๋๋ค. ํ ์ฑ๋์ 1 ๋ณด๋๋ฅผ ์์๋ก ์์ฑํ์์ต๋๋ค. ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ๋ฐฉ๋ฒ์ ๋ค์ ๋ฒ์ ๋ค๋ฃจ๋๋ก ํ๊ฒ ์ต๋๋ค.
ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๋ณ์ ์ ์ธ
from selenium.webdriver.common.by import By
from appium import webdriver
from time import sleep
import gspread
import emoji
import re
import json
#๊ณต์ ์ฑ๋ ์ ๋ณด ๊ฐ์ง๊ณ ์ค๊ธฐ
channel_list = []
#์ฑ๋๋ณ ๋ณด๋ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ (์ ๋ชฉ, ๋ณด๋ ๋งํฌ)
board_title_list = []
board_url_list = []
PAUSE_TIME = 0.1
LOADING_WAIT_TIME = 2
#๊ตฌ๊ธ ๋ฌธ์ ์ฌ์ฉํ๊ธฐ ์ํ INFO ํ์ผ
with open('/Users/program/info_mobile.json') as json_file:
info = json.load(json_file)
APPIUM ๊ธฐ๋ณธ ์ค์
caps = {}
caps["platformName"] = "Android"
caps["appium:platformVersion"] = "์ํํธ์จ์ด ๋ฒ์ "
caps["appium:deviceName"] = "ํด๋ํฐ์ ์ค์ ๋ ์ด๋ฆ"
caps["appium:app"] = "APK ํ์ผ ๊ฒฝ๋ก"
caps["appium:automationName"] = "Appium"
caps["appium:newCommandTImeout"] = 300
caps["appium:appPackage"] = "์นด์นด์คํก ํจํค์ง ๋ช
"
caps["appium:appActivity"] = "์นด์นด์คํก ๋ฉ์ธ Activity"
caps["appium:udid"] = "adb๋ก ๊ฐ์ ธ์จ ํด๋ํฐ udid ๊ฐ"
caps["appium:noReset"] = "true" #ํ ๋ฒ ์คํํ์ฌ ์ธ์ฆ ๋ฐ์ผ๋ฉด ํด๋น ์ ๋ณด๋ฅผ ์ ์ง
caps["appium:fullReset"] = "false" #์ด๊ธฐํ ์ค์
caps["appium:ensureWebviewsHavePages"] = True
caps["appium:nativeWebScreenshot"] = True
caps["appium:newCommandTimeout"] = 3600
caps["appium:connectHardwareKeyboard"] = True
driver = webdriver.Remote("http://0.0.0.0:4723/wd/hub", caps)
1. ์๋๋ก์ด๋์์ ์นด์นด์คํก์ ์คํ์ํค๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์์ธํ ๊ฐ์ด๋ ๋งํฌ : https://appium.io/docs/en/writing-running-appium/caps/
2. ๋๋ฐ์ด์ค udid ๊ฐ ํ์ธ ๋ฐฉ๋ฒ
๋ณด๋ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
์ฑ๋์ ๋ค์ด๊ฐ์ ๋ณด๋์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ์ ๊ธฐ์ฌํ์์ต๋๋ค.
def newBoard(channelName):
#๊ธ์ผ ์๋ก์ด ๋ณด๋ 00 ~ 23 (h ๊ธฐ์ค)
#๋ณด๋ ์ ๋ชฉ, url, ๊ฐฏ์
title = ""
board_url =""
count = 0
#์ฐพ์ ์ฑ๋๋ช
print("\์ฑ๋๋ช
:", channelName)
#์นด์นด์ค๋ทฐ ๊ฒ์ ๋ฒํผ ํด๋ฆญ
ele = driver.find_element(By.XPATH, value='//android.widget.TextView[@content-desc="๊ฒ์ ๋ฒํผ"]')
ele.click()
sleep(LOADING_WAIT_TIME)
#์ฑ๋๋ช
๊ฒ์์ ์
๋ ฅ
ele = driver.find_element(By.XPATH, value='/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.view.ViewGroup/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.EditText')
ele.send_keys(channelName)
sleep(LOADING_WAIT_TIME)
#๊ฒ์๋ ๊ฒฐ๊ณผ์์ ์ฑ๋ ํด๋ฆญํ์ฌ ์นด์นด์ค๋ทฐ ์ฑ๋๋ก ๋ค์ด๊ฐ๊ธฐ
ele = driver.find_element(By.XPATH, value='//android.view.View[@content-desc="ํ๋กํ ์ฌ์ง"][1]')
ele.click()
sleep(LOADING_WAIT_TIME)
sleep(LOADING_WAIT_TIME)
#์ฑ๋์์ ๋ณด๋ ํญ ํด๋ฆญ
ele = driver.find_element(By.XPATH, value='//android.widget.LinearLayout[@content-desc="๋ณด๋"]/android.widget.LinearLayout/android.widget.TextView')
ele.click()
sleep(LOADING_WAIT_TIME)
#์ ๊ท ๋ณด๋ ์ฌ๋ถ flag
bValue = True
count = 0
while bValue :
#๋ณด๋์ ๋ช์๊ฐ ์ ํ๋ ๊ฐ์ ธ์ค๊ธฐ
ele = driver.find_element(By.XPATH, value='//android.widget.LinearLayout[@content-desc="' + channelName + ', ์ฑ๋"]/android.widget.LinearLayout[2]/android.widget.TextView')
sleep(LOADING_WAIT_TIME)
time = ele.get_attribute("text")
#23์๊ฐ์ ์ซ์ ๊ตฌ๋ถํ๊ธฐ (1์ผ ์ )
replaceTime(text)
print("์์ฑ ์๊ฐ : " , time)
sleep(LOADING_WAIT_TIME)
#๊ฐ์ ธ์จ ์๊ฐ์ด 1์ผ ์ ์ด ์๋ ๊ฒฝ์ฐ ๋ณด๋ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
#์ ๊ท ๋ณด๋ ํ์
์ ์ํ ์กฐ๊ฑด๋ฌธ
if hour.isnumeric():
ele_arry = driver.find_elements(By.ID, value='com.kakao.talk:id/title')
sleep(LOADING_WAIT_TIME)
if len(ele_arry) == 4 :
title = deEmojify(ele_arry[3].text)
elif len(ele_arry) == 3 :
title = deEmojify(ele_arry[2].text)
else :
title = deEmojify(ele_arry[4].text)
sleep(LOADING_WAIT_TIME)
xword = '//android.widget.FrameLayout[@content-desc="๋๋ณด๊ธฐ, ๋ฒํผ, ' + channelName + '"]/android.widget.ImageView'
ele_link_arry = driver.find_elements(By.XPATH, value=xword)
sleep(LOADING_WAIT_TIME)
if len(ele_link_arry) == 2 :
ele_link_arry[1].click()
else :
ele_link_arry[0].click()
sleep(LOADING_WAIT_TIME)
#๋ณต์ฌํ ๋ณด๋ ๋งํฌ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
board_url = driver.get_clipboard_text()
sleep(LOADING_WAIT_TIME)
sleep(LOADING_WAIT_TIME)
#์ต์ข
์ ๊ท ๋ณด๋ ์๋ฅผ ํ์
ํ๊ธฐ ์ํ ๋ฐฐ์ด์ ๋ฐ์ดํฐ ๋ฃ๊ธฐ
board_title_list.append (title)
board_url_list.append(board_url)
#๋ณด๋ ์ ์นด์ดํธํ๊ธฐ
count = count + 1
#์ฝ์์ ๋ก๊ทธ ์ถ๋ ฅ
print(count , ".", channelName , "/ ์ ๋ชฉ : " , title , " / ๋ณด๋๋งํฌ : " + board_url)
title = ""
board_url= ""
# ์ฑ๋์์ ์๋ ๋ณด๋๋ก ๊ฐ๊ธฐ ์ถํ ๊ณ์ฐ์์ผ๋ก ๋ณ๊ฒฝ ์์
driver.swipe(start_x=650,start_y=2000,end_x=650,end_y=520)
# ๊ณ์ฐ์ - ์๋ ์ ์
# board_swipe()
sleep(LOADING_SCROLL_WAIT_TIME)
sleep(LOADING_SCROLL_WAIT_TIME)
else :
#time์ด 1์ผ ์ ์ผ ๊ฒฝ์ฐ ํด๋น ์ฑ๋ ๋ณด๋ ํ์ ์ข
๋ฃ
bValue = False
#ํ์ฌ๊น์ง ํด๋น ์ฑ๋์์ countํ ๋ณด๋ ์ ์ถ๋ ฅ
print("\n ์ฑ๋๋ช
", channelName, ", ์ ๊ท ๋ณด๋ ์ :", count, " Update ์๋ฃ")
*title ๊ฐ์ ธ์ค๋ ๋ถ๋ถ์ ์ค๋ฅ๊ฐ ์์ด ์ถํ ์์ ์์ ์ ๋๋ค. ๋์์ ์์๋ฅผ ์ํ ์ํ ์ฝ๋๋ผ๊ณ ์๊ฐ ๋ถํ๋๋ ค์. Appium Inspector๋ก ํ์ธํด๋ณด๋ Title element์ ์๋๊ฐ์ ์ค๋ช ์ด ์์๋ค. XPATH๋ฅผ ์ฌ์ฉํ์ง ๋ง๋ผ๊ณ ๊ฒฝ๊ณ ๋ฌธ๊ตฌ๊ฐ ์์ด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ๋ณด๋ ์ ๋ชฉ์ ๊ฐ์ ธ์๋ณผ ์์ ์ ๋๋ค.
error Using XPath locators is not recommended and can lead to fragile tests.
MAIN ๊ตฌํ
์ ๋ ๊ตฌ๊ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด ์ฌ๋ฌ๊ฐ์ ์ฑ๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ณ ์์ง๋ง, 1๊ฐ ์ฑ๋์ ํ ์คํธ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ด ์์ ํ์ฌ ํ์ธํ์๋ฉด ๋ฉ๋๋ค.
try:
print("\nSTART...")
#๊ตฌ๊ธ ์ํธ์์ ์ฑ๋๋ฆฌ์คํธ ๊ฐ์ง๊ณ ์์ ๋ฆฌ์คํธ ์ ์ฅ
print("\๊ตฌ๊ธ ์ฐ๋ํ์ฌ ๊ณต์ ์ฑ๋ ์ ๋ณด ์ ์ฅ")
googlelib()
print("\n\์ ์ฅ ์ฑ๊ณต")
defaultMain()
#๊ฐ ์ฑ๋ ๋ณ ์ ๊ท ๋ณด๋ ๊ฐ์ ธ์ค๊ธฐ
print("\์ฑ๋๋ณ ์ ๊ท๋ณด๋ ๊ฐ์ ธ์ค๊ธฐ")
for i in range(len(channel_list)) :
newBoard(channel_list[i])
print("\n\์ ๊ท ๋ณด๋ ์๋ฃ")
print("\๊ตฌ๊ธ ์ํธ์ ๊ฐ ์ ์ฅ")
updateBoardList()
print("\๋ณด๋ ์ ๋ณด ๋งํฌ ์ ์ฅ ์๋ฃ")
finally:
driver.quit()
print("\nEND...")
*1๊ฐ์ ์ฑ๋ ํ ์คํธ ์ฝ๋
try:
#๊ฐ ์ฑ๋ ๋ณ ์ ๊ท ๋ณด๋ ๊ฐ์ ธ์ค๊ธฐ
print("\์ฑ๋๋ณ ์ ๊ท๋ณด๋ ๊ฐ์ ธ์ค๊ธฐ")
newBoard("์ฑ๋๋ช
")
print("\n\์ ๊ท ๋ณด๋ ์๋ฃ")
finally:
driver.quit()
print("\nEND...")
์ฌ๋ฌ๊ฐ์ ์ฑ๋์ ์ ๊ท๋ณด๋๋ฅผ ๊ฐ์ ธ์ฌ ๋ ๊ตฌ๊ธ ์คํ๋ ๋์ํธ๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ถ๊ฐ ์ ์ธ ๋ถ๋ถ์ด์ค๋, ํ์์ ์ฌ์ฉํ์ ์.
๊ตฌ๊ธ ์คํ๋ ๋ ์ํธ๋ฅผ ์ด์ฉํ์ฌ ์นด์นด์ค๋ทฐ ์ฑ๋๋ช ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
์ ๋ ๊ตฌ๊ธ ์คํ๋ ๋ ์ํธ์ ์ด N๊ฐ์ ์ฑ๋๋ช ์ด ๊ธฐ์ฌ๋์ด ์์ด ๊ทธ ์ ๋ณด๋ฅผ ํ์ฉํ์ฌ ์นด์นด์ค๋ทฐ ์๋ํ ํ๋ก๊ทธ๋จ์ ๊ตฌํ ์ค์ ๋๋ค.
def googlelib():
# ๊ตฌ๊ธ ์คํ๋ ๋ ์ํธ ์ฐ๋ , ๊ฐ์ธ ์ ๋ณด์ด๋ฏ๋ก ํ์์ ๋ฐ๋ผ ์์ฉํ์ฌ ์ฌ์ฉ
# google platform ์ธ์ฆ key file
json_file_name = info["keyFile"]
gc = gspread.service_account(filename=json_file_name)
#๋ฆฌ์คํธ ๋ถ๋ฌ์ฌ URL
doc = gc.open_by_url(info["channel_list_doc"])
worksheet = doc.worksheet(info["docName"])
tempName = worksheet.range(info["member_kName"])
tempURL = worksheet.range(info["ch_address"])
for i in range(len(tempName)):
if i > 0 and tempName[i].value !='' :
channel_list.append(tempName[i].value)
for i in range(len(tempURL)):
if i > 0 and tempURL[i].value !='' :
url_parse.append(tempURL[i].value)
print("\์ฑ๋: ", channel_list)
print("\n ์ฑ๋๋งํฌ : ", url_parse)
๊ธฐํ ํ์ํ ํจ์
* remove_emoji ํจ์์ deEmojify ์ค ๋ญ ์ฌ์ฉํ ์ง๋ ์ข ๋ ํ์ธ ํ์
๊ธ์์ ์ด๋ชจ์ง ์ง์ฐ๊ธฐ
def remove_emoji(text):
return emoji.replace_emoji(text,replace='')
def deEmojify(text):
regrex_pattern = re.compile(pattern = "["
u"\U0001F600-\U0001F64F" # emoticons
u"\U0001F300-\U0001F5FF" # symbols & pictographs
u"\U0001F680-\U0001F6FF" # transport & map symbols
u"\U0001F1E0-\U0001F1FF" # flags (iOS)
"]+", flags = re.UNICODE)
return regrex_pattern.sub(r'',text)
์คํฌ๋ฆฐ ์ฌ์ด์ฆ ๋ถ๋ฌ์์ swipe ํ๋ ํจ์
def board_swipe() :
#scroll size
deviceSize = driver.get_window_size()
screenWidth = deviceSize['width']
screenHeight = deviceSize['height']
startx = screenWidth / 2
endx = screenWidth / 2
endy = screenHeight * 2 / 9
starty = screenHeight * 8 / 9
print("start x :" , startx, " start y" , starty , "/end x ", endx , " end y ", endy)
driver.swipe(start_x=startx,start_y=starty,end_x=endx,end_y=endy)
ํญ์ ์นด์นด์คํก ์น๊ตฌ ํญ์์ ๊ฒ์ํ๊ธฐ
def defaultMain() :
#์ฑ๋ ๊ฒ์ ๋ฒํผ
sleep(LOADING_WAIT_TIME)
ele = driver.find_element(By.XPATH, value ='//android.widget.RelativeLayout[@content-desc="์น๊ตฌ ํญ"]')
ele.click()
sleep(LOADING_WAIT_TIME)
ele = driver.find_element(By.XPATH, value='//android.widget.TextView[@content-desc="๊ฒ์ ๋ฒํผ"]')
ele.click()
board_title_list.append("๋ณด๋ ์ ๋ชฉ")
board_url_list.append("๋ณด๋ ๋งํฌ")
sleep(LOADING_WAIT_TIME)
๊ตฌ๊ธ ์คํ๋ ๋ ์ํธ์ ๊ฐ ์ฑ๋๋ณ ๋ณด๋ ์ ๋ณด ์ ๋ก๋ํ๊ธฐ
def updateBoardList() :
json_file_name = info["keyFile"]
gc = gspread.service_account(filename=json_file_name)
doc = gc.open_by_url(info["channel_list_doc"])
worksheet = doc.worksheet(info["docName_update"])
worksheet.clear()
worksheet.insert_cols([board_title_list], col=1, value_input_option='RAW')
worksheet.insert_cols([board_url_list], col=2, value_input_option='RAW')
์นด์นด์คํก ๋ณด๋ ์๊ฐ ์ถ์ถ("์ผ ์ "์ด ์๋ ์ ๋ค์ ์ซ์๋ง ์ถ์ถํ๊ธฐ)
def replaceTime(text) :
reTime = text.replace("์๊ฐ ์ ","")
reTime = reTime.replace("๋ถ ์ ","")
reTime = reTime.replace("์์ ","")
reTime = reTime.replace(" ", "")
return reTime
Python ์์ค๊ฐ ์ค๋น๊ฐ ๋ค ๋์๋ค๋ฉด, Appium ์๋ฒ๋ฅผ ๊ตฌ๋ํ ํ์ ์คํ ์์ผ ํ์ธ ํ ์ ์์ต๋๋ค.
9์ 17์ผ ์์ค๋ฅผ ์กฐ๊ธ ์ ๊ทธ๋ ์ด๋ ํ์ฌ ๋ณด๋ ๋งํฌ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์ฑ๊ณตํ์ต๋๋ค. swipe๋ฅผ ํด๋, ๋งํฌ๊ฐ ์ค๋ณต๋๋ ๊ฒฝ์ฐ๊ฐ ์์ด unique๋ก ํ๋ฒ ๋ ์์ ์์ ๊ฑธ๋ฌ๋ด์ ์ฌ์ฉ ํ๊ณ ์๋ต๋๋ค. ํ 90% ๋ง์กฑ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒ ๊ฐ์์. ๋ฌธ์ ์ฌํญ์ ๋๊ธ ๋ถํ๋๋ ค์
๋์ ์์
์์ ์ ์ฒ๋ผ ๋ณด๋ ๋งํฌ๋ฅผ ๋ณต์ฌํ๋ฉด ์ ์ฌ์ง ์ฒ๋ผ ๊ตฌ๊ธ ์คํ๋ ๋ ์ํธ์ ์ ๋ฐ์ดํธ ํฉ๋๋ค. ํ์ฌ ๋ฌด๋ฃ๋ก ๊ฐ ์ฌ์ดํธ๋ณ ํค์๋๋ฅผ ๋ชจ์๋ ์นํ์ด์ง๋ฅผ ์ ๊ณตํ๊ณ ์๋๋ฐ, ๋ทฐ ์ถ์ฒํค์๋๋ ์ ๋ฐ์ดํธ ํด์ผ๊ฒ ๋จ ์๊ฐ์ ํ์ต๋๋ค. ์ด์ ๋ชจ๋ฐ์ผ๋ ์ปจํธ๋กค ํ ์ ์์ด์ ๋๋ฌด ์ข๋ค์.
์ด๋ ๊ฒ ๊ฐ์ ธ์จ ์น๊ตฌ๋ ์ฑ๋์ ์ ๋ณด๋ฅผ ํ๋ฒ์ ๋ชจ์ ๋ณผ ์ ์์ด์ ์ข๋ค์. ํฐ์คํ ๋ฆฌ ๊ฒ์๊ธ ์์ฑ ์์๋ ์ ๊ทน ๋ฐ์ํด๋ด์ผ๊ฒ ์ด์. ์๋ฅผ ๋ค๋ฉด ์ข์์๊ฐ ๋ง์ด ๋๋ฆฐ ์ฝํ ์ธ ๋ ์ด๋ค๊ฒ ์๋์ง ์ ์น๊ตฌ ์ฑ๋ ์ค Top5๋ฅผ ์ ๋ณํ๊ฑฐ๋ ํ๋๊ฑฐ์ฃ !)
๋๊ธ