์นํฌ๋กค๋ง 1ํ์์ requests์ bs4์ ์ด์ฉํ์ฌ ๊ฐ๋จํ ์น์ฌ์ดํธ ํฌ๋กค๋ง ๋ฐฉ๋ฒ์ ๋ํด ๋ค๋ค์ต๋๋ค.
[์นํฌ๋กค๋ง 1ํ] requests์ bs4๋ฅผ ํ์ฉํ ๋ ์ํผ ๋ชฉ๋ก ํฌ๋กค๋ง
ํ์ฌ์์ ํน์ ๊ฐ์ธ ํ๋ก์ ํธ๋ฅผ ์งํํ ๋ ๋ฐ์ดํฐ๋ฅผ ํฌ๋กค๋งํด ์ค๋ ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์์ต๋๋ค. ์ ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ๋ค๋์ง, ์ต๊ทผ 2๋ ์น์ ๊ฒฝ์ ๋ด์ค ๊ธฐ์ฌ๋ฅผ ๋ชจ์๋ค๋์ง ๋ฑ ์น์ฌ์ดํธ์์ ๋ฐ์ดํฐ๋ฅผ
jakely.tistory.com
์ด๋ฒ ํฌ์คํธ์์๋ ์ข ๋ ๊ตฌ์กฐ๊ฐ ๋ณต์กํ๊ณ Javascript๋ฅผ ํฌํจํ ๋ ์ด๋ ค์ด ์น์ฌ์ดํธ ๊ตฌ์กฐ๋ฅผ selenium webdriver๋ฅผ ํ์ฉํด์ ํฌ๋กค๋งํด๋ณด๊ฒ ์ต๋๋ค.
์ต๊ทผ์ ์นํ ์๋ฒ์ง๊ป์ ์ ๊ฒ ์ฌ๋ฌด์ฉ์ผ๋ก ์ ๋ ดํ ๋ ธํธ๋ถ์ ์์๋ด๋ฌ๋ผ๊ณ ํ์ จ์ต๋๋ค. ๊ทธ๋์ ์ค๋์ ์ ๊ฐ ์ปดํจํฐ ๋ฐ IT ๊ด๋ จ ์ ํ์ ๊ตฌ๋งคํ ๋ ์ ์ฉํ๋ ๋ค๋์ ์น์ฌ์ดํธ์์ 20~40๋ง์ ๋์ ์ ๋ ดํ ๋ ธํธ๋ถ ๋ชฉ๋ก์ ํฌ๋กค๋งํด ๋ณด๊ฒ ์ต๋๋ค.
์ฌ์ ์ค๋น
selenium ํจํค์ง์ webdriver ๋ชจ๋์ ์น๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ ์คํํ๋, python์ผ๋ก ๋ช ๋ น์ ํ ์ ์๋๋ก ๋์์ฃผ๋ ํจํค์ง์ ๋๋ค. ํ์ด์ดํญ์ค, ํฌ๋กฌ ๋ฑ ๋ค์ํ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ฐ, ์ด๋ฒ ํฌ์คํธ์์๋ ํฌ๋กฌ์ ์ฌ์ฉํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐ์ ์ webdriver์ ์คํํ๊ธฐ ์ํ ํ๋ก๊ทธ๋จ์ ๋ค์ด๋ก๋ํ์ฌ์ผ ํฉ๋๋ค. ์๋ ์น์ฌ์ดํธ์์ ํฌ๋กฌ ๋ฒ์ ์ ๋ง๋ chromedriver.exe๋ฅผ ๋ค์ด๋ก๋ํ์๋ฉด ๋ฉ๋๋ค. (ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ๋ํ ์ค์น๊ฐ ๋์ด์์ด์ผ ํฉ๋๋ค)
Chrome ์น๋ธ๋ผ์ฐ์
๋์ฑ ์ค๋งํธํด์ง Google๋ก ๋ ๊ฐํธํ๊ณ ์์ ํ๊ณ ๋น ๋ฅด๊ฒ.
www.google.com
ChromeDriver - WebDriver for Chrome - Downloads
Current Releases If you are using Chrome version 110, please download ChromeDriver 110.0.5481.30 If you are using Chrome version 109, please download ChromeDriver 109.0.5414.74 If you are using Chrome version 108, please download ChromeDriver 108.0.5359.71
chromedriver.chromium.org
๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง์ผ๋ก selenium ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด ์ฃผ์๋ฉด ๋ชจ๋ ์ค๋น๋ ๋์ด ๋ฉ๋๋ค.
pip install selenium
์์ค์ฝ๋
[chromedriver๋ก ์๋ํ๋ ์น๋ธ๋ผ์ฐ์ ํ์ฑํ]
์ฌ์ ์ค๋น ๋ ๋ค์ด๋ก๋ํ chromedriver์ ๊ฒฝ๋ก๋ฅผ ์๋์ ์ ๋ ฅํ๊ณ ์ฝ๋๋ฅผ ์คํํ๋ฉด ์๋ํ๋ ์น ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ ์ด ๋๋ฉด์ ๋ค๋์ ์น์ฌ์ดํธ๋ก ์ด๋ํฉ๋๋ค.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
import time
import pandas as pd
driver_path = '/๋์ ๊ฒฝ๋ก/chromedriver.exe'
driver = webdriver.Chrome(driver_path)
url = 'https://www.danawa.com/'
driver.get(url)
[๊ฒ์ ์ค์ ๋ฐ ํฌ๋กค๋ง ์ค๋น]
์๋์ ์ฝ๋๋ฅผ ์ ๋ ฅํ๋ฉด ๋ค๋์ ์น์ฌ์ดํธ ๊ฒ์์ฐฝ์ "๋ ธํธ๋ถ" ๊ฒ์์ด๋ก ๊ฒ์์ ํ ๋ค, ์๋ ํํฐ์ ์ต์๊ธ์ก 20๋ง ์, ์ต๋๊ธ์ก 40๋ง ์์ ์ค์ ํ๊ฒ ๋ฉ๋๋ค. ๋ํ ํ ๋ฒ์ ๋ณด์ด๋ ๊ฒ์๊ฒฐ๊ณผ๋ฅผ 30๊ฐ์์ 90๊ฐ๋ก ๋ณ๊ฒฝํ์ฌ ํฌ๋กค๋งํ ๋ ํ์ด์ง ์๋ฅผ ์กฐ๊ธ ๋ ์ ๊ฒ ๋๊ธธ ์ ์๊ฒ ์ค์ ํฉ๋๋ค.
## ์น ๋ธ๋ผ์ฐ์ง ์๋ํ
def search_item(product, lower, upper):
#๊ฒ์์ด ์
๋ ฅ
driver.find_element(By.CLASS_NAME, 'search__box').find_element(By.TAG_NAME, 'input').send_keys(product)
#๊ฒ์ ๋ฒํผ
driver.find_element(By.XPATH, '//*[@id="srchFRM_TOP"]/fieldset/div[1]/button').click()
#์ต์ ๊ฐ๊ฒฉ ์ค์
driver.find_element(By.XPATH, '//*[@id="priceRangeMinPrice"]').send_keys(lower)
#์ต๊ณ ๊ฐ๊ฒฉ ์ค์
driver.find_element(By.XPATH, '//*[@id="priceRangeMaxPrice"]').send_keys(upper)
#๊ฐ๊ฒฉ ํํฐ ๊ฒ์ ๋ฒํผ
driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[3]/div[2]/div[1]/button').click()
product = '๋
ธํธ๋ถ'
lower = '200000' #20๋ง์
upper = '400000' #40๋ง์
search_item(product, lower, upper)
# ๊ฒ์๊ฒฐ๊ณผ ๋ก๋ฉ ๊ธฐ๋ค๋ ค์ฃผ๊ธฐ (2์ด)
time.sleep(2)
# ๊ฒ์๊ฒฐ๊ณผ 90๊ฐ์ฉ ๋ณด๊ธฐ
driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[2]/div[2]/div[2]/select').click()
driver.find_element(By.CSS_SELECTOR, '#productListArea > div.prod_list_opts > div.view_opt > div.view_item.view_qnt > select > option:nth-child(3)').click()
# ๊ฒ์๊ฒฐ๊ณผ ๋ก๋ฉ ๊ธฐ๋ค๋ ค์ฃผ๊ธฐ (2์ด)
time.sleep(2)
[๋ฐ์ดํฐ ํฌ๋กค๋ง]
webdriver๋ก ํฌ๋กค๋งํ ๋ ์ํ๋ ์ ๋ณด๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ์ด ๋ค์ํฉ๋๋ค. (์์ธ ๊ฐ์ด๋๋ ๊ณต์ Documentation ์ฐธ๊ณ )
- TAG_NAME
- CSS_SELECTOR
- ID
- XPATH
- LINK_TEXT
- PARTIAL_LINK_TEXT
- NAME
- CLASS_NAME
๋ธ๋ผ์ฐ์ ์ html ์ฝ๋๋ฅผ ์ดํผ๋ฉด์ ์ด๋ป๊ฒ ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๊ฒ ์ธ์ง ๊ฐ์ ๊ธธ๋ฌ์ผ ํฉ๋๋ค.
์๋์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๊ฐ๋ฐ์๋๊ตฌ์ ์์ค๊ฒ์ฌ๋ฅผ ํ์ฉํด์ ์ ํ ๋ชฉ๋ก์ด ์์นํ HTML ํ๊ทธ๊ฐ <ul class='product_list'>์ธ ๊ฒ์ ํ์ธํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น HTML์ ์์น๋ฅผ ์ฐพ์ ๋๋ `find_element(By.CLASS_NAME, 'product_list')` ์ ๊ฐ์ด class name์ ์ฌ์ฉํ์ต๋๋ค.
์ต๋ํ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ ์์๋ค์ ์ฐพ์ผ๋ ค๊ณ ๋ ธ๋ ฅํ์ต๋๋ค. ์ ๊ฐ ์ด๋ค ๋ฐฉ๋ฒ์ผ๋ก ์ ํ๋ช , ์ ํ๊ฐ๊ฒฉ, ์ ํ์ค๋ช , ๋ค์ ํ์ด์ง๋ก ๋์ด๊ฐ๋ ๋ฒํผ ๋ฑ์ ์ฐพ์๋์ง ์ฝ๋๋ก ํ๋ฒ ๋ณด์๊ณ , ํด๋น ๋ถ๋ถ์ HTML์ ๋์กฐํด ๋ณด์๋ฉด ์ดํด๊ฐ ์์ํ ๊ฒ์ ๋๋ค.
## ๊ฒ์๊ฒฐ๊ณผ ๋ฐ์ดํฐ ํฌ๋กค๋ง
result_data = []
# ๊ฐ ์์ดํ
์ ์ ๋ณด ์ฐพ์์ ์ ์ฅ
def get_product_info(e):
#์ ํ๋ช
product_name = e.find_element(By.CLASS_NAME, 'prod_name').find_element(By.TAG_NAME, 'a').text.strip()
#์ ํ๋ช
์ ๋ถ์ ์ ํ๋งํฌ
product_link = e.find_element(By.CLASS_NAME, 'prod_name').find_element(By.TAG_NAME, 'a').get_attribute('href')
#์ ํ์ค๋ช
๋ฐ ์คํ
product_spec = e.find_element(By.CLASS_NAME, 'prod_spec_set').text.strip()
#์ ํ ๊ฐ๊ฒฉ๋ฆฌ์คํธ
product_pricelist = e.find_element(By.CLASS_NAME, 'prod_pricelist').find_elements(By.TAG_NAME, 'li')
#์ ํ ๊ฐ๊ฒฉ๋ค
product_prices = [pp.find_element(By.CLASS_NAME, 'price_sect').text.split(" ")[0].strip() for pp in product_pricelist]
#์ ํ ๊ฐ๊ฒฉ ์์ ๋ฉ๋ชจ๋ฆฌ ์ ๋ณด
product_mems = [pp.find_element(By.CLASS_NAME, 'memory_sect').text.strip() for pp in product_pricelist]
#์์์ ์ฐพ์ ๋ฐ์ดํฐ ๋ฆฌ์คํธ ํํ๋ก ํฉ์น๊ธฐ
data = list(zip([product_name]*len(product_prices),
[product_spec]*len(product_prices),
[product_link]*len(product_prices),
product_prices,
product_mems))
return data
# ๊ฒ์๋ ํ์ด์ง์๋ฅผ ๋๊ธฐ๋ฉฐ ํฌ๋กค๋ง ์งํ
for i in range(2,9999):
# ๊ฒ์๋ ์์ดํ
๋ฆฌ์คํธ
result_list = WebDriverWait(driver, 10).until(
lambda x: x.find_element(By.CLASS_NAME,
'product_list').find_elements(By.XPATH, "//li[starts-with(@id, 'productItem')]"))
for r in result_list:
result_data.extend(get_product_info(r))
time.sleep(1) # 1์ด ์ฌ์ ์ฃผ๊ธฐ
if (i-1)%10 == 0:
try: #10n ํ์ด์ง์์ ๋์ด๊ฐ๋ ๊ฒ์๊ฒฐ๊ณผ ์ผ๋
driver.find_element(By.CLASS_NAME,'nav_next').click() #๋ค์๋ฒํผ ํด๋ฆญ
print(f'Data Collecting on Page {i}')
except:
print('No More Pages')
break
else:
try: #๋ค์ ํ์ด์ง๋ก ๋์ด๊ฐ๊ธฐ
driver.find_element(By.CLASS_NAME,'number_wrap').find_element(By.PARTIAL_LINK_TEXT, f'{i}').click()
print(f'Data Collecting on Page {i}')
except:
print('No More Pages')
break
time.sleep(5) # ํ์ด์ง ๋ก๋ฉ๊น์ง 5์ด ์ ๋ ๊ธฐ๋ค๋ ค์ฃผ๊ธฐ
# pandas dataframe์ผ๋ก ์ต์ข
์ ์ผ๋ก ์ ์ฅ
df = pd.DataFrame(result_data, columns = ['์ ํ๋ช
','์คํ','๋งํฌ','๊ฐ๊ฒฉ','๋ฉ๋ชจ๋ฆฌ/๋น๊ณ '])
df.to_csv('๋
ธํธ๋ถ์ ํ๋ฆฌ์คํธ.tsv', sep='\t', encoding='cp949', quotechar='"')
๊ฒฐ๊ณผ
๋ง๋ฌด๋ฆฌ ๋ฐ ์์ค์ฝ๋ ์ ์ฒด
์ด๋ฒ ํฌ์คํธ์์๋ selenium ๋ฐ webdriver๋ฅผ ํ์ฉํ์ฌ ์น ํฌ๋กค๋ง์ ํด๋ดค์ต๋๋ค. ์์ ์ ์ฌ์ฉํ๋ selenium๊ณผ ํจํค์ง๊ฐ ์กฐ๊ธ ๋ฐ๋์ด์ ์ฌ์ฉ๋ฒ์ ์ตํ๋๋ฐ ํ ์๊ฐ ์ ๋ ์์๋ฅผ ํ์ต๋๋ค. ์ญ์ ๋ฐฐ์์๋ ๋์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค ใ ใ ...
๊ถ๊ธํ์ ์ ์ด ์๊ฑฐ๋ ์๋ชป๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ๋๊ธ ๋ถํ๋๋ฆฌ๊ฒ ์ต๋๋ค!
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
import time
import pandas as pd
driver_path = '/Users/jake1/Desktop/chromedriver.exe'
driver = webdriver.Chrome(driver_path)
url = 'https://www.danawa.com/'
driver.get(url)
## ์น ๋ธ๋ผ์ฐ์ง ์๋ํ
def search_item(product, lower, upper):
#๊ฒ์์ด ์
๋ ฅ
driver.find_element(By.CLASS_NAME, 'search__box').find_element(By.TAG_NAME, 'input').send_keys(product)
#๊ฒ์ ๋ฒํผ
driver.find_element(By.XPATH, '//*[@id="srchFRM_TOP"]/fieldset/div[1]/button').click()
#์ต์ ๊ฐ๊ฒฉ ์ค์
driver.find_element(By.XPATH, '//*[@id="priceRangeMinPrice"]').send_keys(lower)
#์ต๊ณ ๊ฐ๊ฒฉ ์ค์
driver.find_element(By.XPATH, '//*[@id="priceRangeMaxPrice"]').send_keys(upper)
#๊ฐ๊ฒฉ ํํฐ ๊ฒ์ ๋ฒํผ
driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[3]/div[2]/div[1]/button').click()
product = '๋
ธํธ๋ถ'
lower = '200000' #20๋ง์
upper = '400000' #40๋ง์
search_item(product, lower, upper)
# ๊ฒ์๊ฒฐ๊ณผ ๋ก๋ฉ ๊ธฐ๋ค๋ ค์ฃผ๊ธฐ (2์ด)
time.sleep(2)
# ๊ฒ์๊ฒฐ๊ณผ 90๊ฐ์ฉ ๋ณด๊ธฐ
driver.find_element(By.XPATH, '//*[@id="productListArea"]/div[2]/div[2]/div[2]/select').click()
driver.find_element(By.CSS_SELECTOR, '#productListArea > div.prod_list_opts > div.view_opt > div.view_item.view_qnt > select > option:nth-child(3)').click()
# ๊ฒ์๊ฒฐ๊ณผ ๋ก๋ฉ ๊ธฐ๋ค๋ ค์ฃผ๊ธฐ (2์ด)
time.sleep(2)
## ๊ฒ์๊ฒฐ๊ณผ ๋ฐ์ดํฐ ํฌ๋กค๋ง
result_data = []
# ๊ฐ ์์ดํ
์ ์ ๋ณด ์ฐพ์์ ์ ์ฅ
def get_product_info(e):
#์ ํ๋ช
product_name = e.find_element(By.CLASS_NAME, 'prod_name').find_element(By.TAG_NAME, 'a').text.strip()
#์ ํ๋ช
์ ๋ถ์ ์ ํ๋งํฌ
product_link = e.find_element(By.CLASS_NAME, 'prod_name').find_element(By.TAG_NAME, 'a').get_attribute('href')
#์ ํ์ค๋ช
๋ฐ ์คํ
product_spec = e.find_element(By.CLASS_NAME, 'prod_spec_set').text.strip()
#์ ํ ๊ฐ๊ฒฉ๋ฆฌ์คํธ
product_pricelist = e.find_element(By.CLASS_NAME, 'prod_pricelist').find_elements(By.TAG_NAME, 'li')
#์ ํ ๊ฐ๊ฒฉ๋ค
product_prices = [pp.find_element(By.CLASS_NAME, 'price_sect').text.split(" ")[0].strip() for pp in product_pricelist]
#์ ํ ๊ฐ๊ฒฉ ์์ ๋ฉ๋ชจ๋ฆฌ ์ ๋ณด
product_mems = [pp.find_element(By.CLASS_NAME, 'memory_sect').text.strip() for pp in product_pricelist]
#์์์ ์ฐพ์ ๋ฐ์ดํฐ ๋ฆฌ์คํธ ํํ๋ก ํฉ์น๊ธฐ
data = list(zip([product_name]*len(product_prices),
[product_spec]*len(product_prices),
[product_link]*len(product_prices),
product_prices,
product_mems))
return data
# ๊ฒ์๋ ํ์ด์ง์๋ฅผ ๋๊ธฐ๋ฉฐ ํฌ๋กค๋ง ์งํ
for i in range(2,9999):
# ๊ฒ์๋ ์์ดํ
๋ฆฌ์คํธ
result_list = WebDriverWait(driver, 10).until(
lambda x: x.find_element(By.CLASS_NAME,
'product_list').find_elements(By.XPATH, "//li[starts-with(@id, 'productItem')]"))
for r in result_list:
result_data.extend(get_product_info(r))
time.sleep(1) # 1์ด ์ฌ์ ์ฃผ๊ธฐ
if (i-1)%10 == 0:
try: #10n ํ์ด์ง์์ ๋์ด๊ฐ๋ ๊ฒ์๊ฒฐ๊ณผ ์ผ๋
driver.find_element(By.CLASS_NAME,'nav_next').click() #๋ค์๋ฒํผ ํด๋ฆญ
print(f'Data Collecting on Page {i}')
except:
print('No More Pages')
break
else:
try: #๋ค์ ํ์ด์ง๋ก ๋์ด๊ฐ๊ธฐ
driver.find_element(By.CLASS_NAME,'number_wrap').find_element(By.PARTIAL_LINK_TEXT, f'{i}').click()
print(f'Data Collecting on Page {i}')
except:
print('No More Pages')
break
time.sleep(5) # ํ์ด์ง ๋ก๋ฉ๊น์ง 5์ด ์ ๋ ๊ธฐ๋ค๋ ค์ฃผ๊ธฐ
# pandas dataframe์ผ๋ก ์ต์ข
์ ์ผ๋ก ์ ์ฅ
df = pd.DataFrame(result_data, columns = ['์ ํ๋ช
','์คํ','๋งํฌ','๊ฐ๊ฒฉ','๋ฉ๋ชจ๋ฆฌ/๋น๊ณ '])
df.to_csv('๋
ธํธ๋ถ์ ํ๋ฆฌ์คํธ.tsv', sep='\t', encoding='cp949', quotechar='"')
'๐ป ITยท๊ธฐ์ ยทํต๊ณ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Python์ผ๋ก ์ฃผ์ฌ์ ๊ฒ์ ๋ง๋ค๊ธฐ (0) | 2023.02.03 |
---|---|
[NLP] ์ ๊ทํํ์์ ํ์ฉํ ์ ์ฒ๋ฆฌ ๋ฐ ๋ฐ์ดํฐ ์ถ์ถ (0) | 2023.01.29 |
๋ฉํฐํ๋ก์ธ์ฑ (Multiprocessing) w/ Python (0) | 2023.01.26 |
[API] DALLยทE 2 Python์ผ๋ก ์ฌ์ฉํด๋ณด๊ธฐ (3) | 2023.01.25 |
Python์ผ๋ก ๋ฉ์ผ ๋ณด๋ด๊ธฐ [@gmail] (3) | 2023.01.21 |
๋๊ธ