ChatGPT API 와 Python 의 Selenium 을 이용해서 ChatGPT 를 백준 풀이 노예로 만들어보자.
ChatGPT API 안 써보면 뒤쳐지는 느낌이라 써볼만한 걸 생각해봤는데 내 뇌는 이게 한계였다.
목표는 백준 한 페이지, 총 100문제 ChatGPT가 풀고 Selenium이 제출.
import openai
openai.api_key = "#####"
my_model = "gpt-3.5-turbo"
GPT-4가 나왔는데 드디어 3.5 터보를 써본다.
사실 ChatGPT API 사용에 큰 의의는 없다.
다들 챗지피티지피티하는데 내 과제 노예로 쓸 수 있을까 테스트 해보자.
my_messages = [
"role": "system", "content" : "You will send me python code that can solve the problem in BOJ"},
]
역할을 너무 길게 줬나 하는 생각도 들지만, 여러번의 시행 착오 끝에 정확하게 명시하는게 더 나은 결과가 나오는 것 같아서 아는 영단어 총동원해서 작성해줬다.
대답 노예에게 줄 두가지 선택지를 생각해봤다.
1. 문제 내용 줘, 내가 알고리즘 짜볼게
2. 주인님. 문제 번호만 주시면 알아서 해보겠습니다
재수가 없으니까 두번째로 간다.
ChatGPT API 사용은 다음과 같다.
chat = openai.ChatCompletion.create(
model = my_model, messages = my_messages
)
아무리 생각해도 model 을 먼저 create 해둔 다음에, 메시지 송신하는게 맞는 것 같은데..
구글링 실력이 미흡해서 이 방법밖에 모르겠다.
{
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "왈왈",
"role": "assistant"
}
}
],
"created": ######,
"id": "#######",
"model": "gpt-3.5-turbo-0301",
"object": "chat.completion",
"usage": {
"completion_tokens": 10,
"prompt_tokens": 18,
"total_tokens": 28
}
}
그럼 chat
은 다음과 같이 구성된다.
난 "role"
을 "system"
이라고 명시했는데 왜 "assistant"
가 된지는?
몰라.
내가 필요한건 대답
reply = chat['choices'][0]['message']['content']
웃긴 건 다시 질문하면 얘가 대답했던 걸 기억 못하는지.
얘가 했던 대답도 넣어서 질문해야한다.
ChatGPT에게 문제 번호를 주고 풀어보라 하면 문제 설명을 열심히 한 뒤에 코드를 던져준다.
문제 설명 어쩌고 저쪼고 나 이렇게 풀었음ㅋ
```python
print("응애 나 CGPT")
```ㅤ
꼭 한마디씩 더해버리기~
코드를 제출하기 위해 가공해보자.
code_start = reply.find('```python')+10
temp = reply[code_start:]
code_end = temp.find('```')-1
reply = temp[:code_end]
아무튼 ChatGPT는 이쯤하고
원래는 requests, beautifulsoup 을 사용해서 백준을 볶아 먹으려 했는데
reCAPTCHA 인가 머시기 때문에 로그인부터 실패한다.
그래서 뤼캡초ㅑ 의 하드 카운터인 쇌래늄으로 볶았다.
Selenium 으로 로그인, requests 에 로그인 세션 보내기 방법도 해봤는데, 안된다.
뭐 아무튼.
사실 Selenium, requests, beautifulsoup 다 처음 써봐서 ChatGPT 보다 시간을 더 잡아먹었다.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome("본인 크롬드라이버 주소")
driver.get("https://www.acmicpc.net")
그럼 크롬이 열리고 백준에 접근이 된다.
나중에 안건데 그 상태에서 로그인을 수동으로 하면 시행착오 없이 넘어갈 수 있었다.
근데 난 몰랐지
driver.find_element(By.LINK_TEXT, '로그인').click()
사실 이런식으로 하는 것 보다는 처음부터 https://www.acmicpc.net/login
으로 접속하는게 더 좋을 듯 하다.
근데 멋있잖아.
find_element
와 By.NAME
, By.ID
, send_keys
등을 이용하면 로그인에 성공한다.
로그인에 성공했으면 https://www.acmicpc.net/problem/unsolved
에 접속했을 때 의미있는 결과가 나온다.
이 정보들을 beautifulsoup로 문제 번호만 빼올 것이다.
import bs4 import BeautifulSoup as bs
driver.get("https://www.acmicpc.net/problem/unsolved")
html = driver.page_source
soup = bs(html, 'html.parser')
problems = soup.findAll(class_='list_problem_id')
자 이제, problems
안에는 내가 안 푼 문제 100 개의 번호가 들어있다.
webdriver
은 백준에 로그인이 되어있다.
더 할 게 없네? 끝.
이라 생각했다.
https://www.acmicpc.net/submit/문제번호
에 접속해보면 어떤 element
에 send_keys
를 해야할 지 감이 안 온다.
textarea
를 찾긴 찾았는데 뭐 상호 작용이 안 된다나 뭐라나
다른 방법이 있을 수 있겠지만, 한 30분동안 webdriver
에서 계속 튕기기만 하니 정신이 나갈 것 같았다.
get
으로 접속하면 커서가 깜빡이는 것에 집중해보자.
그럼 붙여넣기가 가능...
import pyperclip
이 귀여운 녀석. pyperclip.copy("문자열 ><")
한 줄이면 내 클립보드에 문자열을 박아준다.
내 노예가 일하는 동안에 내가 클립보드에 이상한 걸 때려박지 않는다면, 붙여넣기로 코드 전송이 가능하다.
from selenium.webdriver.common.action_chains import ActionChains
어떻게 붙여넣기 하지?
ActionChains
를 이용하면 된다.
ActionChains(driver).key_down(Keys.COMMAND).send_keys('v').key_up(Keys.COMMAND).perform()
좀 길지만. 한줄이면 webdriver
에 붙여넣기 할 수 있다.
이제 제출 버튼만 find_element
로 찾아서 클릭하면 된다.
이제 해보자고.
내 노예가 일하는 순서는 다음과 같다.
1. 백준에 로그인할게요
2. 안 푼 문제 100개 받아올게요
---반복문 입장---
3. 지피티야 이거 좀 풀어봐
4. 대답 가공해서 복붙
5. 제출 !
새로운 아이디를 만들었다. 헬로월드부터 시작이다.
문제가 엄청 쉬운 문제들인데 푸는 시간이 되게 들쑥날쑥이다.
그러다 알 수 없는 오류로 꺼졌고 24문제 풀었다.
컴파일 에러
는 pyperclip
쓰기 전 send_keys
로 보내다가 띄어쓰기 중첩으로 에러가 났다. c나 c++ 이였으면 상관없었을텐데 파이썬.. 이래서 싫다.
런타임 에러
도 한번 나왔는데 코드길이가 1B
였다. 한글자만 뱉은 대답 노예
수정하다가 한번 틀렸지만 코드 문제는 아니라 맞았다치자.
GPT가 뱉어낸 답은 틀린 게 없다. 복붙하는 과정에서 상품이 좀 상했을뿐.
백준 제일 쉬운 24문제에서 틀려버리면 그것도 문제긴 하다.
아마 중간에 튕긴 이유는 chatGPT 토큰 문제일 가능성이 크다.
24문제로 만족하자
목표 달성은 실패했지만 더이상 ChatGPT가 푸는 걸 기다려줄 인내심이 없다.
Selenium, requests, bs4 시행착오로 얻을 걸 얻었다 자기 위로 하고 마무리.