관리자 글쓰기

오늘은 파이썬을 이용한 웹 스크래핑에 대해 알아보겠습니다

 

웹 페이지를 가져와서 데이터를 추출해 내는 행위를

웹 크롤링(crawling) 혹은 웹 스크래핑(scraping)이라고 합니다.

 

웹 스크래핑을 하려면 우선 기본적인 html 이해도가 필요합니다.

 

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <header></header>
  <div></div>
</body>
</html>

html은 태그와 속성으로 구성되어 있습니다.

 

웹 스크래핑을 하는 방법은 우선 html에서 추출하고 싶은 데이터가 있는 태그를 찾고

for문, if문 같은 파이썬의 다양한 문법을 이용해서 데이터를 필터링하는 형식입니다.

 

 

 

requests

 

파이썬으로 html을 읽기 위해서는

링크를 입력했을 때 그 링크로 접속해줄 도구가 필요합니다.

 

pip install requests

터미널에 위의 코드를 입력해서 requests 라이브러리를 설치해줍니다.

 

import requests

url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%A3%BC%EC%8B%9D%EC%8B%9C%EA%B0%80%EC%B4%9D%EC%95%A1"
result = requests.get(url)

담고 싶은 데이터가 있는 주소를 url 변수에 저장하고 

requests.get(url) 을 입력해서 페이지에 있는 모든 html 정보를 result 변수에 저장합니다.

 

위의 url은 네이버에 주식 시가총액을 검색했을 때 나오는 주소입니다.

위에서 선택된 부분만 추출해서 파일에 저장하는 실습을 해보겠습니다.

 

 

BeautifulSoup

 

이제 requests로 불러온 html 정보에서 우리가 원하는 정보를 찾아야 합니다.

그걸 가능하게 해주는 라이브러리가 BeautifulSoup 라이브러리입니다

 

pip install beautifulsoup4

터미널에 위의 코드를 입력해서 BeautifulSoup 라이브러리를 설치해줍니다.

 

import requests
from bs4 import BeautifulSoup

url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%A3%BC%EC%8B%9D%EC%8B%9C%EA%B0%80%EC%B4%9D%EC%95%A1"
result = requests.get(url)
soup = BeautifulSoup(result.text, "lxml")

 

result.text 는 아까 가져온 html 정보에서 text만 추출합니다.

이제 그것을 BeautifulSoup이 사용할 수 있는 표현 방식으로 변환시켜 주어야 합니다.

BeautifulSoup에는 변환을 시켜주는 파서(parser) 기능이 있습니다.

 

parser는 4가지의 종류가 있고 각각 장단점이 있지만 

속도가 빠른 lxml 을 사용하는 것을 권장하고 있습니다.

 

 

위의 코드는 웹 스크래핑을 하기 위해 꼭 해야 하는 작업입니다.

 

이제 페이지에서 가져올 데이터가 속해있는 태그를 찾아야 합니다.

 

우선 F12 버튼을 눌러서 개발자 모드를 띄워줍니다.

화살표가 가리키는 버튼을 클릭하면 마우스로 원하는 태그를 찾을 수 있습니다.

 

 

이렇게 표로 정리되어 있는 형식은 보통 <table> 태그 안에 있습니다.

 

 

<table> 태그의 내용은 <tbody> 태그 속에 있습니다.

그리고 <tr> 태그는 table row 를 뜻하며 <tbody>의 각 행을 구성합니다.

 

이제 우리가 할 일은 다음과 같습니다.

 

1. <table> 태그의 class 속성을 이용해서 특정 <table>을 선택한다.

2. 선택한 <table>에 있는 <tbody>, 그 밑에 있는 <tr> 태그들을 리스트에 담는다.

3.  반복문을 돌려서 <tr> 태그의 원하는 정보를 추출한 다음 파일에 옮겨 닮는다.

 

 

 

먼저 BeautifulSoup의 find 메소드로 <table> 태그를 선택합니다.

 

import requests
from bs4 import BeautifulSoup

url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%A3%BC%EC%8B%9D%EC%8B%9C%EA%B0%80%EC%B4%9D%EC%95%A1"
result = requests.get(url)
soup = BeautifulSoup(result.text, "lxml")

table = soup.find("table", {"class":"lsttype_tb"}) # class가 lsttype_tb 인 table중 첫번째

 

이제 <tr> 태그를 저장합니다.

find 메소드는 찾는 태그가 여러 개 존재해도 첫 번째 태그만 저장합니다.

하지만 find_all 메소드를 사용하면 모든 태그를 리스트에 담을 수 있습니다.

 

import requests
from bs4 import BeautifulSoup

url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%A3%BC%EC%8B%9D%EC%8B%9C%EA%B0%80%EC%B4%9D%EC%95%A1"
result = requests.get(url)
soup = BeautifulSoup(result.text, "lxml")

table = soup.find("table", {"class":"lsttype_tb"})
tr_list = table.find("tbody").find_all("tr") # <table> > <tbody> > <tr>

 

이러면 tr_list 안에는 <tr> 태그들의 정보가 담겨있습니다.

 

이제 for문을 사용해서 데이터를 추출해야 합니다.

 

그림을 보면

 

종목 이름: <tr> 태그의 첫 번째 <a> 태그

가격: <tr> 태그의 첫 번째 <td> 태그인 것을 알 수 있습니다.

 

import requests
from bs4 import BeautifulSoup

url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%A3%BC%EC%8B%9D%EC%8B%9C%EA%B0%80%EC%B4%9D%EC%95%A1"
result = requests.get(url)
soup = BeautifulSoup(result.text, "lxml")

table = soup.find("table", {"class":"lsttype_tb"})
tr_list = table.find("tbody").find_all("tr")

for tr in tr_list:
    name = tr.find("a").get_text() # a 태그의 text 부분을 추출
    price = tr.find_all("td")[0].get_text()
    
    with open("stock_quote.txt","a",encoding="utf8") as f: 
    	f.write(f"{name}: {price}\n")

 

for문을 돌려서 각 tr에 있는 이름과 가격을 추출해서 파일에 담았습니다.

 

 

결과를 보면 가격이 천차만별입니다.

마지막으로 여기서 가격이 500,000원 미만인 것들만 담아보겠습니다.

 

하지만 문제가 있습니다.

가격 정보를 보면 71,500 같이 쉼표가 포함되어있는 문자열입니다. 

 

우선 replace() 함수를 사용해서 쉼표를 ""(빈 문자열)로 바꾸고

int 형 변환을 해야 합니다.

import requests
from bs4 import BeautifulSoup

url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%A3%BC%EC%8B%9D%EC%8B%9C%EA%B0%80%EC%B4%9D%EC%95%A1"
result = requests.get(url)
soup = BeautifulSoup(result.text, "lxml")

table = soup.find("table", {"class":"lsttype_tb"})
tr_list = table.find("tbody").find_all("tr")

for tr in tr_list:
    name = tr.find("a").get_text() # a 태그의 text 부분을 추출
    price = tr.find_all("td")[0].get_text()

    price = price.replace(",", "")
    if int(price) >= 500000: # 만약 가격이 50만원 이상이면 continue 
        continue
    
    with open("stock_quote.txt","a",encoding="utf8") as f: 
    	f.write(f"{name}: {price}\n")

 

 

 

이렇게 웹 스크래핑으로 주식 정보를 파일에 옮겨 닮아 보았습니다.

 

웹 스크래핑의 진정한 힘은 엄청난 양의 데이터를 받아와서

내가 원하는 대로 가공을 할 수 있다는 점입니다.

 

간단히 정리해 볼 생각이었는데 글이 너무 길어졌네요 ^^

 

끝까지 봐주셔서 감사합니다.