본문 바로가기

TFT Support - 3 본문

개인 프로젝트 공부

TFT Support - 3

Seongjun_You 2024. 7. 2. 19:33

내가 가지고 있는 데이터와 어떤 데이터를 비교해야 할지 많이 고민했다.

결국 TFT정보들이 정리되어있는 사이트를 크롤링해서

비교 데이터를 수집하기로 했다.

 

C++로 크롤링을 진행하다 여러 오류를 만나 시간이 오래 걸렸다.

그래서 Python으로 크롤링을 진행하고 해당 출력데이터를 c++로 보내는 방법을 이용하기로 했다.

 

 

점점 디렉터리에 파일이 많아진다.
test.py가 크롤링을 진행하는 스크립트이다.




#include "APIManager.h"
#include "JSONParsing.h"
#include <iostream>
#include <vector>
#include <nlohmann/json.hpp>

#include <cstdio>
#include <cstring>
#include <sstream>

using namespace std;

int main() {
    string puuid = "jzmQU3rvfYTnN7djGlqZg7GvuQISJT1iRAohHZy8PtWwTnFy5EGD8o-_2KL3iVLgEQkB2jk55p6Q_w";
    string api_key = "??";
    string url = "https://www.metatft.com/traits";

    vector<string> match_ids;
    nlohmann::json match_data;

    APIManager get_match_id("https://asia.api.riotgames.com/tft/match/v1/matches/by-puuid/"+ puuid +"/ids?start=0&endTime=1719298646&startTime=1718841600&count=20&api_key=" + api_key); // 실제 API 엔드포인트로 변경
    get_match_id.FetchData();
    MatchID change_to_array(get_match_id.GET_api_data());
    match_ids = change_to_array.GET_match_id();
    
    
    APIManager get_match_data("https://asia.api.riotgames.com/tft/match/v1/matches/"+ match_ids[0] +"?api_key=" + api_key);
    get_match_data.FetchData();
    match_data = get_match_data.GET_api_data();

    Info info_data;
    info_data.from_json(match_data);

    Participant my_data;
    my_data = info_data.get_my_data();

    string pythonscript = "python3 /home/sj/riot_tft_project/Python_script/test.py";
    FILE* pipe = popen(pythonscript.c_str(), "r");
    if (!pipe) {
        std::cerr << "popen() failed : " << strerror(errno) << std::endl;
        return 1;
    }

    // 파이프로부터 데이터 읽기

    vector<string> traits;
    vector<string> avg_places;
    char get_traits[2048];
    char get_avg_places[2048];
    

    fgets(get_traits, sizeof(get_traits), pipe);
    istringstream ss_1(get_traits);
    
    fgets(get_avg_places, sizeof(get_avg_places), pipe);
    istringstream ss_2(get_avg_places);
    
    
    string buffer;
    while(getline(ss_1, buffer, ',')){
        traits.push_back(buffer);
    }

    while(getline(ss_2, buffer, ',')){
        avg_places.push_back(buffer);
    }

    for(auto data : traits){
        cout << data << endl;
    }

    for(auto data : avg_places){
        cout << data << endl;
    }

    pclose(pipe);
    return 0;
}

일단 전부다 main코드에 넣었다.

추후에 클래스 파일로 따로 정리해서 사용할 예정이다.

추가된 코드를 중점적으로 살펴보면


string pythonscript = "python3 /home/sj/riot_tft_project/Python_script/test.py";
    FILE* pipe = popen(pythonscript.c_str(), "r");
    if (!pipe) {
        std::cerr << "popen() failed : " << strerror(errno) << std::endl;
        return 1;
    }
    // 파이프로부터 데이터 읽기

    vector<string> traits;
    vector<string> avg_places;
    char get_traits[2048];
    char get_avg_places[2048];
    

    fgets(get_traits, sizeof(get_traits), pipe);
    istringstream ss_1(get_traits);
    
    fgets(get_avg_places, sizeof(get_avg_places), pipe);
    istringstream ss_2(get_avg_places);
    
    
    string buffer;
    while(getline(ss_1, buffer, ',')){
        traits.push_back(buffer);
    }

    while(getline(ss_2, buffer, ',')){
        avg_places.push_back(buffer);
    }

    for(auto data : traits){
        cout << data << endl;
    }

    for(auto data : avg_places){
        cout << data << endl;
    }

    pclose(pipe);
    return 0;

popen을 이용해서 파이썬 스크립트를 실행시켜 준다.
fgets을 통해 한 줄씩 문자열을 가져올 수 있다.

그래서 python에서 출력양식을 어떻게 하느냐에 따라 편의성이 달라진다.

 

나는 ','을 구분자로 사용해서 split 하기로 했다.

getline을 통해 ss_1, ss_2의 데이터를 split 해주어
vector에 넣어 관리해 준다.


 

 

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

# ChromeDriver의 경로를 설정합니다.
chrome_driver_path = '/usr/local/bin/chromedriver'

# Chrome 옵션 설정 (headless 모드 사용)

chrome_options = Options()
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
chrome_options.add_argument(f"user-agent={user_agent}")
chrome_options.add_argument('--headless')

# ChromeDriver 서비스 생성
service = Service(chrome_driver_path)

# WebDriver 인스턴스 생성
driver = webdriver.Chrome(service=service, options=chrome_options)

# WebDriverWait 인스턴스 생성 (최대 10초 기다림)
wait = WebDriverWait(driver, 5)

# 특정 웹 페이지로 이동
driver.get("https://www.metatft.com/traits")

traits = ""
avg_places = ""
for idx in range(1, 100):  # 인덱스 범위 조정
    selector_string_1 = f"#content-wrap > div.MetaTFTLayout2 > div > div:nth-child(2) > div > div.StatTableContainer > figure > table > tbody > tr:nth-child({idx}) > td:nth-child(1) > div > div"
    selector_string_2 = f"#content-wrap > div.MetaTFTLayout2 > div > div:nth-child(2) > div > div.StatTableContainer > figure > table > tbody > tr:nth-child({idx}) > td:nth-child(3) > div"
    try:
        trait = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector_string_1)))
        avg_place = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector_string_2)))
        traits += trait.text + ","
        avg_places += avg_place.text + ","
        
    except TimeoutException:
        break
print(traits)
print(avg_places)

driver.quit()

Python 코드이다.

Selenium을 통해 스크랩핑을 진행했다.

아무래도 시너지와 승률은 js로 계산되어 나오는 데이터이기에

즉각적으로 가져올 수가 없어 동적으로 데이터를 가져오는 게 편하다고 생각했다.

 

또한 Chrome과 driver의 버전이 일치해야 동작이 가능하다.

WebDriverWait() 함수를 통해 데이터를 즉각적으로 가져오는 게 아니라
설정한 최대시간까지 기다리다 가져오는 방식을 선택했다.

 

너무 빠르게 가져오면 가끔 오류가 났다.

최대시간 지나서까지 데이터를 가져오지 못하면
더 이상 가져올 데이터가 없는 것으로 판단하고 break를 걸었다.

 

그러게 출력된 데이터는
시너지 개수와 시너지이름이고

 

아래 섹터는 같은 인덱스의 평균 등수를 표현해 준다.

 

수집한 데이터와 나의 경기 데이터를 어떻게 활용해야 할지 아직 감이 잡히지 않지만
일단 필요한 데이터들을 수집한 것으로 만족했다.

다음은 다시 작성했던 난잡한 코드들을 클래스별로 알아보기 쉽게 정리할 예정이다.

'개인 프로젝트 공부' 카테고리의 다른 글

TFT Support - 5(완)  (0) 2024.07.05
TFT Support - 4  (0) 2024.07.03
TFT Support - 2  (0) 2024.06.26
TFT Support - 1  (0) 2024.06.21
리눅스 멀티스레드 파일 공유 프로그램 - 10(완)  (0) 2024.06.16
Comments