[๋ฉ์์ด์ฌ์์ฒ๋ผ ๋ฐ์ดํฐ๋ถ์ ๋ถํธ์บ ํ 5๊ธฐ] ์น ํฌ๋กค๋ง ์ฐ์ตํด๋ณด๊ธฐ
0. ํ์ต๋ชฉํ
๋ฐ์ดํฐ ์์ง ์์
์์ ๋ฐฐ์ด ์น ํฌ๋กค๋ง์ ํผ์์(๊ฐ์กฐ) ์ฐ์ตํด๋ณด๋ ค๊ณ ํ๋ค.
๊ฐ์ฌ๋๊ป์ ์๋ ค์ฃผ์ ์ฝ๋ + gpt๋ก ์ฐ์ต ํ ๊ฒ์ด๋ค.
ํผ์์ ํ์ด์ง 2๊ฐ ๊ธ์ด์๋ณด๊ธฐ !!
1. ํ์ด์ฌ ํํ์ด์ง library reference ๋ชฉ์ฐจ ๊ธ์ด์ค๊ธฐ
ํฌ๋กค๋ง ํ ํ์ด์ง :
The Python Standard Library
While The Python Language Reference describes the exact syntax and semantics of the Python language, this library reference manual describes the standard library that is distributed with Python. It...
docs.python.org
ํ๋์ ๊ธ์จ๋ก ์ ํ ๋ชฉ์ฐจ์ ๋งํฌ๋ฅผ ํฌ๋กค๋ง ํด์์ csv ํ์ผ๋ก ์ ์ฅํ ๊ฒ์ด๋ค.
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ถ๋ฌ์ค๊ธฐ
import bs4
import requests
import pandas as pd
import numpy as np
import os
from IPython.display import clear_output
# ์์ค ์์ฒญ ํจ์
def getSource(site):
header_info = {
'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
}
response = requests.get(site, headers = header_info)
# bs4 ๊ฐ์ฒด ์์ฑ
soup = bs4.BeautifulSoup(response.text, 'lxml')
return soup
๐ getSource(site) ํจ์ ์์ฝ
- ํค๋ ์ ๋ณด ์ค์
- ์น ์๋ฒ์ ์ ์์ ์ธ ๋ธ๋ผ์ฐ์ ์ฒ๋ผ ๋ณด์ด๊ฒ ํ๋ ค๊ณ User-Agent ์ ๋ณด๋ฅผ ์ค์ ํ๋ค.
- HTTP ์์ฒญ ๋ณด๋ด๊ธฐ
- requests.get()์ ์ฌ์ฉํ์ฌ ์ง์ ํ site URL์ GET ์์ฒญ์ ๋ณด๋ด๊ณ , ์๋ต(response)์ ๋ฐ๋๋ค.
- BeautifulSoup ๊ฐ์ฒด ์์ฑ
- response.text๋ฅผ lxml ํ์๋ก ์ฝ์ด๋ค์ฌ BeautifulSoup ๊ฐ์ฒด(soup)๋ฅผ ์์ฑํ๋ค.
- ํ์ฑ ๊ฒฐ๊ณผ ๋ฐํ
- ์์ฑํ soup ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
์ด์ ๋ฐ์ ์์ค ์ฝ๋์์ ๋ด๊ฐ ์ํ๋ ๋ถ๋ถ์ ์ถ์ถํด์์ผํ๋ค.
๋ ๋ชฉ์ฐจ data๋ง ํ์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์ ์ฝ๋ (fn+f12)์์ ๋ชฉ์ฐจ ๋ถ๋ถ์ ์ฐพ๊ณ
copy selector ํด์จ๋ค.
< ์ ๊ทผ ์์ >
#the-python-standard-library > div (๋ชฉ์ฐจ ์ ์ฒด ๋ฌถ์)
โฌ๏ธ
#the-python-standard-library > div > ul (๋ชฉ์ฐจ ํ
์คํธ)
โฌ๏ธ
#the-python-standard-library > div > ul > li:nth-child(1) > a (๋งํฌ)
# data ์์ง & ์ ์ฅ
def getData(soup, file_name) :
# ๋ฐ์ดํฐ๊ฐ ์๋ ์ ์ฒด๋ฅผ ๋ถ๋ฌ์จ๋ค
a1 = soup.select_one('#the-python-standard-library > div')
# ์์งํ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ์ ์ฅํ๋ ์ฉ๋๋ก ์ฌ์ฉํ ๋์
๋๋ฆฌ
data_dict = {
'์ ๋ชฉ' :[],
'๋งํฌ' :[],
}
li_list = a1.select('ul > li')
for li in li_list:
a_tag = li.select_one('a')
if a_tag :
title = a_tag.text.strip()
link = a_tag.get('href')
data_dict['์ ๋ชฉ'].append(title)
data_dict['๋งํฌ'].append(link)
df1 = pd.DataFrame(data_dict)
# display(df1)
# ์ ์ฅํ๋ค.
if os.path.exists(file_name) == False :
df1.to_csv(file_name, encoding = 'utf-8-sig', index = False)
# ๋ง์ฝ ํ์ผ์ด ์๋ค๋ฉด
else :
df1.to_csv(file_name, encoding = 'utf-8-sig', index = False, header = None, mode = 'a')
๐ getData(soup, file_name) ํจ์ ์์ฝ
- HTML ์์ ๊ฐ์ ธ์ค๊ธฐ
- soup.select_one('#the-python-standard-library > div')๋ฅผ ์ฌ์ฉํ์ฌ ์ฃผ์ ์ฝํ ์ธ ์์ญ์ ์ ํํ๋ค.
- ๋น ๋์
๋๋ฆฌ ์์ฑ
- data_dict์ '์ ๋ชฉ'๊ณผ '๋งํฌ'๋ฅผ ์ ์ฅํ ๋ฆฌ์คํธ๋ฅผ ์ด๊ธฐํํ๋ค.
- ๋ฆฌ์คํธ ํญ๋ชฉ ์ถ์ถ
- ์ ํํ div ๋ด์ ul > li ์์๋ค์ ๋ชจ๋ ๊ฐ์ ธ์จ๋ค.
- ๊ฐ ํญ๋ชฉ์์ ์ ๋ชฉ๊ณผ ๋งํฌ ์ถ์ถ
- ๊ฐ li์์ <a> ํ๊ทธ๋ฅผ ์ฐพ์ ํ ์คํธ(์ ๋ชฉ)์ href(๋งํฌ)๋ฅผ ๊ฐ์ ธ์ data_dict์ ์ถ๊ฐํ๋ค.
- DataFrame ์์ฑ
- ์์งํ ๋์ ๋๋ฆฌ๋ฅผ pandas.DataFrame์ผ๋ก ๋ณํํ์ฌ ํ ํ์์ผ๋ก ๊ตฌ์ฑํ๋ค.
- CSV ํ์ผ ์ ์ฅ
- ํ์ผ์ด ์๋ค๋ฉด: ์๋ก ์ ์ฅ (header ํฌํจ).
- ํ์ผ์ด ์๋ค๋ฉด: ๊ธฐ์กด ํ์ผ์ ๋ด์ฉ ์ถ๊ฐ ์ ์ฅ (header ์์ด append).
์ ์ด์ ๋ง๋ค์ด๋ ์ฝ๋๋ฅผ ์คํ์์ผ ๋ณด์.
soup = getSource('https://docs.python.org/3/library/index.html')
getData(soup, 'Pydata.csv')
Pydata.csv ํ์ผ๋ก ๋ง๋ค์ด์ง ๊ฒ์ ํ์ธํ ์ ์์๋ค !
๋ชฉํ๋๋ก ์ ๋ชฉ๊ณผ ๋งํฌ ์ ๋๋ก ์ ์ฅ๋์๋ค. ๐
2. ๋์ ํฐ์คํ ๋ฆฌ ๋ธ๋ก๊ทธ์ ๊ธ ์ ๋ชฉ, ๊ธ ์นดํ ๊ณ ๋ฆฌ, ์์ฑ์ผ์ ๋ฅผ ํฌ๋กค๋งํด๋ณด์
1) ๊ธฐ๋ณธ ์ธํ (1๋ฒ ๋ฌธ์ ์ ๋์ผํ๋ค)
import bs4
import requests
import pandas as pd
import numpy as np
import os
import time
from IPython.display import clear_output
# ์์ค ์์ฒญ ํจ์
def getSource(site):
header_info = {
'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
}
# ์์ฒญํ๋ค.
response = requests.get(site, headers=header_info)
# bs4 ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
## BeautifulSoup์ HTML ๋๋ XML ๋ฌธ์๋ฅผ ํ์ฑํ๊ณ ๊ตฌ์กฐํํด์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ์ถ์ถํ ์ ์๋๋ก ๋์์ฃผ๋ ๋๊ตฌ
soup = bs4.BeautifulSoup(response.text, 'lxml')
return soup
< ์ ๊ทผ ์์ >
#mArticle (๊ธ์ด ์๋ ๊ณณ ์ ์ฒด)
โฌ๏ธ
#mArticle > div (๊ฐ๊ฐ์ ๊ธ๋ค)
โฌ๏ธ
#mArticle > div > a.link_post > strong (๊ธ์ ์ ๋ชฉ)
โฌ๏ธ
#mArticle > div:nth-child(3) > div > a (์นดํ
๊ณ ๋ฆฌ)
โฌ๏ธ
#mArticle > div:nth-child(3) > div > span.txt_date (์์ฑ ๋ ์ง)
2) ๋ฐ์ดํฐ ์์ง ํจ์
# ํ ํ์ด์ง์ ๋ฐ์ดํฐ๋ฅผ ์์งํด ์ ์ฅํ๋ ํจ์
def getData(soup, file_name):
# ๋ฐ์ดํฐ๊ฐ ์๋ ์ ์ฒด๋ฅผ ๊ฐ์ ธ์จ๋ค
a1 = soup.select_one('#mArticle')
# ์์งํ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ฆฌ์คํธ
data_list = []
# ๋ด๋ถ์ ํ๊ทธ๋ค ๊ฐ์ ธ์ค๊ธฐ
a2 = a1.select('div')
for div in a2 :
# ์ ๋ชฉ ๊ฐ์ ธ์ค๊ธฐ
# #mArticle > div:nth-child(3) > a.link_post > strong
a3 = div.select_one('a.link_post > strong')
title = a3.text.strip() if a3 else None
# ์นดํ
๊ณ ๋ฆฌ ๊ฐ์ ธ์ค๊ธฐ
# #mArticle > div:nth-child(3) > div > a
a4 = div.select_one('a')
category = a4.text.strip() if a4 else None
# ์์ฑ๋ ์ง ๊ฐ์ ธ์ค๊ธฐ
# #mArticle > div:nth-child(3) > div > span.txt_date
a5 = div.select_one('span.txt_date')
date = a5.text.strip() if a5 else None
# ๋ฆฌ์คํธ์ ๋ฐ์ดํฐ๋ค์ ๋ด๋๋ค
data_list.append({
'์ ๋ชฉ': title,
'์นดํ
๊ณ ๋ฆฌ': category,
'์์ฑ๋ ์ง': date
})
# ๋์
๋๋ฆฌ๋ฅผ ๊ฐ์ง๊ณ ๋ฐ์ดํฐ ํ๋ ์์ ์์ฑํ๋ค.
df1 = pd.DataFrame(data_list)
#display(df1)
# ํ์ผ๋ก ์ ์ฅํ๋ค. (Index๋ ์ ์ฅํ์ง ์๋๋ค)
if os.path.exists(file_name) == False:
df1.to_csv(file_name, encoding = 'utf-8-sig', index = False)
else:
df1.to_csv(file_name, encoding = 'utf-8-sig', index = False, header = None, mode = 'a')
์ด๋ฒ์๋ ์ฌ๋ฌ ํ์ด์ง๊ฐ ์๋ ์ฌ์ดํธ ์ด๊ธฐ ๋๋ฌธ์
๋ค์ ํ์ด์ง ์ฃผ์๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์๋ ํ์ํ๋ค.
# ๋ค์ ํ์ด์ง ์ฃผ์๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
def getNextPage(soup) :
# Next ๋ฒํผ์ ํ๊ทธ๋ฅผ ๊ฐ์ ธ์จ๋ค.
next_tag = soup.select_one('#mArticle > div.area_paging > span > a.btn_next')
print(next_tag)
if next_tag != None :
# href ์์ฑ์ ๊ฐ์ ๊ฐ์ ธ์จ๋ค.
# ๋ค์ ํ์ด์ง์ ๋งํฌ
href = next_tag.get('href')
if href :
return href
else :
return None
else:
return None
# ์์งํ ์ฌ์ดํธ ์ฃผ์
site = 'https://tobepotato.tistory.com/'
# ์์งํ๊ณ ์ ํ๋ ํ์ด์ง๋ฅผ ๋ํ๋ด๋ ๊ฐ
# ์ฒ์์๋ ๋น๊ณต๊ฐ์ผ๋ก
page = ''
while True :
time.sleep(1)
# ๊ธฐ์กด์ ์ถ๋ ฅ๋ ๊ฒ์ ์ฒญ์ํ๋ค.
clear_output(wait=True)
print(f'{site}{page} ์์ง์ค...')
# ํ์ด์ง ์์ฒญ
soup = getSource(site + page)
# ํ์ ํ์ด์ง์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์ ์ฅํ๋ค.
getData(soup, 'tistoryData.csv')
# ๋ค์ ํ์ด์ง ์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ๋ค.
page = getNextPage(soup)
if page == None :
print('์์ง์๋ฃ')
break
๊ทธ๋ฐ๋ฐ..
์ ์ฝ๋๋ฅผ ๋๋ฆฌ๋ฉด? csv ํ์ผ์ด ์์ง๊ฒฝ์ด๋ค...๐ข๐ข๐ข
< ๋ฌธ์ ์ํฉ๐จ >
1. ํ ํ์ ์ ๋ชฉ-์นดํ
๊ณ ๋ฆฌ-๋ ์ง ๋ก ์ถ๋ ฅ๋์ง ์๊ณ ์ ๋ชฉ๊ณผ ์นดํ
๊ณ ๋ฆฌ-๋ ์ง ์ด๋ ๊ฒ ํ ๊ธ ๋น ๋ ํ์ฉ ์ถ๋ ฅ๋๊ณ ์๋ค.
2. ์ด์ , prev ๋จ์ถ๋ ๊ฐ์ด ๊ธ์ด์ด๊ณ ์๋ค.
3. None ๊ฐ์ด ๋ง์์ ๋น์นธ์ด ๋ง๋ค.
< ํด๊ฒฐํ๊ธฐ โ >
์ผ๋จ None ๊ฐ์ด ์๋ ๋ฐ์ดํฐ๋ง ๊ฐ์ ธ์ค๊ธฐ ์ํด์
if title and category and date :
data_list.append({
'์ ๋ชฉ': title,
'์นดํ
๊ณ ๋ฆฌ': category,
'์์ฑ๋ ์ง': date
})
๋ฆฌ์คํธ์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ ์กฐ๊ฑด๋ฌธ์ผ๋ก ๋ฃ์ด์
title, category, date๊ฐ None์ด ์๋ ๋๋ฅผ ๊ฐ์ ํ์๋ค.
< ๋ฌธ์ ์ํฉ๐จ > 1. ํ ํ์ ์ ๋ชฉ-์นดํ ๊ณ ๋ฆฌ-๋ ์ง ๋ก ์ถ๋ ฅ๋์ง ์๊ณ ์ ๋ชฉ๊ณผ ์นดํ ๊ณ ๋ฆฌ-๋ ์ง ์ด๋ ๊ฒ ํ ๊ธ ๋น ๋ ํ์ฉ ์ถ๋ ฅ๋๊ณ ์๋ค. 2. ์ด์ , prev ๋จ์ถ๋ ๊ฐ์ด ๊ธ์ด์ด๊ณ ์๋ค. |
๊ทธ๋ฆฌ๊ณ ๋ด๋ถ์ ํ๊ทธ๋ค์ ๊ฐ์ ธ์ฌ ๋, ์์ชฝ ๊ณต๋ฐฑ์ ์ ๊ฑฐํ๋
title = a3.text.strip() if a3 else None
category = a4.text.strip() if a4 else None
date = a5.text.strip() if a5 else None
์ ์ฝ๋๋ค์ ๋ชจ๋ ์ญ์ ํ๋ค.
์ด์ ๋ ์ผ๋จ ๋ ๊ฒ ๊ทธ๋๋ก์ ์ถ๋ ฅ์ ๋ณด๊ณ ๋ฌด์์ ๊ณ ์ณ์ผํ ์ง ๋ณด๊ธฐ ์ํด์์ด๋ค.
๊ทธ๋ผ ์๋์ ๊ฐ์ด ํ์ผ์ด ๋ง๋ค์ด ์ก๋ค !!
prev, next ๋จ์ถ๋ ์์ด์ง๊ณ , ๊ธ ํ๋ ๋น ํ๋์ ํ์ผ๋ก ์ ์ถ๋ ฅ๋๋ค.
๊ทผ๋ฐ ์ด์ html ์ฝ๋๊ฐ ์ ๋ค๋ก ๋ธ๋ ค ๋์จ๋ค๋๊ฒ ๋ฌธ์ ..
< ๋ฌธ์ ์ํฉ๐จ > 4. html ํ๊ทธ ๋ค์ด ์ ๋ค๋ก ์ถ๋ ฅ๋๋ ํ์ (์๋ก์ด ๋ฌธ์ ๐ข) |
gpt์๊ฒ ๋ฌผ์ด๋ณธ ๊ฒฐ๊ณผ ...
a4 = div.select_one('a')
a ํ๊ทธ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์์ ๋ถํฐ ๋ฌธ์ ๊ฐ ๋น๋กฏ๋์๋ค๊ณ ํ๋ค.
โ ๋น ๋ฅด๊ฒ ์ ๋ฆฌํ๋ฉด:
- ํ์ฌ ํฌ๋กค๋ง ๋์ ํ์ด์ง์๋ ๋ช ํํ ์นดํ ๊ณ ๋ฆฌ ํ ์คํธ๊ฐ ์๊ณ ,
- a ํ๊ทธ๋ ์ด๋ฏธ์ง๋ ํฌ์คํธ ๋งํฌ ์ญํ ๋ง ํ๊ณ ์์ด์.
- ๊ทธ๋์ .text๋ฅผ ํด๋ ๋น์ด์๊ฑฐ๋ ์๋ฏธ ์๋ ํ ์คํธ๊ฐ ๋์ค๋ ๊ฒ๋๋ค.
๋ผ๊ณ ํ๋ค.. ๊ทธ๋์ 'a'์ ์ ๊ทผํ์ง ์๊ณ 'a.link_cate' ๋ก ์ ๊ทผ ํ๋๋
๋๋์ด ๋ด๊ฐ ์ํ๋ ๊ฒฐ๊ณผ๋ฌผ์ด ๋์๋ค !
link_cate๊ฐ ๋ฌด์์ด๋๋ฉด... ๋ฐ๋ก ๋นจ๊ฐ์ ๋ถ๋ถ
<a href="/category/%EB%A9%8B%EC%9F%81%EC%9D%B4%EC%82%AC%EC%9E%90%EC%B2%98%EB%9F%BC%20%E0%BB%92%28%E2%8A%99%E1%B4%97%E2%8A%99%29%E0%A5%AD%E2%9C%8E" class="link_cate">๋ฉ์์ด์ฌ์์ฒ๋ผ เป(โแดโ)เฅญโ</a>
< ๋ฌธ์ ์ํฉ๐จ > |
์ฝ๋ ๊น์ง ๋ถ์ฌ๋ฃ๊ธฐ ํ๋ฉด ๊ธ์ด ๋๋ฌด ๊ธธ์ด์ง๋๊น Py ํ์ผ์ ์ฌ๋ ค๋ฌ์ผ๊ฒ ๋ค (๊ธฐ๋ก์ฉ)
๊ฒฐ๊ตญ ํด๋ธ ๋ ์ ๋ง ์นญ์ฐฌํด !!
๐ญ ๋๋์
์ฒซ ๋ฒ์งธ ํ๋ก์ ํธ๋ ๊ฐ์ฌ๋๊ป์ ์ฌ์ด ์ฌ์ดํธ๋ก ์ฃผ์
์ ๊ธฐ์กด ์ฝ๋๋ง ๋ฐ๋ผ๊ฐ๋ฉด ํฌ๊ฒ ์ด๋ ต์ง ์์๋๋ฐ,
๋ ๋ฒ์งธ ํ๋ก์ ํธ๋ ๊ฐ์ธ ํผ์์ ํ๋๊ฑฐ๋ค ๋ณด๋๊น ๋งํ๋ฉด ๋๋ฌด ์ด๋ ค์ ๋ค.
ํนํ ์นดํ
๊ณ ๋ฆฌ ํ๊ทธ๊ฐ ๋น์ฐํ a์ธ์ค ์์๋๋ฐ class๋ผ๋ ๊ฐ์ฒด๋ฅผ ์๊ฐ๋ชปํ๋ค.
์ํผ gpt ์์ด๋ ๊น๋ํ ํฌ๋กค๋ง์ด ์ด๋ ค์ ์๊ฑฐ๋ค ใ
๊ทธ๋๋ ์ด๋ ต๊ฒ ํฌ๋กค๋ง ํด์์ผ๋๊น ๋ค์ ํ๋ก์ ํธ๋ ์ข ๋ ์์ํ๊ฒ ํ ๊ฑฐ ๊ฐ๋ค ^^
์ญ์ ํ๋ค๊ฒ ๋ฐฐ์์ผ ๋จธ๋ฆฌ์ ์ค๋ ๋จ๋๋ฒ ๐
์ถ์ฒ : ๋ฉ์์ด์ฌ์์ฒ๋ผ, ๊ฐ์์๋