๐ ํฌ๋กค๋ง ๋ถ์ ํ๋ก์ ํธ (4) - ์ฝ๋ ์ผ ๊ธฐ์ฐจํ ํฌ๋กค๋ง
์ฝ๋ ์ผ ๊ธฐ์ฐจํ ํฌ๋กค๋ง
robots.txt๋ฅผ ํตํด ํด๋น ์ฌ์ดํธ๋ ํฌ๋กค๋ง์ด ๊ฐ๋ฅํจ์ ํ์ธํ์ต๋๋ค.
ํ์ง๋ง ํฌ๋กค๋ง์ ๊ณผ๋ํ๊ฒ ํ๋ ๊ฒ์ ์๋ฒ์ ๋ถ๋ด์ ์ค ์ ์๊ธฐ์,
ํ์ํ ๋ฐ์ดํฐ๋ง ์ ์ํ๊ณ ๊ทธ ๋ถ๋ถ๋ง ์์ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
import requests
from bs4 import BeautifulSoup
import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
# selenium ์น ๋๋ผ์ด๋ฒ ์๋น์ค ์ค์
service=Service(executable_path=ChromeDriverManager().install())
url='https://www.letskorail.com/ebizprd/EbizPrdTicketPr21111_i1.do?&txtGoAbrdDt=20241118&txtGoHour=071600&selGoYear=2024&selGoMonth=11&selGoDay=18&selGoHour=00&txtGoPage=2&txtGoStartCode=0001&txtGoStart=%EC%84%9C%EC%9A%B8&txtGoEndCode=0020&txtGoEnd=%EB%B6%80%EC%82%B0&selGoTrain=05&selGoRoom=&selGoRoom1=&txtGoTrnNo=&useSeatFlg=&useServiceFlg=&selGoSeat=&selGoService=&txtPnrNo=&hidRsvChgNo=&hidStlFlg=&radJobId=1&SeandYo=&hidRsvTpCd=03&selGoSeat1=015&selGoSeat2=&txtPsgCnt1=1&txtPsgCnt2=0&txtMenuId=11&txtPsgFlg_1=1&txtPsgFlg_2=0&txtPsgFlg_3=0&txtPsgFlg_4=0&txtPsgFlg_5=0&txtPsgFlg_8=0&chkCpn=N&txtSeatAttCd_4=015&txtSeatAttCd_3=000&txtSeatAttCd_2=000&txtGoStartCode2=&txtGoEndCode2=&hidDiscount=&hidEasyTalk=&adjcCheckYn=N'
driver=webdriver.Chrome(service=service)
driver.get(url)
wait=WebDriverWait(driver,10) # ์น ํ์ด์ง๊ฐ ๋ก๋๋ ๋๊น์ง, ์ต๋ 10์ด๊ฐ ๊ธฐ๋ค๋ฆฐ๋ค๋ ๋ป
# Selenium์ผ๋ก javascript ์คํ๋ ํ์ ํ์ด์ง ์์ค๋ฅผ ๊ฐ์ ธ์ด
html=driver.page_source
driver.quit()
# BeautifulSoup ์ผ๋ก ํ์ฑ
soup = BeautifulSoup(html,'html.parser')
table_contents=soup.find('tbody')
table_contents
๊ฒฐ๊ณผ๋ฌผ์ด ๊ต์ฅํ ๋ณต์กํ๊ฒ ๋์ด ์์ต๋๋ค.
ํด๋น ๋ด์ฉ๋ค์ ์ฒ๋ฆฌํด์ ๋ณด๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
# ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋น ๋ฆฌ์คํธ ์์ฑ
data_rows=[]
# table_contents์ ๊ฐ tr ํ(ํ)์ ๋ํด์ ๋ฐ๋ณตํ๋ฉด์, td ๋ฐ์ดํฐ๋ฅผ ์ปฌ๋ผ์ ๋ด๊ธฐ
for tr in table_contents.find_all('tr'):
# ๊ฐ ์ด์ ํด๋นํ๋ ๋ฐ์ดํฐ ์ถ์ถ
data=[]
for td in tr.find_all('td'):
text=td.get_text(strip=True)
# ์ด์ ๋ฐ์ดํฐ ์ถ๊ฐ
data.append(text)
#๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ถ๊ฐ
data_rows.append(data)
# ๋ฐ์ดํฐ ํ๋ ์ ์์ฑ
# column ์ด๋ฆ
columns=[
'๊ตฌ๋ถ','์ด์ฐจ๋ฒํธ','์ถ๋ฐ์๊ฐ','๋์ฐฉ์๊ฐ','ํน์ค/์ฐ๋ฑ์ค','์ผ๋ฐ์ค','์ ์',
'์์ ์/์
์','์ธํฐ๋ทํน๊ฐ(๋ฉค๋ฒ์ญํํ)','์์ฝ๋๊ธฐ','์ ์ฐจ์ญ(๊ฒฝ์ )','์ฐจ๋์ ํ/ํธ์ฑ์ ๋ณด','์ด์์๊ธ','์์์๊ฐ'
]
df=pd.DataFrame(data_rows,columns=columns)
df
์ด๋ ๊ฒ ํน์ค/์ฐ๋ฑ์ค๊ณผ ์ผ๋ฐ์ค ์นธ ๋ฑ์ด ๋น์ด ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๊ฐ๋ฐ์๋๊ตฌ๋ฅผ ์ด์ด๋ณด์๋ฉด ๊ทธ ์ด์ ๋ฅผ ์ ์ ์์ต๋๋ค.
ํด๋น ์นธ์ด ์ด๋ฏธ์ง๋ก ๋์ด์๊ณ alt="์์ฝํ๊ธฐ"๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
# ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋น ๋ฆฌ์คํธ ์์ฑ
data_rows=[]
# table_contents์ ๊ฐ tr ํ(ํ)์ ๋ํด์ ๋ฐ๋ณตํ๋ฉด์, td ๋ฐ์ดํฐ๋ฅผ ์ปฌ๋ผ์ ๋ด๊ธฐ
for tr in table_contents.find_all('tr'):
# ๊ฐ ์ด์ ํด๋นํ๋ ๋ฐ์ดํฐ ์ถ์ถ
data=[]
for td in tr.find_all('td'):
# td์์ img ํ๊ทธ๊ฐ ์๋์ง ํ์ธ, alt ์์ฑ ์ถ์ถ
img_tag=td.find('img')
#img_tage๊ฐ ์กด์ฌํ๋ฉด
if img_tag:
text=img_tag.get('alt','')
else:
text=td.get_text(strip=True)
# ์ด์ ๋ฐ์ดํฐ ์ถ๊ฐ
data.append(text)
#๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ถ๊ฐ
data_rows.append(data)
# ๋ฐ์ดํฐ ํ๋ ์ ์์ฑ
# column ์ด๋ฆ
columns=[
'๊ตฌ๋ถ','์ด์ฐจ๋ฒํธ','์ถ๋ฐ์๊ฐ','๋์ฐฉ์๊ฐ','ํน์ค/์ฐ๋ฑ์ค','์ผ๋ฐ์ค','์ ์',
'์์ ์/์
์','์ธํฐ๋ทํน๊ฐ(๋ฉค๋ฒ์ญํํ)','์์ฝ๋๊ธฐ','์ ์ฐจ์ญ(๊ฒฝ์ )','์ฐจ๋์ ํ/ํธ์ฑ์ ๋ณด','์ด์์๊ธ','์์์๊ฐ'
]
df=pd.DataFrame(data_rows,columns=columns)
df
์ด๋ฒ์ ํด๋น ์ ๋ณด๋ค์ด ๋ชจ๋ ์ ๋๋ก ๋ค์ด๊ฐ์ต๋๋ค.
์ฌ๋ฌ ํ์ด์ง ๊ธฐ์ฐจ ์๋งค ํฌ๋กค๋ง
๊ฐ๋ฐ์๋๊ตฌ๋ฅผ ์ฌ์ ๋ค์์ ๋ค์์ ๋๋ฅธ ๋ค์์ ํด๋น์ค์ ์ฐํด๋ฆญ ํด์ฃผ์ธ์
๊ทธ๋ผ Copy > Copy Xpath๋ฅผ ํด๋ฆญํด์ฃผ์ธ์
Xpath์ ๋ค์ ๋ฒํผ์ ํด๋ฆญํ์ฌ, ์ ์๋ ํ์ด์ง์ url์ ๊ฐ์ ธ์ค๋ ๊ฒ ๊น์ง ์ํํ๊ฒ ์ต๋๋ค.
# ํ์ด์ง๋ค์ด์
: ์ค๋ฅ๊ฐ ๋ฐ์ํ ๋ฒ์ ผ
# URL๊น์ง ํฌํจ๋ ๋ฐ์ดํฐ ํ๋ ์ ์์ฑ
# Xpath, '๋ค์' ๋ฒํผ ํด๋ฆญ, ์ ์๋ ํ์ด์ง์ url์ ๊ฐ์ ธ์ค๋ ๊ฒ ๊น์ง ์ํ
from selenium.webdriver.common.by import By
import time
# selenium ์น ๋๋ผ์ด๋ฒ ์๋น์ค ์ค์
service=Service(executable_path=ChromeDriverManager().install())
driver=webdriver.Chrome(service=service)
url='https://www.letskorail.com/ebizprd/EbizPrdTicketPr21111_i1.do?&txtGoAbrdDt=20241020&txtGoHour=065700&selGoYear=2024&selGoMonth=10&selGoDay=20&selGoHour=00&txtGoPage=2&txtGoStartCode=0001&txtGoStart=%EC%84%9C%EC%9A%B8&txtGoEndCode=0020&txtGoEnd=%EB%B6%80%EC%82%B0&selGoTrain=05&selGoRoom=&selGoRoom1=&txtGoTrnNo=&useSeatFlg=&useServiceFlg=&selGoSeat=&selGoService=&txtPnrNo=&hidRsvChgNo=&hidStlFlg=&radJobId=1&SeandYo=&hidRsvTpCd=03&selGoSeat1=015&selGoSeat2=&txtPsgCnt1=1&txtPsgCnt2=0&txtMenuId=11&txtPsgFlg_1=1&txtPsgFlg_2=0&txtPsgFlg_3=0&txtPsgFlg_4=0&txtPsgFlg_5=0&txtPsgFlg_8=0&chkCpn=N&txtSeatAttCd_4=015&txtSeatAttCd_3=000&txtSeatAttCd_2=000&txtGoStartCode2=&txtGoEndCode2=&hidDiscount=&hidEasyTalk=&adjcCheckYn=N'
# ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋น ๋ฆฌ์คํธ ์์ฑ
data_rows=[]
# 5๋ฒ ๋ฐ๋ณต
for _ in range(5):
#Selenium ์น ๋๋ผ์ด๋ฒ ์คํ
driver.get(url) # ๊ฐฑ์ ๋ url ๋ฐ๋ณต์ ์ผ๋ก ์ ๋ฌ
time.sleep(2) # 2์ด ๋๊ธฐ
# Selenium์ผ๋ก javascript ์คํ๋ ํ์ ํ์ด์ง ์์ค๋ฅผ ๊ฐ์ ธ์ด
html=driver.page_source
# BeautifulSoup ์ผ๋ก ํ์ฑ
soup = BeautifulSoup(html,'html.parser')
#table_contents๋ก ํ์ํ ๋ถ๋ถ๋ง ์ ์
table_contents=soup.find('tbody')
# table_contents์ ๊ฐ tr ํ(ํ)์ ๋ํด์ ๋ฐ๋ณตํ๋ฉด์, td ๋ฐ์ดํฐ๋ฅผ ์ปฌ๋ผ์ ๋ด๊ธฐ
for tr in table_contents.find_all('tr'):
# ๊ฐ ์ด์ ํด๋นํ๋ ๋ฐ์ดํฐ ์ถ์ถ
data=[]
for td in tr.find_all('td'):
# td์์ img ํ๊ทธ๊ฐ ์๋์ง ํ์ธ, alt ์์ฑ ์ถ์ถ
img_tag=td.find('img')
#img_tage๊ฐ ์กด์ฌํ๋ฉด
if img_tag:
text=img_tag.get('alt','')
else:
text=td.get_text(strip=True)
# ์ด์ ๋ฐ์ดํฐ ์ถ๊ฐ
data.append(text)
#data, ์ฆ ๋ฐฉ๊ธ๊น์ง td ํ๊ทธ๋ค์ด ์์ธ data ๋ฆฌ์คํธ์ url๋ ํ๋ ๋ ์ถ๊ฐ
data.append(url)
#๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ถ๊ฐ
data_rows.append(data)
#'๋ค์' ๋ฒํผ ์ฐพ์์ ํด๋ฆญ
try:
next_button=driver.find_element(By.XPATH,'//*[@id="divResult"]/table[2]/tbody/tr/td/a[2]') # copy XPATH
except: # ์ด์ ๋ฒํผ์ด ์์ด์ ์์น๊ฐ 2๋ฒ์งธ๊ฐ ์๋๋ผ 1๋ฒ์งธ aํ๊ทธ๋ก ๋ณ๊ฒฝ๋
next_button=driver.find_element(By.XPATH,'//*[@id="divResult"]/table[2]/tbody/tr/td/a[1]') # copy XPATH
next_button.click()
time.sleep(2)
# ๋ค์ ๋ฒํผ ๋๋ฅด๊ณ ์ด๋๋ ํ์ด์ง์ ํ์ฌ url์ ๋ค์ url ๋ณ์์ ๋ฃ์ด์ ๊ฐฑ์
url=driver.current_url
driver.quit()
# ๋ฐ์ดํฐ ํ๋ ์ ์์ฑ
# column ์ด๋ฆ
columns=[
'๊ตฌ๋ถ','์ด์ฐจ๋ฒํธ','์ถ๋ฐ์๊ฐ','๋์ฐฉ์๊ฐ','ํน์ค/์ฐ๋ฑ์ค','์ผ๋ฐ์ค','์ ์',
'์์ ์/์
์','์ธํฐ๋ทํน๊ฐ(๋ฉค๋ฒ์ญํํ)','์์ฝ๋๊ธฐ','์ ์ฐจ์ญ(๊ฒฝ์ )','์ฐจ๋์ ํ/ํธ์ฑ์ ๋ณด','์ด์์๊ธ','์์์๊ฐ','url'
]
df=pd.DataFrame(data_rows,columns=columns)
df
์ด๋ ๊ฒ ์ ์์ ์ผ๋ก ํฌ๋กค๋ง ๋ฉ๋๋ค.
ํ์ง๋ง 9,10๋ฒ ์ธ๋ฑ์ค์ ๋ด์ฉ์ด ๊ฒน์น๊ฒ ๋ฉ๋๋ค.
๊ทธ ์ด์ ๋ ์น์ฌ์ดํธ ์์ฒด์์ ๋ง์ง๋ง ์์ฝ๋ด์ฉ๊ณผ ๊ทธ ๋ค์ํ์ด์ง ์ฒซ ์์ฝ๋ด์ฉ์ด ๋์ผํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
df=df.drop_duplicates(subset=['์ถ๋ฐ์๊ฐ'],keep='first')
df
ํด๋น ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๋ฐ์๊ฐ์ด ๊ฒน์น๋ ๊ฒ์ค ์ฒซ๋ฒ์งธ๊ป๋ง ๋จ๊ธฐ๊ณ ๋๋จธ์ง๋ ๋ค ์ ๊ฑฐ๋ฅผ ํด์ค๋๋ค.
fast_reserve_df=df[df['์ผ๋ฐ์ค']=='์์ฝํ๊ธฐ']
# ์ธ๋ฑ์ค ๋ฆฌ์
fast_reserve_df=fast_reserve_df.reset_index(drop=True)
fast_reserve_df.head()
fast_reserve_df.loc[0,'url']
์ ์+์ข์ ์ผ๋ก ๋์ด์๋ ๋ฌถ์ ์ํ์ ์ ์ธํ๊ณ
์ ์์ผ๋ก ๊ฐ ์ ์๊ณ ์์ฝ์ด ๊ฐ๋ฅํ ๊ฐ์ฅ ๋น ๋ฅธ ์ํ์ ์ถ์ถํ ์ ์์ต๋๋ค.
๋ง์ฝ ๊ธฐ์ฐจ๋ฅผ ์์ฃผํ๊ณ ์์ฝ์ ํด์ผํ๋ ์ํฉ์ด๊ณ ํฌ๋กค๋ง์ ํตํด ์ฝ๋๋ฅผ ์๋ํ ํด๋๋ค๋ฉด
ํด๋น ์์ฝ ํ์ด์ง๋ก ๋ฐ๋ก ๊ฐ ์ ์๊ธฐ์ ํจ์จ์ ์ด๊ฒ ๋ฉ๋๋ค!