dataframe의 한 컬럼에 대해 unique한 값을 얻기위해 'datafame['컬럼명'].uique()' 메소드를 사용할 수 있고 결과값이 list가 아닌 ndarray형태로 생성돼죠.

 

unique() 메소드를 이용하여 생성된 list를 다른 컬럼으로 생성하거나 비교를 위한 list로 활용하려하던 중 ndarray 형태로는 원하는 작업에 지장이 생겨서 list형태로 변환하는 과정입니다.

 

numpy 형태의 배열의 경우 list와 다르게 ','로 구분이 안되어있습니다.

list형태로 간단하게 변경할 수 있습니다.

import numpy as np
unique_values = df_proceed['시간대별'].unique()
print(unique_values)
print(type(unique_values))

# ndarray to list
python_list = unique_values.tolist()
# 결과 확인
print(python_list)

ndarray

Bigquery Table → CSV file download-> Python Dataframe Read 과정에서 발생한 문제

파이썬으로 데이터 분석을 위해 빅쿼리 테이블을 csv로 받았습니다. (google.bigquery packages는 사용하지 않음)

연, 월, 일만을 갖고있는 Datetime을 나타내는 컬럼의 포맷을 변경하면서 발생한 문제입니다.


1. bigquery 테이블을 가져온 csv 파일 Read

Datetime 컬럼 예시

위 컬럼을 yyyy-mm-dd 형태로 포맷을 변경할거죠

 

2. dt.strtime() 메소드 사용 → 에러 발생

dataframe_of_csv = pd.read_csv('bigquery_table.csv')
dataframe_of_csv["SEARCH_DATE"] =  dataframe_of_csv['SEARCH_DATE'].dt.strftime('%Y-%m-%d')

"AttributeError: Can only use .dt accessor with datetimelike values" 에러가 발생합니다

Can only use .dt accessor with datetimelike values는 .dt 접근자는 datetimelike 값에만 사용할 수 있다는 의미입니다. 즉, 해당 컬럼이 datetimelike 데이터 형식이 아니라서 발생한 오류입니다.

 

3. pd.to_datetime(dataframe['컬럼명']) 메소드 사용 → 해결

코드를 아래와 같이 수정하여 원하는 형태로 formmating을 할 수 있습니다.

dataframe_of_csv = pd.read_csv('bigquery_table.csv')
dataframe_of_csv['SEARCH_DATE'] = pd.to_datetime(dataframe_of_csv['SEARCH_DATE'])

Datetime 컬럼 변환 예시

 


결론

bigqeury, csv(file), python pandas(dataframe) 등 테이블 형태를 여러 방법으로 다루다보면 column의 데이터 형으로 인한 문제는 흔하게 발생합니다.

특히 Datetime의 경우 ETL과정에서 형식의 일치가 무엇보다 중요하죠

'ORA-01722: 수치가 부적합합니다'

Oracle 쿼리 실행하다보면 자주 발생하는 에러중 하나입니다.

 

집계함수를 사용하던 중에 발생한 오류를 해결한 과정입니다.

'date_column'에 'yyyy-mm-dd'형태의 일자가 있고, 'a_columnm'에 날짜별 데이터가 있다고 가정했을때,

날짜별로 'a_columnm'이 갖는 값들에 대해 count를 하려합니다.

SELECT TO_CHAR(date_column, 'YYYY-MM') AS month,
       a_column,
       COUNT(*) AS count_per_value
FROM your_table_name
GROUP BY TO_CHAR(date_column, 'YYYY-MM'), a_column
ORDER BY month, a_column;

 

위 쿼리만 봤을 때 문제없이 실행되어야 하지만 'ORA-01722: 수치가 부적합합니다' 에러가 발생합니다.

TO_CHAR() 함수가 실행될 때 데이터 형식에 관련된 문제라고 판단되어 쿼리를 아래와 같이 실행하였습니다.

SELECT TO_CHAR(TO_DATE(date_column), 'YYYY-MM') AS month,
       a_column,
       COUNT(*) AS count_per_value
FROM your_table_name
GROUP BY TO_CHAR(TO_DATE(date_column), 'YYYY-MM'), a_column
ORDER BY month, a_column;

 

'date_column'의 형 변환을 TO_DATE(date_column) 처럼 해준 뒤에 실행하니 정상적으로 실행되었습니다.

다시 확인해보니 'date_column'의 형식이 character형식이었네요.

 

이처럼 oracle은 데이터 형시에 더 민감한 모습을 보여줍니다.

허무하게 해결되었네요 :)

외부서비스에서 제공하는 데이터를 관리용 웹사이트를 이용중인 상황.

하지만 일괄적으로 입력할 데이터 양도 많고 input tag에 값을 일일이 넣을 경우 사이트가 느려지거나 여러 값들을 일일이 넣어줘야하는 번거로운 상황이 있었다.


1. Python requests와 BeautifulSoup4 package 이용

 데이터를 입력하고 submit할 때 호출하는 api와 payload(parameters)값들을 추출하였고 웹브라우저 상에서 테스트 시 정상적으로 작동하였지만 requests 패키지를 활용하여 api를 다루다보니 '세션'관련 문제가 발생하였다.

 form-data에 id와 pw를 입력하여 post로 전송하였으나 이 역시 마찬가지 였으며, headers의 세팅 또한 웹브라우저 환경과 동일하게 하였으나 마찬가지 였다.


2. python selenium 활용

입력할 값들을 미리 변수에 넣어서 selenium으로 자동화를 하려하였으나, 관리하는 데이터의 값들과 사이트 폼이 달라서 사실상 의미없는 작업이었다.


3. 세션유지를 위한 문제해결 방법!

결론적으로 requests를 활용하여 api를 호출하는 방법이 가장 효과적이었기에, 세션 유지를 하고자 1 + 2 방법을 혼용하였다.

최초엔 selenium으로 해당사이트에 로그인을 한 뒤, session 값을 가져와서 requests로 제어하니 원하던 작업을 진행할 수 있었다.

 

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time

driver = webdriver.Chrome(service= Service(ChromeDriverManager().install()))

url = "https://test.com"
driver.get(url)
time.sleep(5)


import requests
# 여기에서 로그인 작업을 수행
# 사용자명과 비밀번호 입력
username_element = driver.find_element(By.XPATH, '//*[@id="UserId"]')  # 사용자명 입력 필드
password_element = driver.find_element(By.XPATH, '//*[@id="UserPassword"]')  # 비밀번호 입력 필드

username_element.send_keys("id")
password_element.send_keys("password")

# 로그인 버튼 클릭
login_button = driver.find_element(By.XPATH, '//*[@id="myForm"]/button')  # 로그인 버튼 선택
login_button.click()



# Selenium을 사용하여 페이지 이동 및 추가 작업 수행

# 이제 requests를 사용하여 세션을 유지하면서 추가 요청을 보낼 수 있음
session = requests.Session()
# 필요한 추가 요청 설정, 세션에 쿠키 등을 추가
# 예를 들어, session.cookies.update(driver.get_cookies())를 사용하여 브라우저 쿠키를 세션에 추가

# requests를 사용하여 추가 요청을 보내거나 데이터를 추출
response = session.get("https://test.com/example/list")
response.text



# Selenium에서 세션 쿠키 가져오기
selenium_cookies = driver.get_cookies()

# requests 세션 초기화
session = requests.Session()

# Selenium에서 가져온 세션 쿠키를 requests 세션에 추가
for cookie in selenium_cookies:
    session.cookies.set(cookie['name'], cookie['value'])

# requests를 사용하여 추가 요청을 보냄
response = session.get("https://test.com/example/list")




# 요청을 보낼 URL
url = "https://test.com/api/sample"

# POST 요청에 사용할 데이터
data = {
    .........
}

response = session.post(url, data=data)

 

핵심은 마지막 줄 처럼 'requests.post()'가 아닌 'session.post()'로 호출한다는 점! 

 flask로 간단한 웹 페이지를 만들어서 Local 환경에서 테스트한 후, 서버에 docker container로 서비스를 가동하니 접속이 안되는 문제가 발생하였습니다.

if __name__ == '__main__':
    cache.clear()
    app.run(debug=True, port=8888)

1. port binding도 잘 해주었고,

2. host도 오타없이 잘 작성하였고,

3. python 파일도 정상적으로 실행되고 있었습니다.

 


host='0.0.0.0'

해결책은 간단했습니다.

 

Flask 애플리케이션을 실행할 때, Flask 서버는 기본적으로 127.0.0.1 또는 localhost에서만 연결을 허용합니다.

따라서 "Running on http://127.0.0.1:8888"과 같이 로컬 주소에서만 서버가 실행되는 것이 기본 동작입니다.

하지만 "Running on all addresses (0.0.0.0)" 또는 "Running on http://172.17.0.2:8100"와 같이 모든 주소에서 서버를 실행하려면 Flask 애플리케이션을 아래와와 같은 코드로 실행해야합니다.

if __name__ == '__main__':
    cache.clear()
    app.run(debug=True, host='0.0.0.0', port=8888)

바로 run()함수에 'host = '0.0.0.0'으로 지정해두니 서버 호스트로도 접속이 정상적으로 이루어졌습니다.

 

아래는 chat-gpt가 답해준 내용입니다. 훌륭한 설명이네요.

이렇게 하면 Flask 서버가 모든 주소 (0.0.0.0)에서 클라이언트 연결을 허용하며, 외부 클라이언트도 액세스할 수 있게 됩니다. 
단, 이렇게 서버를 열면 보안상 주의가 필요하며, 특히 개발 환경에서만 사용해야 합니다. 
production(운영) 환경에서는 보안 검토와 관련된 설정을 고려해야 합니다.
따라서 Flask 애플리케이션을 모든 주소에서 실행하고 싶다면 위의 코드를 Flask 애플리케이션 코드 안에서 사용하십시오.

 

python flask로 구현한 웹 페이지를 가상화공간(docker container)에서 서비스하려할 때 위와 같은 문제가 발생하시는 분들께 도움이 되었으면 합니다.

 

+ Recent posts