작성일: 2021. 10. 15. 17:33
이 글은 이전의 블로그( https://aesop.tistory.com/ ) 에서 작성한 글 입니다.
원본 글 링크: 파이썬으로 네이버 폼 매크로를 만들어보자 (tistory.com)
개발 배경
대학에 진학해 대면수업을 하다보니 기숙사에 입주하게 되었다.
여러명이서 함께 생활하는 기숙사의 특정상 코로나 감염에 민감할 수 밖에 없던지라 고등학생 때 하던듯이 자가진단을 진행해야 한다.
고등학생 때에는 교육부가 직접 자가진단 앱을 제공하여 매크로를 만들기 쉽지 않았지만, 기숙사에서는 네이버 폼(Form)을 이용하기에 지난 학기 배운 파이썬을 되짚어 볼 겸 '자가진단 매크로'를 만들어 보았다.
시행착오
실재로 사용할 수 있는 프로그램 개발은 처음이었기에 베이스를 두고 사용할 수 있는 코드를 먼저 찾아 보았다.
그러던 중 유명 인터넷 사이트의 글 기록을 지울 수 있는 클리너 프로그램 코드를 찾게 되었고 이를 이용하기로 하였다.
내부 동작은 selenium
을 이용하였고, GUI 는 PyQt5
를 이용하였다.
작동 방식은 GUI를 띄워 학번, 이름, 방 번호를 입력받아 자동으로 네이버 폼 페이지에 서식을 채움 → 제출이다.
여름방학 때 즈음 파이썬 웹 크롤링 실습을 진행해본 경험이 있어 처음 클리너 프로그램의 소스코드를 봤을 때에는 할 만 하다고 생각했었다.
다만 네이버 폼은 각 항목을 큰 ID > 작은 ID > (중복된 이름의) 항목
처럼 묶어 놨기 때문에 단순한 find_element 만을 사용할 줄 아는 나에게는 살짝 벅차보였다.
해결
새싹 개발자는 Fun 하고 Cool 하고 Sexy 하기 때문에 무지성으로 큰 ID 값 불러오기 > 항목 불러오기
를 통해 해결했다.
하지만 외박과 생활관을 선택하는 버튼 항목에서, 증상을 선택하는 버튼 항목에서 또다시 막혔다.
첫번째 문제는 버튼의 XPATH
를 직접 가져와 find\_element By.XPATH
로 해결하였지만
두번째 문제는 Element is not clickable at point
라는 오류메세지로 한동안 나를 애먹였다. 구글링을 통해 알아낸 바로는 보여지는 페이지 안에서의 버튼은 다른 버튼이 눌려질 수 있기 때문에 스크롤을 내려 버튼이 보이는 곳에서 click( )
를 실행해야 하는 것이었다.
따라서 해당 동작이 필요 없는 가장 밑에 있는 주관식 단답형 부분을 먼저 채워준 후 버튼이 클릭되도록 하여 해결했다.
장단점
PyQt5를 사용해 GUI 형식 .exe
로 빌드함으로써 같은 기숙사 내의 학생들이 어렵지 않게 이용 가능했다.
다만 네이버 폼 특정상 서식 마다 링크가 다르고 element
주소 값 도 다르기 때문에 사용하려면 이용자에 맞게 코드를 수정해야 한다.
소스코드
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from PyQt5.QtWidgets import *
import PyQt5.QtCore
import PyQt5.QtGui
import time
import pyperclip
import random
import sys
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
id_label = QLabel('학번', self)
id_font = id_label.font()
id_font.setPointSize(14)
# id_font.setFamily('Times New Roman')
# id_label.setFont(id_font)
id_label.move(40, 20)
name_label = QLabel('이름', self)
name_font = name_label.font()
name_font.setPointSize(14)
# name_font.setFamily('Times New Roman')
# name_label.setFont(id_font)
name_label.move(40, 80)
room_label = QLabel('방 번호', self)
room_font = room_label.font()
room_font.setPointSize(14)
# room_font.setFamily('Times New Roman')
# room_label.setFont(id_font)
room_label.move(40, 140)
self.id_line = QLineEdit(self)
self.id_line.move(160, 20)
self.name_line = QLineEdit(self)
self.name_line.move(160, 80)
self.room_line = QLineEdit(self)
self.room_line.move(160, 140)
start_btn = QPushButton('설문 시작', self)
start_btn.move(130, 200)
start_btn.clicked.connect(self.survey)
self.setWindowTitle('Corona Survey')
self.move(500, 500)
self.resize(350, 270)
self.show()
def survey(self):
id = self.id_line.text()
name = self.name_line.text()
room = self.room_line.text()
course = "생활관"
temp_list = [36.1, 36.2, 36.3, 36.4, 36.5, 36.6, 36.7, 36.8]
temperature = random.choice(temp_list)
driver = webdriver.Chrome('C:/Temp/chromedriver.exe')
driver.implicitly_wait(3)
driver.get('')
time.sleep(2)
pyperclip.copy(f'{id}')
driver.find_element(By.ID, 'formItem_1').find_element(By.ID, 'answer').send_keys(Keys.CONTROL, 'v')
# time.sleep(1)
pyperclip.copy(f'{name}')
driver.find_element(By.ID, 'formItem_2').find_element(By.ID, 'answer').send_keys(Keys.CONTROL, 'v')
# time.sleep(1)
pyperclip.copy(f'{room}')
driver.find_element(By.ID, 'formItem_5').find_element(By.ID, 'answer').send_keys(Keys.CONTROL, 'v')
# time.sleep(1)
out = driver.find_element(By.XPATH, '//*[@id="formItem_6"]/div/div[3]/div/div[2]/div/div[1]')
out.click()
# time.sleep(1)
pyperclip.copy(f'{course}')
driver.find_element(By.ID, 'formItem_11').find_element(By.ID, 'answer').send_keys(Keys.CONTROL, 'v')
# time.sleep(1)
pyperclip.copy(f'{temperature}')
driver.find_element(By.ID, 'formItem_15').find_element(By.ID, 'answer').send_keys((Keys.CONTROL, 'v'))
# time.sleep(1)
symptom = driver.find_element(By.XPATH, '//*[@id="formItem_13"]/div/div[3]/div/div[9]/div/div[1]')
symptom.click()
# time.sleep(1)
plus_symptom = driver.find_element(By.XPATH, '//*[@id="formItem_12"]/div/div[3]/div/div[2]/div/div[1]')
plus_symptom.click()
# time.sleep(1)
time.sleep(2)
driver.find_element(By.XPATH, '//*[@id="pageNav"]/button[3]').click()
QMessageBox.information(self, '제출 완료', '프로그램을 종료해주세요.')
self.show()
time.sleep(3)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyApp()
sys.exit(app.exec_())
기분
C언어와 함께 떠나버리며 잊은 '전여친 파이썬'이 생각나는 프로젝트 였다.