일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- hr애널리틱스
- Text mining
- 피플 애널리틱스
- Pa
- 회귀분석
- 다항로지스틱회귀분석
- Talent Analytics
- 하나만 쓰자..
- HR Anlaytics
- HR Analytics
- 유사도분석
- ChatGPT
- LDA Topic Modeling
- HR 애널리틱스
- 피플애널리틱스
- 인사데이터
- PA201
- 태그도 많이 치는거 힘들다..
- HRA
- Workforce Analytics
- survival analytics
- HR데이터
- PA 미래
- 자기소개서 스크리닝
- 성장혼합모형
- HR 데이터 분석
- people analytics
- 데이터분석
- HR대시보드
- HR
- Today
- Total
PA201: People Analytics 201
코린이도 한다, 텍스트 크롤링 (feat. ChatGPT, 구글링) 본문
본 포스팅은 PA201 구성원 "숀"님에 의해 작성된 글입니다.
안녕하세요. 숀입니다.
이슈
• 새로운 영입사이트를 도입함에 따라, 기존의 영입사이트는 서비스 및 운영이 종료될 예정
• 기존의 영입사이트에 있던 영입공고 및 데이터(JD 등)들이 서비스 종료와 함께 유실될 예정
• 해당 데이터는, 영입 파트에 있어서 상당히 의미 있는 비정형 데이터로 판단
목표
. 추후 분석 또는 영입에 활용할 수 있도록 해당 데이터들을 최대한 백업하고자 함
현황
• 기존 영입사이트 제공 업체 : 백업 불가
• 영입공고: 약 580개
• 영입 담당자: 코딩은 for 구문 예제를 실행시켜 본 게 전부인 코린이
결심
• 코린이지만 요즘엔 chatGPT가 코드도 써준다길래, chatGPT를 통해서 기존 영입페이지의 텍스트를 크롤링할 수 있는 코드를 작성해보기로 함.
실행
[Day 1]
• 무작정 ‘텍스트 크롤링’, ‘chatGPT’를 구글링하여 관련 유튜브 영상을 찾게 됨
https://youtu.be/eap62CrRtgg
• 위의 영상을 통해 영입공고의 텍스트를 바로 크롤링하는 것이 아니라, 각 영입공고의 URL을 먼저 크롤링 해야 한다는 것을 알게 됨
• 그래서 chatGPT에게 첫 번째 부탁(?)을 함. (물론 영어는 구글 번역기를 활용)
• 그 결과는, 지나가다가 개발자님의 PC를 몰래 훔쳐봤을 때와 비슷한 느낌의 답변이 나옴
• 정말로 구현(모든 영입공고의 URL을 크롤링)되었는지, 실행시켜 봄
• 예???
• 하지만 당황하지 않고, 오히려 chatGPT에게 어떻게 된거냐고 따져 물음
• 적절한 코드가 나올 때까지 ‘질문을 바꿔가며’ 계속 다시 써달라고 부탁했지만 [ ]만 출력됨
• 명령조로 질문해서, 그런가 하는 마음에 could you로 예의 바르게 질문해 봄. (소용 없었음 TㅡT)
[Day 2]
• ‘크롤링시 아무 값도 가지 오지 못함’을 키워드로 구글링하며 방법을 찾기 시작
• 그러다가 동적인 페이지의 경우, selenium 라이브러리를 이용해야 한다는 것을 알게 됨
파이썬으로 크롤링하는데 값이 안 읽어와질때 해결법
파이썬으로 크롤링하는데 값이 안 읽어와질때 해결법
아마 이렇게 코드를 짰을 것이다 import requests from bs4 import BeautifulSoup # HTTP GET Request req = requests.get('링크') # HTML 소스 가져오기 html = req.text # BeautifulSoup으로 html소스를 python객체로 변환하기 soup = Bea
conservative-vector.tistory.com
• 영입사이트가 동적인 페이지인지는 모르겠으나, selenium 라이브러리를 활용하여 코드를 써달라고 chatGPT에게 부탁함
• 그랬더니 이번에는 뭔가 새로운 오류 메시지를 확인할 수 있었음
• 오류 메시지를 바탕으로, 코드를 수정해달라고 chatGPT에게 부탁함
• 그랬더니 놀랍게도, 드디어! 결과물(URL 크롤링)이 출력됨
• 그러나, 모든 페이지의 URL을 크롤링한 것이 아니라 첫 번째 페이지의 URL만 크롤링 함
• 그래서 현재 보이는 페이지 뿐만 아니라 모든 페이지를 크롤링할 수 있도록 코드 수정을 부탁함
• ‘다음 페이지(next_button)’를 클릭할 수 있는 코드를 작성해 주었지만 오류가 발생
• 이때부터, 여러 페이지를 크롤링할 수 있는 방법을 찾아 chatGPT와 지리한 문답 공방이 이어짐
[Day 3]
• 계속해서 오류가 발생
• 돌이켜 보면, 포기할 뻔했던 가장 큰 고비 중에 하나였음
• chatGPT가 적어주는 코드를 그대로 실행하는 것으로는, 오류의 원인을 파악하기 어렵다고 생각
• 그래서 코드를 나눠서 조금씩 실행하면서, 어느 부분에서 오류가 발생하는지 파악하고자 함
• 이 과정을 통해, chatGPT가 작성한 코드를 ‘글자 덩어리’가 의미가 있는 ‘코드로써’ 조금 이해하게 됨
• chatGPT가 작성해 주는 주요 코드를 어느 정도 이해하게 되었지만, 오류는 여전함
• 그래서 다른 웹페이지에서는 될까 싶어, 크롤링을 테스트 해보았는데 놀랍게도 잘됨
• 그래서 완전히 틀린 길은 아니구나, 스스로를 다독이며 일단 하루를 마무리 함
[Day 4]
• 구글링을 통해 다른 분들이 해놓은 코드를 chatGPT에게 샘플로 보여주며 계속 수정을 요구
• 그렇지만, 여전히 첫 번째 페이지만 크롤링되거나 오류가 발생함
• 그러다 문득 다른 분들의 코드에는 range()에 1개가 아닌 2개의 인수가 있다는 것과 time.sleep() 기능을 통해, 크롬이 동작하는 과정에 시간을 주고 있다는 것을 알게 됨
• 이를 바탕으로, 해당 코드를 조금씩 수정하였고 드디어 전체 페이지(4개 페이지)의 URL을 크롤링 함
(여기서 약간 눈물이 났음 TㅡT)
• 정말 저 부분을 추가하여 크롤링이 된 것인지는 모르겠으나, 일단 기쁜 마음으로 하루를 마무리함
[Day 5]
• 오늘부터는 각 URL(영입공고) 안에 들어 있는 JD(텍스트)를 크롤링하는 코드를 작성해 보고자 함
• 앞서와 마찬가지로 chatGPT에게 해당 페이지의 URL과 html 샘플을 보여주고 코드를 부탁함
• 그랬더니, 놀랍게도 너무나도 쉽게 원하는 결과물을 얻음
• 위 결과에 크게 고무되었고, 더 많은 영역의 텍스트를 크롤링 하도록 코드 수정을 부탁함
• 그 결과 역시 만족스러웠음
• 심지어, 여러 페이지를 크롤링하는 것도 쉽게 성공하였음
• 하지만, 텍스트 데이터를 분석하기 위해서는 항목별(업무, 자격요건 등)로 크롤링 하는 것이 필요했음
• 그래서 무턱대고 chatGPT에게 항목별로 크롤링 할 수 있게, 코드 수정을 부탁함
• 하지만 결과는 엉망이었음
• 정확한 크롤링을 위해서는 메소드와 class, ID, attribute 등을 이해할 필요가 있다는 것을 알게 됨
• 이런 부분은 다행히 구글링을 통해 어느 정도 기본적인 학습을 할 수 있었음
[웹 크롤링 3/3] 원하는 데이터 직접 크롤링해보기 (실전)
[웹 크롤링 3/3] 원하는 데이터 직접 크롤링해보기 (실전)
🎨 웹 크롤링 (3) - 실전 연습!
velog.io
• 이를 통해, chatGPT에게 어떻게 코드를 수정하면 좋을지 구체적으로 부탁했고 항목별로 크롤링이 되도록 코드를 수정함
[Day6]
• 앞서 크롤링 했던 URL(영입공고)에 포함된 모든 JD(텍스트)를 크롤링 하여 엑셀 파일에 저장하도록 chatGPT에게 코드 작성을 부탁함
• 이때부터 두 번째 고비가 시작됨
• chatGPT가 작성해 준 코드를 바탕으로 크롤링을 진행하였으나, 항목별로 나눠서 크롤링이 되지 않거나 아예 크롤링이 되지 않음
• 앞서 영입공고 URL 크롤링과 마찬가지로, chatGPT와의 지리한 문답과 구글링이 이어짐
• 그러나 다행히, 메소드와 클래스에 대한 이해가 있었고 코드를 끊어가며 실행하면서 어느 정도 방향성을 가지고 조금씩 수정할 수 있었음
(이제는 제법 코드가 길어짐)
[Day7]
• 엑셀에 저장되는 크롤링 항목이 하나씩 늘어가는 것을 확인할 수 있었음
• 그렇게 항목별 클래스 또는 태그를 찾아가며, 크롤링 코드를 늘려나감
• 약간의 오류는 있지만 원하는 정보는 어느 정도 크롤링 되고 있다고 판단
• 이에, 영입사이트의 이전 공고를 포함한 모든 공고를 오픈(게시)하여 위의 코드를 실행함
• 여기서 세 번째 고비가 찾아옴
• 이전 공고를 포함해 모든 공고를 오픈하니, 총 58페이지에 걸쳐 크롤링이 필요
• 현재의 코드는 10페이지에서 ‘다음 버튼’을 눌러 11~20이 있는 페이지로 넘어가는 코드가 없었음
• 이번에도 여지없이, chatGPT에게 관련 기능이 구현되도록 코드 수정을 부탁함
• 여기에서 추가적인 구글링을 통해, 10페이지마다 ‘다음 버튼’이 클릭되도록 코드를 수정하였음
try:
if i % 10 != 0:
next_page = driver.find_element(By.XPATH, f"//a[@pageindex='{i+1}']")
next_page.click()
time.sleep(3)
else:
next_button = driver.find_element(By.XPATH, "//button[@class='btn btn-paging btn-small btn-circle fa fa-angle-right']")
next_button.click()
time.sleep(3)
except:
# if there is no next page button, break out of the loop
break
•최종적으로 다음과 같은 코드를 완성하게 됨
•chatGPT가 낳은(?) 코드지만, 왠지 제 자식 같은 결과물 (눈물이.. TㅡT)
[완성본]
import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# set up webdriver
driver = webdriver.Chrome()
# navigate to webpage
driver.get("<https://kakaoent.recruiter.co.kr/app/jobnotice/list>")
# last page check
lastpage = 58
# create list to store urls
url_list = []
# create list to store titles and text
titles_jds = []
# loop through the first 4 pages
for i in range(1,lastpage):
# find all job notice elements on the page
job_notices = driver.find_elements(By.XPATH, "//a[contains(@href, 'jobnoticeSn=')]")
# append the href attribute of each job notice element to the url_list
for job_notice in job_notices:
url_list.append(job_notice.get_attribute("href"))
try:
if i % 10 != 0:
next_page = driver.find_element(By.XPATH, f"//a[@pageindex='{i+1}']")
next_page.click()
time.sleep(3)
else:
next_button = driver.find_element(By.XPATH, "//button[@class='btn btn-paging btn-small btn-circle fa fa-angle-right']")
next_button.click()
time.sleep(3)
except:
# if there is no next page button, break out of the loop
break
# close the webdriver
driver.quit()
# loop through each URL in the url_list
for url in url_list:
# send a GET request to the webpage URL
response = requests.get(url)
# parse the HTML content using BeautifulSoup
soup = BeautifulSoup(response.text, "html.parser")
# find the element containing the title text
title_element = soup.find("span", class_="view-bbs-title")
# check if title_element is None before trying to access its text content
if title_element is not None:
title = title_element.get_text().strip()
else:
title = ""
# find the element containing the text content
if title_element is not None:
# look for the first span element after the title element and extract its text content
period_element = title_element.find_next("span")
if period_element is not None:
period = period_element.get_text().strip()
else:
period = ""
else:
period = ""
if period_element is not None:
# look for the first span element after the title element and extract its text content
status_element = period_element.find_next("span")
if status_element is not None:
status = status_element.get_text().strip()
else:
status = ""
else:
status = ""
if status_element is not None:
# look for the first span element after the title element and extract its text content
position_element = status_element.find_next("ul")
if position_element is not None:
position = position_element.get_text().strip()
else:
position = ""
else:
position = ""
if position_element is not None:
# look for the first span element after the title element and extract its text content
process_element = position_element.find_next("ul")
if process_element is not None:
process = process_element.get_text().strip()
else:
process = ""
else:
process = ""
if process_element is not None:
# look for the first span element after the title element and extract its text content
org_element = process_element.find_next("ul")
if org_element is not None:
org = org_element.get_text().strip()
else:
org = ""
else:
org = ""
if org_element is not None:
# look for the first span element after the title element and extract its text content
work_element = org_element.find_next("ul")
if work_element is not None:
work = work_element.get_text().strip()
else:
work = ""
else:
work = ""
if work_element is not None:
# look for the first span element after the title element and extract its text content
qualification_element = work_element.find_next("ul")
if qualification_element is not None:
qualification = qualification_element.get_text().strip()
else:
qualification = ""
else:
qualification = ""
if qualification_element is not None:
# look for the first span element after the title element and extract its text content
goodtohave_element = qualification_element.find_next("ul")
if goodtohave_element is not None:
goodtohave = goodtohave_element.get_text().strip()
else:
goodtohave = ""
else:
goodtohave = ""
# append the title and text to the title_and_text_list
titles_jds.append([title, period, status, position, process, org, work, qualification, goodtohave])
# save the title and text data to an Excel workbook
wb = Workbook()
ws = wb.active
# write header row
ws.append(['Title', 'Period', 'status', 'position', 'process','org','work','qualification','goodtohave'])
# write the data rows to the Excel workbook
for row in titles_jds:
ws.append(row)
# save the workbook
wb.save('titles_jds.xlsx')
[느낀 점]
• 고작 for문 예제를 실행해봤던 코린이가 맨땅에 헤딩하듯, 영입사이트에서 원하는 데이터를 크롤링 할 수 있었던 것은 어쨌든 chatGPT와 구글링(+ PA 스터디)이 있었기에 가능했습니다.
• 물론 제법 많은 시간이 소요되었지만, chatGPT가 있다면 다른 코린이 담당자나 신입사원들도 충분히 해낼 수 있을 것이라고 생각합니다.
• 시작을 고민하는 분들이 있다면, 저의 미흡한 사례가 작은 용기가 되었으면 좋겠습니다.
'People Insight > PA201 스터디' 카테고리의 다른 글
AI 기반 HR 텍스트 분석 : 자기소개서 스크리닝 (0) | 2023.04.14 |
---|---|
직무기술서 유사도분석을 통한 내부 인재 추천 (0) | 2023.04.10 |
코멘트 유사도를 활용한 조직 네트워크 분석(Organizational Network Analysis) (0) | 2023.04.09 |
LDA Topic Modeling을 활용한 기업 리뷰 분석 (0) | 2023.04.08 |
최근 N년간 부서별 입사자/재직자/퇴직자 수 계산하기 (0) | 2023.03.26 |