[๐Ÿ—„Database]Web Crawling

์—ฌ์ฃผ๋งยท2020๋…„ 12์›” 6์ผ
1

WECODE

๋ชฉ๋ก ๋ณด๊ธฐ
10/10

์ด๋ฒˆ์— ๋‚ด๊ฐ€ ํ•˜๋Š”๊ฑด ์ง„์งœ ์ฐ ์›น ํฌ๋กค๋ง์€ ์•„๋‹ˆ๋‹ค. ๊ทธ์ € ๊ธ์–ด์˜ค๋Š”๊ฑธ ๋”ฐ๋ผํ•ด๋ณด๋Š”๊ฒƒ์ด์ง€..
์ˆ˜๋ฐ•์„ ํ•œ๋ฒˆ ๊ฒ‰๋งŒ ํ•ฅ์•„๋ณด๋Š”....์‹์ด๋ž„๊นŒ?ใ…Ž

๊ทธ๋Ÿฐ๋ฐ..ํ•˜๋‹ค๊ฐ€ ์ค‘๋ฐ˜์— ๊นจ๋‹ฌ์€ ์‚ฌ์‹ค... ๋‚˜๋Š” ์ด๋ฏธ ๊ฒฝํ—˜์ž๋‹ค(?)
๋…ธ๋งˆ๋“œ์ฝ”๋” ์›น์Šคํฌ๋ฆฌํผ ๋งŒ๋“ค๊ธฐ

๊ทผ๋ฐ ์ด๊ฑฐ ๋‹ค์Œ๋‹จ๊ณ„์—์„œ 2์ผ ๐Ÿ•๊ณ ์ƒํ•จ

<Web Crawling์ด๋ž€?>

์ž๋™ํ™” ๋ด‡(bot)์ธ ์›น ํฌ๋กค๋Ÿฌ(web crawler)๊ฐ€ ์กฐ์ง์ , ์ž๋™ํ™”๋œ ๋ฐฉ๋ฒ•์— ๋”ฐ๋ผ ๋ณต์ˆ˜ ๊ฐœ์ˆ˜ ์›น ํŽ˜์ด์ง€๋ฅผ ๋ธŒ๋ผ์šฐ์ง• ํ•˜๋Š” ํ–‰์œ„

์˜ค๋Š˜๋‚  ๋ฐ์ดํ„ฐ์‚ฌ์ด์–ธ์Šค์™€ ๋จธ์‹ ๋Ÿฌ๋‹์ด ๋„๋ž˜ํ•˜๋ฉฐ ๋น… ๋ฐ์ดํ„ฐ๊ฐ€ ์ค‘์š”์„ฑ์ด ๋Œ€๋‘๋˜์—ˆ๊ณ , ์ด๋ฅผ ์œ„ํ•ด ์ธํ„ฐ๋„ท์—์„œ ์ •๋ณด๋ฅผ ๊ธ์–ด์˜ค๋Š” ํฌ๋กค๋ง์ด ๋งŽ์ด ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค. (๋ฌผ๋ก  ๊ฐœ์ธ์ ์ธ ํŽธ์˜์„ฑ๊ณผ, ์„œ๋น„์Šค๋ฅผ ์œ„ํ•ด์„œ๋„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋„ ๋งŽ๋‹ค)
ํŒŒ์ด์ฌ์ด ํฌ๋กค๋ง์œผ๋กœ ๊ฐ€์žฅ ์œ ๋ช…ํ•˜๋‹ค๋Š”๋ฐ, ์‹ค์ œ๋ก  ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ๋„ ํฌ๋กค๋ง์€ ๊ฐ€๋Šฅํ•จ(๊ฒ€์ƒ‰์ „๊นŒ์ง„ ํŒŒ์ด์ฌ๋งŒ ๋˜๋Š”์ค„ ์•Œ์•˜๋‹ค)

์ธํ„ฐ๋„ท์„ ํ†ตํ•ด ํฌ๋กค๋ง์„ ๊ฒ€์ƒ‰ํ•˜๋‹ค๋ณด๋ฉด ์›น ์Šคํฌ๋ž˜ํ•‘์ด๋ผ๋Š” ๋น„์Šทํ•œ ๊ฐœ๋…์ด ๋‚˜์˜ค๋‹ˆ ์ด์™• ๋‚˜์˜จ๊น€์— ํ•œ๋ฒˆ ์ •๋ฆฌ๋ฅผ ํ•ด๋‘์ž

์›น ์Šคํฌ๋ž˜ํ•‘(scraping) : ์›น์‚ฌ์ดํŠธ ์ƒ์—์„œ ์›ํ•˜๋Š” ๋ถ€๋ถ„์— ์œ„์น˜ํ•œ ์ •๋ณด๋ฅผ ์ปดํ“จํ„ฐ๋กœ ํ•˜์—ฌ๊ธˆ ์ž๋™์œผ๋กœ ์ถ”์ถœํ•ด ์ˆ˜์ง‘ํ•˜๋Š” ๊ธฐ์ˆ . ๋ณธ์ธ์ด ์›ํ•˜๋Š” ํ˜•ํƒœ๋กœ ๊ฐ€๊ณตํ•˜๋Š”๊ฒƒ.
~ํฌ๋กค๋ง๋„ ์ผ์ข…์˜ ์Šคํฌ๋ž˜ํ•‘๊ธฐ์ˆ ์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.~

์œ„์—์„œ๋„ ๋งํ–ˆ์ง€๋งŒ, ๋ง์ด์•ผ ์›นํฌ๋กค๋ง์ด์ง€
์ž˜ ๋”ฐ์ ธ๋ณด๋ฉด ์›น ์Šคํฌ๋ž˜ํ•‘์ด๋‹ค... ํฌ๊ด„์ ์œผ๋กœ ํ‘œํ˜„ํ•˜์—ฌ ํฌ๋กค๋ง์ด๋ผ๊ณ  ํ•˜๋Š”๊ฒƒ์ผ๋ฟ
๊ทธ๋ž˜๋„ ๊ทธ๊ฒŒ ์–ด๋””๋ƒ ์ด์ œ 3์ฃผ์ฐจ์ธ๋ฐ..!!!
์‹ค์งˆ์ ์ธ ์›นํฌ๋กค๋ง์˜ ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค๊ทธ๋ƒฅ๋ด๋„ ๊ฒ๋‚ด ์–ด๋ ค์šฐ๋‹ˆ.. ์ผ๋‹จ ๋‚˜๋Š” ์กฐ์šฉํžˆ ๋ณด๊ธฐ๋งŒํ•˜๊ณ  ๋„˜์–ด๊ฐ„๋‹ค

์‹œ์ž‘์ „ ๊นจ์•ŒํŒ. Robots.txt๐Ÿค–

์ €์ž‘๊ถŒ๋ฒ•๊ณผ ์ง€์ ์žฌ์‚ฐ์— ๋Œ€ํ•œ ์ค‘์š”์„ฑ์ด ์ฆ๊ฐ€ํ•œ ํ˜„๋Œ€์‚ฌํšŒ์—์„œ, ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์—ด~์‹ฌํžˆ ๋งŒ๋“  ์ž๋ฃŒ๋ฅผ ์—ฐ์Šต์šฉ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๊ฐ€๋Šฅํ• ๊นŒ? ์‚ฌ์ดํŠธ์ฃผ์†Œ์— /robots.txt๋ฅผ ์ณ๋ณด์ž.
์‚ฌ์ดํŠธ๋ณ„๋กœ ์ž๊ธฐ๋“ค์ด ์ •ํ•ด๋‘” ๋ฃฐ, ์–ด๋””๊นŒ์ง€ ์“ฐ์„ธ์š”~๊ฐ€ ์นœ์ ˆํžˆ ๊ธฐ๋ก๋˜์–ด์žˆ๋‹ค.
[P.S]์ฐพ์•„๋ณด๋‹ˆ ๊ถŒ๊ณ ์‚ฌํ•ญ์ด๋ผ ์‚ฌ์ดํŠธ๋ณ„๋กœ robots.txt๊ฐ€ ์—†๋Š” ๊ณณ๋„ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ์‚ฌ๋žŒ์˜ ์ง€์ ์žฌ์‚ฐ๊ถŒ์„ ์‚ฌ์šฉํ•˜๋Š”๊ฑฐ๋‹ˆ ๋ฌด์กฐ๊ฑด ํ•œ๋ฒˆ ๋กœ๋ด‡์„ ๋„ฃ์–ด๋ณด๋Š”๊ฑธ ๊ถŒ์žฅ
(์‚ฌ์šฉ ์˜ˆ์‹œ : https://www.nike.com/robots.txt)
์ด๋ ‡๊ฒŒ ์ด์Šคํ„ฐ์—๊ทธ์ฒ˜๋Ÿผ ํ‘œํ˜„ํ•œ ๊ณณ๋„ ์žˆ๋‹ค (์ถœ์ฒ˜ Nike)

<์›น ํฌ๋กค๋ง์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ>

1. BeautifulSoup

๋…ธ๋งˆ๋“œ์ฝ”๋”์˜ ๋‹ˆ์ฝœ๋ผ์Šค๊ฐ€ ์™ธ์น˜๋Š” '๋ทฐ๋ฆฌํ’€ ์ˆฉ~'์œผ๋กœ ์ต์ˆ™ํ•ด์ง„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

HTML, XML ํŒŒ์ผ์˜ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•ด๋‚ด๋Š” python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ์‚ฌ์šฉํ•˜๊ธฐ ๋งค์šฐ ์‰ฝ๊ณ , ์‹ฌํ”Œํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์œผ๋‚˜, ์„œ๋ฒ„์—์„œ HTML์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›๊ธฐ๋•Œ๋ฌธ์—, ์„œ๋ฒ„์‚ฌ์ด๋“œ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” SPA ์‚ฌ์ดํŠธ๋‚˜, javascript ๋ Œ๋”๋ง์„ ํ•„์š”๋กœํ•˜๋Š” ์‚ฌ์ดํŠธ๋“ค์€ ์ƒ๋‹นํžˆ ๊นŒ๋‹ค๋กœ์šด ํŽธ

  • ์žฅ์  โ€” ์‰ฌ์›€, ์‹ฌํ”Œํ•จ, ๋น ๋ฆ„ (๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค, ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ์ ์šฉ์‹œ ํ•ด๋‹น)
  • ๋‹จ์  โ€” javascript ๋ Œ๋”๋ง์ด ํ•„์š”ํ•œ ์‚ฌ์ดํŠธ๋“ค์„ ํฌ๋กค๋งํ•˜๊ธฐ ์–ด๋ ค์›€. ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๋ณ„๋„๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š์œผ๋ฉด ๋Š๋ฆฐํŽธ.

2. Selenium

์ด๊ฑฐ ์…€๋ ˆ๋‹ˆ์›€์ด๋ผ๊ณ  ๋ชป์ฝ๋˜ ๋ฐ”๋ณด->๋ฐ”๋กœ '๋‚˜'
(์ด์ œ๋Š” ์ž˜ ์ฝ์Œ)

Selenium์€ย ์›น ์ž๋™ํ™” ํ…Œ์ŠคํŠธ (๋ฒ„ํŠผ ํด๋ฆญ, ์Šคํฌ๋กค ์กฐ์ž‘ ๋“ฑ๋“ฑ)์— ์‚ฌ์šฉ๋˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค. ์›น ํŽ˜์ด์ง€์—์„œ javascript๋ฅผ ํ†ตํ•ด ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๋ฐ์ดํ„ฐ๋“ค์„ ์†์‰ฝ๊ฒŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

  • ์žฅ์  โ€” ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋Š” ์›น ํŽ˜์ด์ง€์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ, javascript rendering ๊ธฐ๋Šฅ ์ง€์›, ์‚ฌ์šฉ๋ฐฉ๋ฒ•์ด ์ง๊ด€์ ์ด๊ณ  ์‰ฌ์šด
  • ๋‹จ์  โ€” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งŽ์ด ์ฐจ์ง€ํ•œ๋‹ค

<์‹ค์ „์—ฐ์Šต>

์Šคํƒ€๋ฒ…์Šค ์ฝ”๋ฆฌ์•„์—์„œ ๋ชจ๋“  ์Œ๋ฃŒ์˜ ์ œ๋ชฉ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ํฌ๋กค๋งํ•ด์„œ csv๋กœ ์ €์žฅํ•ด๋ณด๊ธฐ

CSV์— ๋Œ€ํ•ด์„œ
์ฐธ๊ณ ํ•œ ์Šคํƒ€๋ฒ…์Šค์‚ฌ์ดํŠธ
์ด๋ฒˆ ์—ฐ์Šต์€ ์ด๋ฏธ ์‚ฌ์ „์— ์ฝ”๋“œ๋ฅผ ๋‹ค ์•Œ๋ ค์ฃผ์…จ๊ณ , ํฌ๋กค๋ง์ด๋ผ๊ธฐ๋ณด๋‹ค ๊ทธ๋ƒฅ ํ๋ฆ„์„ ์ดํ•ดํ•˜๋Š” ์ˆ˜์ค€์ด์˜€๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๊ทธ๋ƒฅ ๊ฒฐ๊ณผ ์ฝ”๋“œ๋งŒ ๊ธฐ์ˆ ํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค

 #ํ•„์š”ํ•œ ์• ๋“ค import
 import csv
 import time

 from bs4 import BeautifulSoup
 from selenium import webdriver
 from webdriver_manager.chrome import ChromeDriverManager

 #csvํŒŒ์ผ ์ž‘์„ฑํ•ด์„œ ์„ค์ • ์ด๋ฆ„์€ stabucks.csv
 csv_name = "starbucks.csv"
 #csv์—ด์–ด๋ณธ๋‹ค
 csv_open = open(csv_name, "w+", encoding = "utf-8")
 csv_writer = csv.writer(csv_open)
 csv_writer.writerow(('category','name','image_url'))

 #ํฌ๋กฌ์„ ์—ด๊ฒŒ ํ•˜๊ฒ ๋‹ค
 driver = webdriver.Chrome(ChromeDriverManager().install())

 #๊ฐ€์ ธ์˜ค๋Š” ํŽ˜์ด์ง€
 org_crawling_url = "https://www.starbucks.co.kr/menu/drink_list.do"
 driver.get("https://www.starbucks.co.kr/menu/drink_list.do")

 #๊ฐ€์ ธ์˜ค๋Š” ํŽ˜์ด์ง€์˜ ์ „์ฒด ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์™€๋ผ~
 full_html = driver.page_source

 #์ „์ฒด์†Œ์Šค๋ฅผ ํŒŒ์ด์ฌ์ด html์„ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์ž
 soup = BeautifulSoup(full_html, 'html.parser')

 #๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ 3์ดˆ์ •๋„ ๊ธฐ๋‹ค๋ ค์ฃผ์ž
 time.sleep(3)

 #์ „์ฒด์—์„œ ๋‚ด๊ฐ€ ๊ฐ€์ ธ์˜ฌ ์นดํ…Œ๊ณ ๋ฆฌ์— ๊ทธ ํƒœ๊ทธ๋ฅผ ์ฐพ์•„์ฃผ์ž
 categories = soup.select('#mCSB_1_container > li > label')

 #๊ทธ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋ฐ˜๋ณตํ•˜๊ธฐ์œ„ํ•œ for๋ฌธ
 for i in range(2,len(categories)+1):
     #์นดํ…Œ๊ณ ๋ฆฌ ๋Œ๋ฆฌ๋Š”๊ฑฐ 2,3,4,5,6์ˆœ
     element = driver.find_element_by_css_selector(f'#mCSB_1_container > li:nth-child({i}) > label')

     category_name = element.text
     time.sleep(2)
     element.click()
     #ํ™ˆํŽ˜์ด์ง€์—์„œ ์ „์ฒด ์†Œ์Šค ๊ฐ€์ ธ์˜ค๊ณ  ๊ฑฐ๊ธฐ์„œ html๊ธ์–ด์™“!
     full_html = driver.page_source
     soup = BeautifulSoup(full_html, 'html.parser')
     #๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋Š” 2์”ฉ ๋Š˜์–ด๋‚˜๋Š”๋ฐ,
     titles = soup.select(f'#container > div.content > div.product_result_wrap.product_result_wrap01 > div > dl > dd:nth- child(2) > div.product_list > dl > dd:nth-child({i*2-2}) > ul > li > dl > dt > a > img')
     print(titles)

     for i, title in enumerate(titles):
         #print('name: ',title['alt'])
         #print('image_url: ',title['src'].split('/')[4:])
         url = title['src']
         print(url) 
         
         if i == 0:
             csv_writer.writerow((category_name,title['alt'],url))
         else:
             csv_writer.writerow(('',title['alt'],url))         

๊ฒฐ๊ณผ

ํ›„๊ธฐ

์ด๋ฒˆ๊ฑด ์†”์งํžˆ ์œ„์ฝ”๋“œ์—์„œ ๋‹ค ๋– ๋จน์—ฌ์ค€๊ฑฐ๋ผ..(์‚ฌ์ „์— ์ฝ”๋“œ๋ฅผ ์•Œ๋ ค์ฃผ์‹ฌ)
๋‹จ์ง€ ๊ณ„์† ๊ณ ์ƒํ–ˆ๋˜ ๋ถ€๋ถ„์€
BeautifulSoup๊ฐ€ Javascript๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š”์ ์„ ์‚ฌ์ „์— ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ณ 
BeautifulSoup๋งŒ importํ•ด์„œ ์“ฐ๋‹ค๊ฐ€ ๋’ค๋Šฆ๊ฒŒ ๋‹ค๋ฅธ๋™๊ธฐ๋ถ„์ด ์•Œ๋ ค์ฃผ์‹ ๊ฑฐ์˜€๋‹ค..ใ…Ž..
๊ทธ๋ฆฌ๊ณ  ์›๋ฆฌ๋ฅผ ์ดํ•ดํ–ˆ๋Š”๋ฐ ์‚ฌ์ดํŠธ์—์„œ ์•Œ๋งž๋Š” ํƒœ๊ทธ๋ฅผ ์ฐพ์•„๋‚ด๋Š”๊ฒƒ๋„..ใ…Ž ํ•œ ๋„ค๋‹ค์„ฏ์‹œ๊ฐ„ ๊ณ ์ƒํ•œ๋“ฏใ… ใ… 
์ด๋ฒˆ ๊ณผ์ œ๋Š” ์Œ.. ๋‚ด๊ฐ€ ๋…ธ๋ ฅํ•œ๊ฒƒ๋ณด๋‹ค ๋‹ค๋ฅธ๋ถ„๋“ค์ด ๋„์™€์ฃผ์‹ ๊ฒŒ ์ปค์„œ ์ข€ ์•„์‰ฌ์šด ๊ณผ์ œ์˜€๋‹ค.
(๊ทธ๋ž˜๋„ ์ดํ•ด๋Š” ํ•˜๊ณ  ์žˆ์œผ๋‹ˆ ๋‹ค์Œ๋ฒˆ์— ํ•œ๋ฒˆ๋” ํ˜ผ์ž์„œ ํ•ด๋ด์•ผ๊ฒ ๋‹ค. ํ• ๊ฒŒ ์Œ“์ด๋Š”์ค‘)

profile
๐ŸŒฑBackend Developer๐Ÿ‘ฉโ€๐Ÿ’ป

0๊ฐœ์˜ ๋Œ“๊ธ€