파이썬/라이브러리(API)

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기

코데방 2024. 3. 11.
728x90

표 형태 데이터 페이지 번호 가져오기

 

표가 한장이면 그냥 가져오면 되는데 보통 웹페이지에서 표 형태는 상당히 많은 데이터를 가지고 있기 때문에 여러 페이지인 경우가 많습니다. 이럴 때 마지막 페이지 번호를 알아야 반복문을 사용해 모든 데이터를 가져올 수 있기에 먼저 데이터의 처음과 마지막을 파악하는 것이 중요합니다.

 

네이버의 주식 시가총액 순 주식 데이터를 가져와보겠습니다. 아래 url에 있는 화면입니다. 

https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기 - undefined - undefined - 표 형태 데이터 페이지 번호 가져오기

 

 

 

먼저 가장 아랫쪽에 페이지번호가 있는 html의 태그를 확인하겠습니다. 페이지번호에 마우스로 오른쪽 클릭 후 "검사" 버튼을 누르면 개발자 모드에서 코드를 볼 수 있습니다. 

 

쭉 훑어보면 "맨 뒤" 버튼과 매칭되는 클래스가 <td class=pgRR> 입니다. 해당 클래스가 가진 링크 주소가 마지막 페이지의 번호임을 알 수 있습니다. 

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기 - undefined - undefined - 표 형태 데이터 페이지 번호 가져오기

 

 

 

 

이제 페이지 마지막 페이지 번호를 가져오기 위해 코드를 짜봅니다.

먼저 url을 요청해 태그정보를 받습니다.

import requests
from bs4 import BeautifulSoup as bs
import time
import pandas as pd

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")

 

 

그리고 해당 url 객체를 BeautifulSoup으로 정리해줍니다.

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)

 

 

 

find() 함수를 써서 <td> 태그의 "pgRR" 클래스를 찾아봅니다.\

찾고 있는 가장 마지막 페이지가 들어있는 링크는 <a href> 안에 들어있는 것을 알 수 있습니다. 

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
html.find("td", class_ = "pgRR")

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기 - undefined - undefined - 표 형태 데이터 페이지 번호 가져오기

 

 

 

여기서 <a> 태그만 골라내기 위해 한 번 더 find() 함수를 써주고 그 안에서도 "href"의 내용을 골라내기 위해 ["href"]로 접근할 수 있습니다.

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
html.find("td", class_ = "pgRR").find("a")["href"]

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기 - undefined - undefined - 표 형태 데이터 페이지 번호 가져오기

 

 

 

문자열로 된 주소만 골라내졌습니다. 프론트앤드에서 이 형태에서는 대부분 마지막이 페이지 넘버가 되고 "="으로 구분될수밖에 없습니다. 따라서 마지막 번호를 골라내기 위해 "split()"을 사용해 마지막 배열의 숫자만 가져옵니다. 숫자만 가져와서 반복문에 사용할 예정이므로 int형으로 변환도 해줍니다. 

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
page_num = int(html.find("td", class_ = "pgRR").find("a")["href"].split("=")[-1])

 

 

 

 

반복문으로 표 전체 데이터 가져오기

 

이제 페이지의 마지막 번호를 알아냈으니 반복문을 통해 전체 표 데이터를 가져와 배열에 넣어줍니다.

표의 데이터를 가져와 판다스에서 제공하는 데이터프레임 형태로 만들어주는건 판다스에서 제공해주는 "read_html()" 메소드 하나로 가능합니다. 

 

다만 "read_html()"로 데이터프레임을 만들어줄 때는 배열 형태로 들어가기 때문에 첫 번째 값인 [0]번을 불러와줘야 제대로 된 데이터프레임 데이터를 얻을 수 있습니다.

 

그리고 "read_html()"의 매개변수로는 꼭 "str"형태가 들어가야 하기 때문에 BeutifulSoup 객체로 되어 있는 부분을 str 타입으로 변환해서 넣어줘야 합니다. 

import requests
from bs4 import BeautifulSoup as bs
import time
import pandas as pd

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
page_num = int(html.find("td", class_ = "pgRR").find("a")["href"].split("=")[-1])

for i in range(1, page_num +1):
    url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page={}".format(i))
    html = bs(url.text)
    table = html.find("table", class_ = "type_2")

    # 표 부분 데이터 판다스 데이터프레임으로 만들기
    df_table = pd.read_html(str(table))[0]

 

 

 

데이터를 긁어와보면 알겠지만 여백을 위한 표의 행 부분들이 많아서 필수 항목인 "종목명"이 NaN값인 경우가 많습니다. 이를 제거해주고 불필요한 컬럼을 제거해줍니다. 

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
page_num = int(html.find("td", class_ = "pgRR").find("a")["href"].split("=")[-1])

# table_all = []
for i in range(1, page_num +1):
    url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page={}".format(i))
    html = bs(url.text)
    table = html.find("table", class_ = "type_2")

    # 표 부분 데이터 판다스 데이터프레임으로 만들기
    df_table = pd.read_html(str(table))[0]
    
    #불필요한 부분 제거
    df_table = df_table[df_table["종목명"].notnull()]
    del df_table["N"]
    del df_table["토론실"]

 

 

 

이제 한 페이지의 데이터프레임에 표의 내용을 제대로 넣었습니다. 이 작업을 마지막 페이지까지 반복하면서 리스트 안에다가 데이터프레임을 모아주면 되므로 리스트를 하나 만들어서 추가해줍니다.

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
page_num = int(html.find("td", class_ = "pgRR").find("a")["href"].split("=")[-1])

table_all = []
for i in range(1, page_num +1):
    url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page={}".format(i))
    html = bs(url.text)
    table = html.find("table", class_ = "type_2")

    # 표 부분 데이터 판다스 데이터프레임으로 만들기
    df_table = pd.read_html(str(table))[0]
    
    #불필요한 부분 제거
    df_table = df_table[df_table["종목명"].notnull()]
    del df_table["N"]
    del df_table["토론실"]

    table_all.append(df_table)
    print("{}페이지 저장 완료".format(i))

 

 

 

 

한 번에 하면 아주 빠르고 좋긴 한데 크롤링을 무분별하게 하다가는 포털 쪽에서 IP 차단을 당해버릴 위험이 존재합니다. 실제로 네이버는 대부분의 사이트에서 머신의 접근을 거부하고 있습니다. 

 

이 때 필요한 것이 time 라이브러리의 "sleep()" 입니다. "sleep(초)"는 프로세스 수행을 매개변수의 초단위만큼 지연시켜줍니다. 반복문에 사용하면 반복문이 1초에 한 번 돌도록 하는 것이죠. 나름 인간이 클릭하는 속도와 비슷하게 만들어줌으로써 네이버측에서 매크로로 판단하지 않도록 해줍니다.

url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page=1")
html = bs(url.text)
page_num = int(html.find("td", class_ = "pgRR").find("a")["href"].split("=")[-1])

table_all = []
for i in range(1, page_num +1):
    url = requests.get("https://finance.naver.com/sise/sise_market_sum.naver?sosok=0&page={}".format(i))
    html = bs(url.text)
    table = html.find("table", class_ = "type_2")

    # 표 부분 데이터 판다스 데이터프레임으로 만들기
    df_table = pd.read_html(str(table))[0]
    
    #불필요한 부분 제거
    df_table = df_table[df_table["종목명"].notnull()]
    del df_table["N"]
    del df_table["토론실"]

    table_all.append(df_table)
    print("{}페이지 저장 완료".format(i))
    time.sleep(1)

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기 - undefined - undefined - 반복문으로 표 전체 데이터 가져오기

 

 

 

최종 표 데이터 합치기

 

이제 "table_all"이라는 리스트에 모든 데이터프레임이 담겼습니다. 이것을 하나로 합쳐서 하나의 데이터프레임으로 만들어주면 작업이 완성됩니다. 

 

판다스의 "concat()" 메소드를 통해 합쳐주고, 합칠 때 인덱스는 초기화해줄 수 있도록 "igonore_index"값을 True로 설정해줍니다.

final_table_data = pd.concat(table_all, ignore_index = True)

파이썬 웹페이지 크롤링 표를 데이터프레임으로 만들기 - undefined - undefined - 최종 표 데이터 합치기

 

 

 

 

728x90

댓글