본문 바로가기

Python/Investment

ChatGPT로 쉽게 재무제표 웹스크래핑 코딩하기:Noteable plugin

반응형

ChatGPT로 쉽게 재무제표 웹스크래핑 코딩하기:Noteable plugin

필자는 주식에 관심이 많다.
그래서 책도 자주 읽는 편이 아닌 내가 주식 책은 엄청 열심히 봤는데,
그중에서도 재무제표를 분석하고 이 주식이 저평가 되어 있는지 판단하는 분석 방법에 꽂혔었다.
저평가인지 판단하는 방법은 많지만 나는 그중에서 사경인 님의 '재무제표 모르면 주식투자 절대로 하지 마라'에서 소개하는 SRIM을 주로 사용했고 근 1~2년간 좋은 성적을 내기도 했다.
SRIM 분석을 위해 엑셀로 계산식을 만들기도 하고, Python으로 단순하게 계산하는 방법도 했었지만 가장 편한 방법은 역시 웹스크래핑을 통해 모든 것을 자동화하는 방법이 좋다고 생각했었다.
그래서 3년 전쯤에 만든 것이...
3년전 만들었던 SRIM 계산기
종목 코드를 넣으면 Company Guide의 Snap shot에서 연결재무제표를 웹스크래핑하여 SRIM을 계산하는 프로그램이다.
(예시가 KG ETS로 되어 있는데 필자는 3년 전에 KG ETS를 발견하고 최근 좋은 성적을 이루어냈다.)
겸사겸사 현금흐름표와 종목 설명 및 PBR, PER 등을 스크래핑한다.
전체 종목 검색을 하면 국내 코스피/코스닥 종목을 모두 검색해서 SRIM 계산 결과를 엑셀로 출력할 수 있게 만들었다. 지금도 장기투자 종목을 찾을 때는 간간이 참고용으로 쓰는 중인데,
아마 이 프로그램의 코드를 다시 보면 나는 경악할지도 모른다.
Python을 배운지 얼마 되지도 않았고 심지어 웹스크래핑 모듈인 BeautifulSoup도 잘 몰랐고 Tkinter도 잘 모르는 상태에서 열심히 검색해가면서 만들었기 때문에 코드가 엄청 지저분할 것이다...

그래서 이번에 새로 만들어 볼 생각인데, 이번에는 ChatGPT를 통해서 큰 고민 없이 아주 빠르게 만들어 보려 한다.
그냥 ChatGPT에게 웹스크래핑 코드를 작성해달라고 하고 그 코드를 검토하는 것도 충분히 좋지만
나는 Noteable 플러그인을 사용해서 작업을 하려고 한다.
ChatGPT에게 원하는 코드를 프롬프트로 잘 전달만 하면 분명 코드를 잘 주기는 하지만
Noteable을 사용하면 확실히 더 편하고 좋다.

가장 큰 이유는 두 가지인데
1. 답변을 코드로 주지 않고 코드의 결과로 답변을 해준다.
2. 만약 생성한 코드에서 에러가 발생하면 ChatGPT가 다시 작업을 해서 더 정확한 결과를 준다.


이 두 가지만으로도 Noteable 플러그인을 사용하는 이유로 충분하다고 생각한다.

Noteable 플러그인에 대한 설명은 아래 포스트를 참고 부탁드린다.
우선 SRIM을 계산하기 위해선 연간재무제표의 데이터가 필요하다.
이번 포스트에서는 연간재무제표를 웹스크래핑하는 방법만 먼저 작성하고자 한다.

그럼 우선 가장 중요한 연간재무제표의 데이터를 웹스크래핑 하는 코드를 요청해 보자.
ChatGPT에게 요청한 내용 정리
우선 Company Guid에서 '삼성전자'의 연결재무제표의 내용으로 요청해보려 한다.
몇번 시도해보니 역시 좀 명확하게 프롬프트를 정리해주면 결과를 잘 주는 것 같아서 우선 Company Guide에서의 소스를 확인했다.
id가 'highlight_D_A'인 div안에 table 태그가 내가 원하는 내용들을 가지고 있는 것을 확인했다.
이 내용을 포함해서 다른 요청 사항과 함께 정리해서 최종적으로 아래와 같이 프롬프트를 작성했다.

1. 아래 URL에서 ID가 'highlight_D_A'인 div를 찾고 그 안의 table 태그를 웹스크래핑

2. thead는 제외

3. 각 tr의 th의 텍스트만 추출하고 만약 괄호가 있다면 괄호를 포함한 괄호안의 텍스트는 제거해서 추출
그리고 띄어쓰기로 split하고 index가 0번째의 값만 추출할 것

4. 각 tr의 td에서 index가 0~3까지의 텍스트를 추출

5. 추출한 각 td의 텍스트가 만약 빈값('')이면 None으로 변환

6. 추출한 td의 값을 list로 정리

7. 추출한 각 tr의 th를 key로, td를 list로 변환한 값을 value로 하는 dict를 생성

ChatGPT Noteable 결과
● ChatGPT에서의 답변
● Noteable에서의 결과
import requests
from bs4 import BeautifulSoup
import re

# URL 설정
url = 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A005930&cID=&MenuYn=Y&ReportGB=&NewMenuID=11&stkGb=&strResearchYN='

# URL에서 HTML 가져오기
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

# ID가 'highlight_D_A'인 div 찾기
div = soup.find('div', {'id': 'highlight_D_A'})

# div 안의 table 태그 찾기
table = div.find('table')

# thead 제외하기
table.thead.decompose()

# 각 tr 찾기
rows = table.find_all('tr')

# 결과를 저장할 dict 생성
result = {}

# 각 tr에 대해
for row in rows:
    # th의 텍스트 추출
    th_text = row.th.get_text(strip=True)

    # 괄호가 있다면 괄호를 포함한 괄호안의 텍스트 제거
    th_text = re.sub(r'\(.*?\)', '', th_text)

    # 띄어쓰기로 split하고 index가 0번째의 값만 추출
    key = th_text.split()[0]

    # 각 td에서 index가 0~3까지의 텍스트 추출
    values = [td.get_text(strip=True) for td in row.find_all('td')[:4]]

    # 추출한 각 td의 텍스트가 만약 빈값('')이면 None으로 변환
    values = [value if value != '' else None for value in values]

    # 추출한 td의 값을 list로 묶어줌
    result[key] = values

result
내가 원하던 형태로 정확하게 출력해주었다.
이제 웹스크래핑한 결과를 숫자로 변환 및 데이터를 정리를 해보자.
Question
생성한 dict의 values를 None을 제외하고 모두 정수 또는 소수로 변환해줘
Answer
● ChatGPT에서의 답변
● Noteable에서의 결과
Question
출력한 dict의 각 values를 아래 배열의 index와 매칭되게 dict로 변환해줘
['3_years_ago', '2_years_ago', '1_years_ago', 'current']
Answer
● ChatGPT에서의 답변
● Noteable에서의 결과
(사실 current가 아니라 예상(expectation)으로 했었어야 했던 거 같은데 그냥 넘어가자)
ChatGPT로 정리한 최종 코드
import requests
from bs4 import BeautifulSoup
import re

# URL 설정
url = 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A005930&cID=&MenuYn=Y&ReportGB=&NewMenuID=11&stkGb=&strResearchYN='

# URL에서 HTML 가져오기
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

# ID가 'highlight_D_A'인 div 찾기
div = soup.find('div', {'id': 'highlight_D_A'})

# div 안의 table 태그 찾기
table = div.find('table')

# thead 제외하기
table.thead.decompose()

# 각 tr 찾기
rows = table.find_all('tr')

# 결과를 저장할 dict 생성
result = {}

# 각 tr에 대해
for row in rows:
    # th의 텍스트 추출
    th_text = row.th.get_text(strip=True)

    # 괄호가 있다면 괄호를 포함한 괄호안의 텍스트 제거
    th_text = re.sub(r'\(.*?\)', '', th_text)

    # 띄어쓰기로 split하고 index가 0번째의 값만 추출
    key = th_text.split()[0]

    # 각 td에서 index가 0~3까지의 텍스트 추출
    values = [td.get_text(strip=True) for td in row.find_all('td')[:4]]

    # 추출한 각 td의 텍스트가 만약 빈값('')이면 None으로 변환
    values = [value if value != '' else None for value in values]

    # 추출한 td의 값을 list로 묶어줌
    result[key] = values

# 결과 dict의 values를 None을 제외하고 모두 정수 또는 소수로 변환
for key, values in result.items():
    new_values = []
    for value in values:
        if value is not None:
            # 쉼표 제거
            value = value.replace(',', '')
            # 소수점이 있는지 확인
            if '.' in value:
                # 소수로 변환
                new_values.append(float(value))
            else:
                # 정수로 변환
                new_values.append(int(value))
        else:
            new_values.append(None)
    result[key] = new_values

# 각 value를 ['3_years_ago', '2_years_ago', '1_years_ago', 'current']와 매칭되게 dict로 변환
years = ['3_years_ago', '2_years_ago', '1_years_ago', 'current']

for key, values in result.items():
    result[key] = dict(zip(years, values))
내가 필요했던 내용들을 모두 작성해준 ChatGPT이다.
이제 저 코드에서 예외 처리할 내용들을 좀 정리하고 함수로 변경해서 종목코드를 입력하면 스크래핑하게 변경만 하면 된다.
참고로 Company Guide의 URL에서 gicode의 파라미터에 ['A'+종목코드]를 입력하면 해당 종목으로 들어갈 수 있다.
함수로 만들면서 URL에 gicode 부문만 종목코드를 입력하면 해당 URL을 스크래핑하게 만들면 된다.
삼성전자 종목코드:005930
당연히 이 결과는 Noteable을 사용하지 않아도 ChatGPT가 충분히 만들어내는 코드이다.
Noteable을 사용하지 않고 ChatGPT에게 요청했을 때
하지만 아까 위에서도 작성했지만 이렇게 코드만 전달하게 되고 결과는 출력해주지 않는다.
심지어 저 코드가 정상적으로 작동하는지 확인은 사용자가 직접 해야한다.
일반 ChatGPT가 생성한 코드의 결과를 출력해달라고 할 때
그리고 Noteable은 에러가 발생하면 그 에러를 보고 수정이 될 때까지 시도해준다.
● 요청한 내용을 실행 중 에러가 발생했을 때
지금까지 ChatGPT Noteable 플러그인을 통해 Company Guide의 연결재무제표를 웹스크래핑하는 과정에 대해 알아보았다.
Python을 사용하시는 분들에겐 Noteable 플러그인 사용을 강력 추천드린다.

이제 나는 ChatGPT가 생성해 준 저 코드를 활용해서 SRIM 계산하는 코드를 만들어봐야겠다.
계산식에 더 필요한 내용을 스크래핑해야하기 때문에 해당 사항들도 다 마무리해서 추가로 포스팅할 계획이다.

3년 전 공부하면서 시간을 엄청 썼던 때와 비교하면 말도 안 되게 빠르게 끝냈다.
감회가 새로우면서 앞으로 개발될 것들이 너무 기대된다.
AI의 발전 속도에 발맞춰서 사용법과 활용법을 빠르게 익힐 수 있도록 앞으로도 노력해야겠다.
반응형

loading