Jsoup과 Gson을 활용해서 Java로 Steam 뉴스 받아오기

김효민·2021년 1월 10일
0

구현한 코드 전체는 여기에서 볼 수 있습니다.

이전에서 세웠던 계획을 하나씩 처리하면서 고려했던 점들을 적어보려 합니다.

1. Steam 게임 ID 가져오기

Steam Web API를 이용하려는 계획이었습니다. 그러나 SteamUser Interface를 열심히 봐도 팔로우한 게임의 리스트를 제공하는 API는 나오지 않았습니다. 그래서 저는 직접 스팀 웹사이트(저와 관계가 있을 수도 있고 없을 수도 있습니다)에서 직접 스크래핑하기로 마음 먹었습니다.

🛑 주의: 로봇 배제 표준(robots.txt) 확인

웹사이트를 직접 스크래핑하기 전에 로봇 배제 표준을 확인해야 합니다.

#https://steamcommunity.com/robots.txt

User-agent: *
Disallow: /actions/
Disallow: /linkfilter/
Disallow: /tradeoffer/
Disallow: /trade/
Disallow: /email/
Host: steamcommunity.com

제가 스크랩하려던 페이지는 상관 없는 것 같습니다. 다행이다!

📝 코드 작성

Java 크롤링 라이브러리 추천은 필자가 작성한 글 참조

Steam이라는 클래스를 생성해서 웹페이지를 긁어올 수 있게 했습니다.

//https://github.com/hyoputer/steam-follow-game-newsletter/blob/master/src/main/java/me/hyoputer/Steam.java
public class Steam {

    private static final String FOLLOWED_GAMES_URL_FORMAT = "https://steamcommunity.com/profiles/%s/followedgames/";

    private static final String FOLLOWED_GAME_ITEM_SELECTOR = ".gameListRowItemName > a";

    private String followedGameUrl;

    public Steam(String userId) {
        this.followedGameUrl = String.format(FOLLOWED_GAMES_URL_FORMAT, userId);
    }

    public List<String> getFollowedAppIds() throws IOException {
        return Jsoup.connect(followedGameUrl).get().select(FOLLOWED_GAME_ITEM_SELECTOR)
                .eachAttr("href").stream().map(str -> Pattern.compile("\\D*").matcher(str).replaceAll(""))
                .collect(Collectors.toList());
    }
}
  • static field 로 url과 같은 상수들을 정의하였습니다.
  • 클래스 생성할 때 생성자를 통해서 userId를 받아온다.
  • getFollowedAppIds 메소드는 Jsoup을 통해서 받아온 HTML을 파싱한 후 게임 ID 리스트를 뽑아낸다.

2. Steam News 받아오기

위에서 만든 클래스와 메소드를 이용해서 받은 게임 ID의 리스트를 이용해서 Steam News를 받아올 계획입니다. 게임 ID만 있으면 Steam Web API를 이용해서 해당 게임의 뉴스를 받아올 수 있습니다.

🏭 JSON 처리하기

Steam Web API는 대부분의 API와 같이 기본적으로 JSON으로 데이터를 보냅니다. 따라서 JSON을 처리하는 Java 라이브러리 활용은 필수입니다.

JSON 처리는 주로 Jackson 라이브러리Gson 라이브러리가 쓰입니다. 이 두 가지의 차이점은 구글에 검색하면 여러 블로그에서 알 수 있습니다. 저는 이번 프로젝트에 Gson 라이브러리를 썼습니다. 더 유명하고 스프링부트에도 들어있는 Jackson 라이브러리 대신 Gson 라이브러리를 쓴 이유는 JSON 정보를 객체에 주입할 생각이 없는데 Jackson 라이브러리의 ObjectMapper 객체를 선언해서 사용하는 것은 거추장스럽게 느꼈기 때문입니다.

Gson 라이브러리를 활용해서 위에서 만든 Steam 클래스에 다음과 같이 메소드를 추가했습니다.

//https://github.com/hyoputer/steam-follow-game-newsletter/blob/master/src/main/java/me/hyoputer/Steam.java

 private static final String APP_NEWS_URL_FORMAT = "https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?appid=%s&count=1&maxlength=100&format=json";

 public JsonObject getAppNews(String appId) throws IOException {

    URL url = new URL(String.format(APP_NEWS_URL_FORMAT, appId));

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setRequestMethod("GET");

    InputStreamReader in = new InputStreamReader(connection.getInputStream());

    return JsonParser.parseReader(in).getAsJsonObject().get("appnews").getAsJsonObject().get("newsitems")
                .getAsJsonArray().get(0).getAsJsonObject();
}

Gson 라이브러리는 객체를 따로 선언할 필요는 없지만 위와 같이 static 메소드를 이용해서 바로 파싱 가능하지만 getAsJsonObject와 같은 메소드를 계속 써야 한다는 단점이 있습니다.

이렇게 Steam에서 팔로우한 게임들의 ID를 가져오고 그 ID에 따른 Steam News를 가져오는 부분의 구현을 완성했습니다.

나머지 구현은 다음 글에서 이어집니다. 기대해 주세요!

Reference

Baeldung Jackson vs Gson

profile
귀찮음에 민감한 개발자

0개의 댓글