백준 문제 크롤링

LONGNEW·2022년 2월 3일
0

여러가지

목록 보기
17/18

해당 코드는 solved.ac API를 사용하였습니다.

백준의 모든 문제를 가져와야 하는 일이 있어 코드를 작성하였다.
requests의 경우에 크롤링 하는 경우에 html을 가져오는(?) 형식으로 많이 사용하였는데
API를 가져올 수도 있다.

[python] REST API 호출에서 해당 코드를 읽어볼 수 있고 이를 조금 고치면 사용할 수 있다.

구조

해당 코드의 구조는 이러하다.

  1. 크롤링할 페이지 전달
  2. requests 모듈을 통해 정보 가져옴
  3. str을 json으로 변경한 후 item만 분리
  4. 모든 item을 반복하며 필요한 정보만 가져옴(문제 번호, 타이틀, 태그)
  5. 모든 정보를 전역 변수에 저장
  6. 1 ~ 5를 반복문이 끝날 때 까지 반복하며 마지막에는 csv파일로 저장.

주의

해당 API의 1분, 10분당 즉 시간에 대한 호출 제한을 몰라서 아주 최소한의 횟수로 선택하였다.

  • 10분에 60회 미만으로 호출을 하게 되어 있어 느리다.
  • json을 리턴하지만 파이썬의 특성(?), 코드의 의도로 인해 문자열로 변환된다.
  • json내에서 확인하는 경우에는 모든 정보가 json이다.


메모리 추가사항

기본적으로 한글을 저장하는 상황이라면 메모리를 더 잡아먹는다.
TEXT와 같은 타입에선 길이가 곧 메모리이기 때문에 이를 줄이는 것이 더 좋다고 생각했다.

"", [], 와 같은 기호들을 제거하기 위해 배열이 아닌 문자열을 사용했다.
그리고 영어 태그, 이름을 가져오기 위해서는 가져오는 정보의 위치를 바꾸면 된다.






API를 제작하신 분에게 감사하다.

import requests, time, json, pandas as pd

idx, input_hash, input_title, solve, input_tag = [], [], [], [], []

def appending(hash, title, tags):
    idx.append(None)
    input_hash.append(hash)
    input_title.append(title)
    solve.append(None)
    input_tag.append(tags)

def crawl(page):
    url = "https://solved.ac/api/v3/search/problem"
    querystring = {"query": " ", "page": f"{page}"}

    headers = {"Content-Type": "application/json"}
    response = requests.request("GET", url, headers=headers, params=querystring)

    temp = dict()
    temp["item"] = json.loads(response.text).get("items")
    for item in temp["item"]:
        hash = int(item.get("problemId")) * 1000
        title = item.get("titleKo")
        tags = ""

        info = item.get("tags")
        length = len(info)
        for idx, tag in enumerate(info):
            temp_tag = tag.get("displayNames")
            tags += temp_tag[1].get("short")

            if idx == length - 1:
                continue
            tags += " "

        appending(hash, title, tags)

def make_csv():
    df = pd.DataFrame({"PROBLEM_ID" : idx, "TITLE_NM" : input_title, "TAGS_NM" : input_tag, "SOLVED_USR" : solve, "HASH_ID" : input_hash})
    df.to_csv("problem.csv", index=False, encoding="utf8")

def main():
    for i in range(1, 250):
        print(f"crawling {i} page now still {249 - i} to go")
        crawl(i)

        time.sleep(12)

    make_csv()

if __name__ == "__main__":
    main()

0개의 댓글