파이썬

[파이썬] 웹(OP.GG) 스크래핑하기

jackypark 2022. 10. 21. 10:53

개요

한 번도 해본 적 없는 크롤링을 한번 해보았다. 유명 게임 리그 오브 레전드의 전적 검색 사이트인 OP.GG에서 웹 크롤링을 해보았다. 

플레이상 탑 정글 미드 원딜 서폿들의 승률 티어 데이터 정보를 30분 주기로 스크래핑하여 DB에 저장하는 것까지 시도해보았다..

 

사용한 라이브러리 

BeautlfulSoup :

HTML정보로 부터 원하는 데이터를 가져오기 쉽게,
비슷한 분류의 데이터별로 나누어주는(parsing) 파이썬 라이브러리

selenium:

다양한 브라우저 맟 플랫폼에서 웹 응용 프로그램을 위한 무료 자동화 테스트 스위트

webdriver

sqlalchemy:

SQLAlchemy는 인기 있는 SQL 툴킷이며 Object Relational Mapper이다. 이것은 파이썬으로 작성되었고 응용 프로그래머에게 강력한 기능과 풍부한 SQL의 유연성을 제공한다. MIT 라이선스에 따라 출시된 오픈 소스 및 크로스 플랫폼 소프트웨어

pandas:

Pandas는 쉽고 직관적인 관계형 또는 분류된 데이터로 작업할 수 있도록 설계된 

빠르고 유연하며 표현이 풍부한 데이터 구조를 제공하는 Python 패키지

pymysql:

MySQL을 Python에서 사용할 수 있도록 하는 라이브러리

apscheduler:

특정시간에 주기적으로 프로그램을 실행시키는 스케줄러

이번 프로그램에선 단일 프로세스 실행이므로 BLockingScheduler 사용

 

 

과정

플레 이상 탑 정글 미드 원딜 서폿들의 승률 정보 티어를 알려면 

https://www.op.gg/champions?region=kr&tier=platinum_plus&position=   

이제 뒤에 top jungle mid adc sup들을 더해주면 각각의 정보를 불러올 수 있다

저 뽀삐 카밀 나서스 쉔 등등 의 정보는 table에 담겨있는데 tbody로 잘라서 그 안에 태그들을 활용하여 값을 받아오면 dataframe에 저장 후 sql로 db에 저장합니다

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from sqlalchemy import create_engine
import sqlalchemy
import time
import pandas as pd
import pymysql
from apscheduler.schedulers.blocking import BlockingScheduler

def get_Counter(counter):
    if counter is None:
        return 'None'
    else:
        return counter.get('src')

    
def crawl_Daily():
    options = Options()
    options.add_experimental_option('detach', True)  # 브라우저 바로 닫힘 방지
    options.add_experimental_option('excludeSwitches', ['enable-logging'])  # 불필요한 메시지 제거
    ##크롭 드라이버 자동업데이트 및 설치
    service = Service(ChromeDriverManager().install())

    ##DB연결 엔진 설정
    sqlEngine       = create_engine('mysql+pymysql://root:1111@localhost/test', pool_recycle=3600)

    ##db 테이블 설정
    dtypesql = {'rank':sqlalchemy.types.INT, 
              'champImg':sqlalchemy.types.TEXT, 
              'champion':sqlalchemy.types.VARCHAR(20), 
              'tier':sqlalchemy.types.INT,
              'winRate':sqlalchemy.types.VARCHAR(10),
              'pickRate':sqlalchemy.types.VARCHAR(10),
              'banRate':sqlalchemy.types.VARCHAR(10),
              'counter1':sqlalchemy.types.TEXT,
              'counter2':sqlalchemy.types.TEXT,
              'counter3':sqlalchemy.types.TEXT,              
    }

    base_url = "https://www.op.gg/champions?region=kr&tier=platinum_plus&position="
    key=['top','jungle','mid','adc','support']
    for k in range(len(key)):
        search_url = base_url + key[k] ## 검색하는 진짜 url
        driver = webdriver.Chrome(service=service, options=options)
        driver.get(search_url)## 크롬드라이버에 url 넣고
        html = driver.page_source
        soup = BeautifulSoup(html, "html.parser") ##bs4에 html 넣고
        items = soup.select("tbody")##tbody로 짜른다
        driver.quit()
        rows=items[0].find_all('tr') ## 찾아온 데이터에서 tr태그 찾아옴
        champData=[0 for i in range(len(rows))]## tr태그 갯수만큼 챔프 데이터 가져옴
        j=0
        for row in rows: ##for each문
            rank=row.find('td',class_='css-3bfwic e1oulx2j4').find('span').get_text() ##순위보여주는 td태그
            champ=row.find('td',class_='css-cym2o0 e1oulx2j6') ##챔피언 정보를 담고있는 td태그
            img=champ.find('img').get('src')## 챔피언 이미지 
            champName=champ.find('strong').get_text() ## 챔피언 이름을 가지고있는 strong태그
            tier=row.find('td',class_='css-ew1afn e1oulx2j3').get_text() ##티어를 가지고있는 td태그
            rate=row.find_all('td',class_='css-1wvfkid exo2f211') ## 승률,픽률,밴률을 담고있는 td태그
            winRate=rate[0].get_text() ## 승률 
            pickRate=rate[1].get_text() ## 픽률
            banRate=rate[2].get_text() ## 밴률
            counter=row.find('td',class_='css-8jdpx8 e1oulx2j2') ## 카운터 챔피언 3개 아미지

            counterC=[0 for i in range(3)] 

            ## Counter챔피언이 존재를 할수도있고 3개가 아닌 수도있어서 예외처리
            for i in range(3):
                try:
                    counterC[i]=get_Counter(counter.find_all('img')[i])
                except:
                    counterC[i]=None
            ## champdata에 정보 저장
            champData[j]=[rank,img,champName,tier,winRate,pickRate,banRate,counterC[0],counterC[1],counterC[2]] 
            j=j+1
        ##DataFrame 사용 정렬
        data=pd.DataFrame(champData,columns=['rank','champImg','champion','tier','winRate','pickRate','banRate','counter1','counter2','counter3'])
        tableName=key[k]+"champ"
        ##db커넥
        dbConnection    = sqlEngine.connect()
        try:
            ##db에 존재하는 테이블이면 replace시키고 data DB에 저장
            frame           = data.to_sql(name=tableName, con=dbConnection, if_exists='replace',index=False,dtype=dtypesql);

        except ValueError as vx:

            print(vx)

        except Exception as ex:   

            print(ex)

        else:

            print("Table %s created successfully."%tableName);   

        finally:

            dbConnection.close()

            
sched=BlockingScheduler()
##분당 함수 호출
sched.add_job(crawl_Daily,'interval',minutes=1)

## 스타트
sched.start()

 

DB결과

 

느낀 점:

 

간단하지만 내가 원하는 정보를 뽑는 웹 스크래핑을 해보았다. 사실 위 코드는 너무 비효율적인 코드인 것 같다. 내가 파이썬을 오랫동안 했었다면 좀 더 정교하게 짯을텐데 하루 만에 공부하고 구현하느라 어려움이 많았다.

이제 다음으로 파이썬 파일을 AWS ec2에 올려서 진짜 주기적으로 db에 올리는 작업을 해보아야겠다.