nan + nan = 2nan

[개인프로젝트] Foodlog_네이버 내 장소를 sqlite로 저장(1) 본문

Project/개인 프로젝트

[개인프로젝트] Foodlog_네이버 내 장소를 sqlite로 저장(1)

2nan 2023. 4. 18. 22:00
728x90

네이버 지도 내 장소 가져오기


우선적으로 네이버 지도에 있는 내 장소 데이터를 가볍게 가져오는 것을 구현해봤다.

라이브러리는 Selenium, pymysql을 사용했다.

구글링을 해본 결과, 해당 url에서 내 장소에 대한 정보를 json 형태로 얻을 수 있었다.

https://map.naver.com/v5/api/bookmark/sync

해당 url에 접근하기 전, 로그인을 한 상태여야 하기 때문에 login을 수행한 후 해당 url로 이동하여 정보를 가져오는 방식이다.

git에 코드를 올리려면 일단 Naver 계정 정보와 같은 부분은 올리면 안 되기 때문에,

해당 데이터는 secret.json으로 관리한다.

git에 업로드 하지 않도록 .gitignore에 해당 경로를 추가하고, secret의 데이터를 불러오는 함수를 만들어

데이터를 변수로 뿌려주는 방법을 택했다. 애초에 git에 암호화해서 올리는 방식도 있다던데, 해당 방식은 익숙하지 않아

일단 익숙한 방법을 사용하기로 했다.

## utils/common_utils.py

import json
import utils.common_variables as common_variables

STR_FILE_ENCODING = common_variables.STR_FILE_ENCODING

def load_json(str_path_json):
    
    with open(str_path_json, 'r', encoding=STR_FILE_ENCODING) as dict_json:
        str_data = json.load(dict_json)
    
    return str_data

def get_secret_settings(str_path_json):

    dict_json = load_json(str_path_json)
    
    str_naver_id = dict_json['Naver']['id']
    str_naver_password = dict_json['Naver']['password']

    dict_result = {}
    dict_result['str_naver_id'] = str_naver_id
    dict_result['str_naver_password'] = str_naver_password

    return dict_result
## scraping/common_variables.py

import utils.common_utils as common_utils
import utils.common_variables as common_variables

STR_PATH_SECRET = common_variables.STR_PATH_SECRET

dict_secrets = common_utils.get_secret_settings(STR_PATH_SECRET)

STR_NAVER_ID = dict_secrets['str_naver_id']
STR_NAVER_PASSWORD = dict_secrets['str_naver_password']

Json 파일 (secret.json)

get_secret_setting 함수로 json에 있는 데이터를 불러와서 계정 정보를 변수에 담아준다.

## main.py

from selenium import webdriver
from selenium.webdriver.common.by import By
from tqdm import tqdm
import time
import json
import sqlite3
import utils.common_variables as common_variables
import scraping.common_variables as scraping_variables
import sqlite.common_variables as sqlite_variables

# 네이버 로그인 정보
STR_NAVER_ID = scraping_variables.STR_NAVER_ID
STR_NAVER_PASSWORD = scraping_variables.STR_NAVER_PASSWORD
# 경로
STR_PATH_DB = common_variables.STR_PATH_DB
STR_PATH_CHROMEDRIVER = common_variables.STR_PATH_CHROMEDRIVER

STR_CREATE_PLACE = sqlite_variables.STR_CREATE_TABLE_PLACE
STR_CREATE_EVALUATE = sqlite_variables.STR_CREATE_TABLE_EVALUATE
STR_INSERT_PLACE = sqlite_variables.STR_INSERT_PLACE
STR_INSERT_EVALUATE = sqlite_variables.STR_INSERT_EVALUATE

# 웹 드라이버 생성 및 네이버 로그인 페이지 이동
driver = webdriver.Chrome(STR_PATH_CHROMEDRIVER)
driver.get('https://nid.naver.com/nidlogin.login')
time.sleep(2)

# 아이디, 비밀번호 입력 후 로그인 버튼 클릭
id = driver.find_element(By.ID, 'id').send_keys(STR_NAVER_ID)
pwd = driver.find_element(By.ID, 'pw').send_keys(STR_NAVER_PASSWORD)
time.sleep(1)
driver.find_element(By.CLASS_NAME, 'btn_login').click()

#TODO: 로그인 시, 자동입력문자 창이 뜰 경우 stop하고 입력 시까지 무한 대기하기

time.sleep(15)

# 내 장소 정보가 들어있는 페이지 이동
driver.get('https://map.naver.com/v5/api/bookmark/sync')

time.sleep(3)

# 내 장소 정보를 JSON 형태로 가져옴
bookmark_json = driver.find_element(By.XPATH, '/html/body/pre').text
bookmark_data = json.loads(bookmark_json)

# DB 연결 및 내 장소 정보 저장
conn = sqlite3.connect(STR_PATH_DB)
cur = conn.cursor()
conn.execute(STR_CREATE_PLACE)
conn.execute(STR_CREATE_EVALUATE)

dict_folder = {}

for item in tqdm(bookmark_data['my']['folderSync']['folders']):
    folder_id = item['folderId']
    folder_name = item['name']
    dict_folder[folder_id] = folder_name
    cnt = item['bookmarkCount']
    cur.execute(STR_INSERT_EVALUATE, 
                (folder_id, folder_name, cnt))

for item in tqdm(bookmark_data['my']['bookmarkSync']['bookmarks']):
    info = item['bookmark']

    store_name = info['name']
    store_nickname = info['displayName']
    latitude = info['py']
    longitude = info['px']
    create_time = info['creationTime']
    last_update_time = info['lastUpdateTime']
    address = info['address']
    memo = info['memo']
    if memo == '':
        memo = '-'
    place_type_id = info['mcid']
    place_type = info['mcidName']

    folder_info = item['folderMappings'][0]

    folder_id = folder_info['folderId']
    folder_name = dict_folder[folder_id]

    cur.execute(STR_INSERT_PLACE, 
                (store_name, store_nickname, address, memo, place_type_id, 
                 place_type, latitude, longitude, create_time, last_update_time, folder_id, folder_name))


conn.commit()
conn.close()

# 웹 드라이버 종료
driver.quit()

 

 

해당 코드를 활용할 경우, 선언한 전역변수들은 알아서 잘 설정해서 하길 바란다.

순서는 다음과 같다.

Selenium으로 네이버 로그인 페이지에 접속을 해서, id 및 password에 데이터를 입력하고 엔터키를 누른다.

근데 여기서 로그인을 하면, 바로 로그인이 되는 경우도 있지만 (바로 로그인이 된다면 TODO 아래 time.sleep(15)를 줄여서 사용해도 된다.
ex)time.sleep(3)

자동완성문자를 입력해야 넘어가는 경우들도 있었다. 원인은 제대로 파악하지 못 했는데 우선은 해당 문자 입력 창이 뜨면 수기로 입력 후 로그인을 시켰다.

그리고 네이버 지도의 내 장소 데이터가 있는 url로 이동해서 json 데이터를 text 형태로 가져온다.

필요한 정보들은 각각 변수로 담아 sqlite에 저장을 한다.

 

그리고 위에서 사용하는 chromewebdriver는 해당 url에서 본인이 사용하는 크롬 버전과 동일한 파일을 다운 받아,
프로젝트 폴더에서 놓고 STR_PATH_CHROMEWEBDRIVER에 해당 경로를 입력하여 사용하면 된다.

https://chromedriver.chromium.org/downloads

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 113, please download ChromeDriver 113.0.5672.24 If you are using Chrome version 112, please download ChromeDriver 112.0.5615.49 If you are using Chrome version 111, please download ChromeDriver 111.0.5563.64

chromedriver.chromium.org

 

DB에 데이터를 넣을 때 사용한 쿼리는 따로 변수로 빼두었는데, 다음과 같다.

(조금 더 효율적으로 설정할 필요가 있어 보이는데, 귀찮아서 일단은 변수로 담았다.)

## sqlite/common_variables.py

STR_CREATE_TABLE_PLACE = '''
CREATE TABLE IF NOT EXISTS Places
(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    place_name TEXT NOT NULL,
    place_nickname TEXT,
    address TEXT NOT NULL,
    memo TEXT,
    place_type_id TEXT,
    place_type TEXT,
    latitude TEXT,
    longitude TEXT,
    create_time TEXT,
    last_update_time TEXT,
    folder_id INTEGER NOT NULL,
    folder_name TEXT NOT NULL
)
'''
STR_CREATE_TABLE_EVALUATE = '''
CREATE TABLE IF NOT EXISTS Evaluate
(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    folder_id INTEGER NOT NULL,
    folder_name TEXT NOT NULL,
    count INTEGER NOT NULL
)
'''
STR_INSERT_PLACE = """
INSERT INTO Places 
(
    place_name, 
    place_nickname, 
    address, 
    memo, 
    place_type_id, 
    place_type, 
    latitude, 
    longitude, 
    create_time, 
    last_update_time,
    folder_id,
    folder_name
) 
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
STR_INSERT_EVALUATE = """
INSERT INTO Evaluate
(   
    folder_id,
    folder_name,
    count
)
    VALUES (?, ?, ?)
"""

 

해당 코드를 사용하여 Database에 데이터를 넣은 결과는 다음과 같다.

 

지금은 간단하게 구현했는데, 실제 서비스라고 생각한다면 업데이트 및 쿼리 효율성을 생각해서 코드를 개선해나가야겠다.

Comments