파이썬으로 CFA 연습문제 크롤링해서 가져오는 방법이 있네요~

IT/빅데이터|2020. 11. 17. 17:13

이번 시간에는 제가 전에 본 네이버 블로그에서 'GD공원 경비아저씨'라는 아이디의 한 블로거 분의 파이썬으로 CFA 연습문제 크롤링으로 긁어와 문서로 만드는 방법을 직접 실습해 본 결과에 대해 포스팅하려 합니다.

 

이 글이 참 좋았던 그 블로거분이 정리를 참 잘해 주셔서 너무나 큰 도움으로 저도 파이썬으로 CFA의 FRA과목 실제 CFA협회에서 제공하는 연습문제를 문서화 할 수 있었고, CFA 자격 시험을 준비하는 저에게 너무나 큰 도움이 되었던 지식 및 정보이기 때문입니다.

 

이 자리를 빌어 정말 유용한 파이썬 소스를 연구하고 오픈해 주신 경비아저씨 블로거님 감사의 인사를 드립니다.

 

 

이 파이썬 소스를 따라 하기 위해선 먼저 기본적으로 CFA Study카페의 아이디가 있어야 합니다. CFA 스터디 사이트에서 연습문제를 풀기위한 회원은 유료 가입으로 가입하여 쓸 수 있습니다.

 

저도 소정의 수수료를 지급하고 아이디를 발급받아 열심히 문제 풀고 있습니다. 아직 실제 시험에 응시하진 않았고 내년(2021년)에 도전할 생각입니다.

 

 

그럼 아래 예제를 실습한 제 실습 환경은 아래와 같습니다. 따라하실 분들은 미리 준비해 두세요,

 

- 기본적으로 파이썬이라는 프로그래밍 언어에 대한 기본 이해

- 크롬 자동화 도구 프로그램 다운로드

- 파이썬을 실습할 수 있는 UI프로그램인 아나콘다

- 빵빵한 인터넷

- 초고속 SSD를 탑재한 나만의 퍼스널 컴퓨터!

 

 

 

CFA 스터디 사이트에 로그인 후 화면 좌측의 메뉴에 Practice라는 메뉴가 있습니다. 이 메뉴로 이동하면 CFA의 실제 시험 과목에 맞는 연습문제가 과목별로 제공됩니다.

 

FRA(Financial Reporting Analysis)는 GD 경비아저씨님께서 예시로 크롤링하셨던 CFA 여러 과목중 한 과목이며 저도 이 과목으로 소스 테스트해 보았습니다.

 

결론적으로 다른 CFA과목(Quantitative Methods 등)들을 크롤링하기 위해선 소스를 분석하고 변형해서 사용해야 한다는 점.

 

 

대체적으로 문제가 이런식으로 구성되어 있습니다. 웹 페이지 기준으로 문제가 있고 사진에 잘 보이지는 않지만 오른쪽에 A,B,C 중 선택하는 답안지가 있고 답안지 클릭 후에는 정답인지, 오답인지를 체크해서 문제지 아래에 설명지가 나오는 구조입니다.

 

 

 

그리고 이 문제 화면을 소스 분석(크롬에서는 F12버튼을 눌러 보셔요)을 하게 되면 각 웹 페이지 영역별로 CSS ID가 부여되어 있는 ID값을 확인할 수 있으며 파이썬에서는 이 CSS 속성값을 이용해서 크롤링하는 방식입니다.

 

 

GD 경비아저씨님의 블로거 내용을 참조해서 제가 작성해 본 소스 입니다. 전체 소스는 본 포스팅 아래에 별도로 공개해 드렸습니다.

 

 

 

GD 경비아저씨님 블로그 내용을 따라하다 보면 조금 걸리는 부분이 있습니다. 예를 들어 위 사진의 빨간색 부분에 submit.click() 부분을 GD님은 (1)을 주셨는데 오류가 발생하더라구요.

 

 

저 같은 경우 (1)을 ()로 변경해서 크롤링해보니 잘 되었습니다.

 

 

 

그리고 무엇보다도 소스에서 사용되는 라이브러리가 미리 인스톨되어 있어야 한다는 점입니다. selenium 라이브러리나 docx라이브러리를 설치 후에 소스를 실행하셔야 한다는 점.

 

그리고 이게 또 어려웠었던 부분인데..

 

제가 쓰는 파이썬은 3점대 버전입니다. 그런데 docx라이브러리를 설치해도 계속 오류나더라구요..여러 구글링을 해본 결과 파이썬 3점대에선 docx라이브러리가 아닌 python-docx라이브러리를 설치 후 사용해야 한다고 하더라구요.

 

 

처음에는 docx를 다운받았드랬죠. 그래서 계속 오류가 났었드랬죠...

 

 

구글링 열심히해서 문제 원인 알아내고 python-docx로 다운받아 사용했드랬죠. 그래서 정상으로 처리되더라구요.

 

 

그리고 서두에 애기하기는 했는데 크롬 자동화 프로그램 미리 다운받아 두셔요~ 자신의 OS버전에 맞는 프로그램을 다운받으셔야 합니다.

 

 

이렇게까지 해서 소스를 돌려보면 크롬 자동화 프로그램에서 알아서 로그인하고 문제 풀고 따따따딱!!! 하다가 소스가 문제가 없으면 이렇게 지정해 둔 폴더 위치에 문서 쨘! 만들어 주죠.

 

 

 

 

 

전 GD님 따라서 문제와 해설서 따로 각각 1개씩 워드 파일로 만들어 보았습니다.

 

 

 

 

문제 내용도 잘 나오구요. 그른데 역시나 GD님 말씀대로 테이블이 있는 문제는 가독성이 떨어지게 긁어 오네요 ㅎㅎ 이건 제 숙제니 좀더 고민해 보구요~

 

이렇게 까지 해서 CFA 시험 연습문제 문서화 잘되는 파이썬 크롤링 전체 소스입니다!

 

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from bs4 import BeautifulSoup
from tqdm import tqdm
import time
import docx

driver = webdriver.Chrome(r'chromedriver.exe')
driver.implicitly_wait(60)
driver.get('https://study.cfainstitute.org/app/cfa-level-i-full-program-2020#quiz/take/39418')

myid = ""
mypw = ""

username = WebDriverWait(driver, 10).until(lambda drv: drv.find_element_by_css_selector("#Username"))
username.send_keys(myid)
time.sleep(1)

password = WebDriverWait(driver, 10).until(lambda drv: drv.find_element_by_css_selector("#Password"))
password.send_keys(mypw)
time.sleep(1)

submit = WebDriverWait(driver, 60).until(lambda drv: drv.find_element_by_css_selector("#login-form > fieldset > div> input"))
submit.click()
time.sleep(10)

submit = WebDriverWait(driver, 10).until(lambda drv: drv.find_element_by_css_selector("#navigation > ul > li:nth-child(5) > a > span"))
time.sleep(10)
submit.click()

submit = WebDriverWait(driver, 60).until(lambda drv: drv.find_element_by_css_selector("#subview-wrapper > div.subview-container > div > ul > li:nth-child(10) > div.li-cell.pad-left.flex-4"))
submit.click()
time.sleep(1)

submit = WebDriverWait(driver, 10).until(lambda drv: drv.find_element_by_css_selector("#quiz-details > div > div.wrapper.fixed-width-sidebar-columns.sidebar-left > div > div.recommended-action > a"))
submit.click()
time.sleep(1)

PROBLEMS = docx.Document()
PROBLEMS_para = PROBLEMS.add_paragraph()
ANSWERS = docx.Document()
ANSWERS_para = ANSWERS.add_paragraph()

for x in range(659) : 
    Probs = driver.find_element_by_xpath('//*[@id="speechstream-question-start"]/div')
    Question = Probs.text.split('\n')[:-3]
    Question = "\n".join(Question)
    Choices = Probs.text.split('\n')[-3:]
    
    run = PROBLEMS_para.add_run(f'{x+1}번:\n{Question}\n\n'
                                f'A. {Choices[0]}\n'
                                f'B. {Choices[1]}\n'
                                f'C. {Choices[2]}\n\n\n')
    
    submit = WebDriverWait(driver, 10).until(lambda drv: drv.find_element_by_css_selector("#quiz > div.question-content-container.container.padded > div > div.fixed-width-sidebar-columns > div.sidebar-column.wide > div > div > div > div.choices > div.btn-group-vertical > div:nth-child(1) > a.btn.choice-link"))
    submit.click()
    
    submit = WebDriverWait(driver, 10).until(lambda drv: drv.find_element_by_css_selector("#confirm-choice"))
    submit.click()
    
    Answer = driver.find_element_by_xpath('//*[@id="answer"]').text
    run2 = ANSWER_para.add_run(f'{x+1}번:\n{Answer}\n\n')
    
    submit = WebDriverWait(driver, 60).until(lambda drv: drv.find_element_by_css_selector("#quiz > div.question-content-container.container.padded > div > div.toolbar.text-center > div.icon-bar.navigate > a.toolbar-btn.cap.next > i"))
    submit.click()
    time.sleep(1)
    
ANSWERS.save(r'FRA_answers.docx')
PROBLEMS.save(r'FRA_probs.docx')
    

댓글()