스크래핑 : 웹 사이트를 분석하여 원하는 데이터를 추출하는 과정
크롤링과 스크래핑의 차이?
크롤링
- 자동화
- 웹 상의 데이터가 최신화 될 때마다 나의 데이터베이스도 최신화 된다
스크래핑
- 자동화가 되지는 않음
- 긁어오는 시점의 데이터만 긁어온다
우선 어떤 웹 브라우저를 크롤링 하고싶은지 지정하기!
👆🏻 보그 웹사이트를 크롤링한다고 가정했을 때,
정해야한다!
개발자 도구option + command + i
를 통해 html 파일을 조회해보면 대략적인 분석이 가능하다.
우선, <img>
태그를 확인해보자!
👉🏻 해당 태그마다 어떠한 image 파일을 사용하고 있는지, 등을 분석할 수 있다.
웹 브라우저는 html 파일을 이해할 수 있지만
terminal에게 html파일은 그저 텍스트일 뿐!
terminal은 해당 코드가 html 태그인지, css 선택자인지 알 수 없다
크롤링을 하기 위해, html 파일을 인식하도록 하기 위해서는
특정 라이브러리를 사용해야 한다
Beautiful soup
- html과 xml파일로부터 데이터를 뽑아내는 파이썬 라이브러리
- html의 'id', 'class' , css selector를 분석해서 변수로 사용할 수 있도록 해준다
selenium
- 브라우저를 실행시켜 동적인 입력이 필요한 웹을 구동할 수 있는 라이브러리
- 검색어 입력, 버튼 클릭 등의 동작을 실행하도록 도와준다
ex) '크롤링' 검색 결과 페이지 스크랩
> pip freeze
👆🏻 가상환경에 어떠한 라이브러리가 설치되었는지 확인할 수 있다
python --version
우선 내 컴퓨터에 설치되어있는 파이썬의 버전을 확인한 뒤,
conda create -n web-crawling python=3.8
miniconda를 통해 web-crawling이라는 이름의 가상환경을 설치하겠다고 입력하기!
이 가상환경을 활성화 할 것인지, 아닌지에 대해서 입력해야 한다.
conda activate web-crawling
나는 작업을 해줄 것이므로 👆🏻👆🏻 요로케 입력하기!
>> pip install beautifulsoup4
>> pip install requests
>> pip install selenium
>> pip install webdriver-manager
>> pip freeze
👆🏻 크롤링을 하기 위해 필요한 beautifulsoup,
웹사이트로 요청할 때 필요한 requests를 설치하고
(추후에 자동화 된 크롤링을 하기 위해 selenium, webdriver-manager를 추가했다)
pip freeze
를 통해 설치내역 확인하기!
1 from bs4 import BeautifulSoup
2
3 import csv
4 import re
5 import requests
6
7 #1. csv file open
8 csv_name = "main_all.csv"
9 csv_open = open(csv_name, "w+", encoding="utf-8")
10 csv_writer = csv.writer(csv_open)
11 csv_writer.writerow(("drink", "image_url"))
12
13 #2.BeautifulSoup
14 crawling_url = "https://www.starbucks.co.kr/menu/drink_list.do"
15 response = requests.get(crawling_url)
16
17 #3. Parsing html code
18 html = response.text
19 bs = BeautifulSoup(response.text, 'html.parser')
20
21 #4. Get element selector
22 lists = bs.select("#container > div.content > div.product_result_wrap.product_result_wrap01 > div > dl > dd:nth-child(2) > div.product_list > dl > dd:nth-child(2) > ul > li:nth-child(1) > dl > dd")
23 imgs = bs.select("#container > div.content > div.product_result_wrap.product_result_wrap01 > div > dl > dd:nth-child(2) > div.product_list > dl > dd:nth-child(2) > ul > li:nth-child(1) > dl > dt > a > img") 24
25 #5. Save drink, img
26 with open(csv_name, "w+", encoding = "utf-8") as file:
27 for i in range(len(lists)):
28 #drink
29 drink = lists[i]['dd']
30
31 #image_url
32 img_url = crawling_url + '/' + imgs[i]['src']
33
34 writer = csv.writer(file)
35 writer.writerow((drink, img_url))
👆🏻 크롤링 작업을 위해 BeautifulSoup만 쓴 상황!
작성하다가 selenium을 사용해서 보다 편리하게 크롤링을 하려고 했어서 작성ㅎㅏ다 그만둔 코드..
요로케 python crawling.py
하고 파일을 실행시키면
터미널 창에는 아무런 변화도 생기지 않지만
내가 작업중인 디렉토리에 가면 csv파일이 생성되어있는것을 볼 수 있다!
👆🏻 결과물!
(아무 데이터도 가져오지 못했으니 누가 봐도 문제가 다분한 코드파일인듯 ㅎㅅㅎ)
무튼 selenium을 사용해서, 동적인 입력을 자동으로 하는 크롤링을 해보도록 할 것!
1 from bs4 import BeautifulSoup
2 from selenium import webdriver
3 from webdriver_manager.chrome import ChromeDriverManager
4
5 import csv
6 import time
7
8 #1. csv file open
9 csv_name = "main_all.csv"
10 csv_open = open(csv_name, "w+", encoding="utf-8")
11 csv_writer = csv.writer(csv_open)
12 csv_writer.writerow(("category", "drink", "image_url"))
13
14
15 #2. Driver & BeautifulSoup
16 driver = webdriver.Chrome(ChromeDriverManager().install())
17
18 crawling_url = "https://www.starbucks.co.kr/menu/drink_list.do"
19 driver.get(crawling_url)
20
21
22 #3. Parsing html code
23 full_html = driver.page_source
24 soup = BeautifulSoup(full_html, 'html.parser')
25
26 time.sleep(3)
27
28
29 #4. Get element selector (1)
30 categories = soup.select('#mCSB_1_container > li')
31
32
33 #5. Get element selector (2)
34 for i in range(2, len(categories)+1):
35 element = driver.find_element_by_css_selector(f'#mCSB_1_container > li:nth-child({i})')
36 category_name = element.text
37 time.sleep(2)
38 element.click()
39
40 full_html = driver.page_source
41 soup = BeautifulSoup(full_html, 'html.parser')
42
43 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-1)*2}) > ul > li > dl > dt > a > img')
44
45 #6. print drink_title, image url
46 for i, title in enumerate(titles):
47 print('title: ', title['alt'])
48 print('original src: ', title['src'])
49 print('image_url: ', title['src'].split('/')[4:])
50 url = crawling_url + '/' + '/'.join(title['src'].split('/')[4:])
51
52 if i == 0:
내가 작성한 코드!
우선 selenium 라이브러리, time 모듈을 추가로 import 해준다.
동적인 입력을 자동으로 하게 하기 위해서는 웹 페이지가 로딩 된 이후에 동작해야 한다.
이 때 time모듈의 기능을 사용해주는 것!
작성할 csv파일에 대한 설정을 해주고, csv 파일 내 어떤 컬럼을 생성할 것인지 지정한다
어떠한 웹 브라우저를 통해 크롤링을 할 것인지,
어느 주소의 웹 페이지를 크롤링 할 것인지 명시해주는 구간!
내가 크롤링하겠다고 명시한 페이지를 html파일로 파싱해주는 구간!
여기서 BeautifulSoup 라이브러리를 사용해서 파이썬이 html파일을 인식할 수 있도록 해준다.
앞서 이야기했지만, html 파일은 파이썬에게 있어 그저 문자열의 나열일 뿐!
parsing을 통해 이것이 우리가 작업할 html파일이다, 하고 인식할 수 있도록 해주어야 한다.
이제 대망의 단계, 크롤링 해올 선택자를 파악해야하는 구간이다.
(여기서 제일 많이 헷갈리고 고민되는 부분)
우선 어떻게 크롤링을 해올지 생각을 해보자.
각 카테고리에 해당하는 음료를 가져와야 하므로, 카테고리 & 음료를 가져올 방법을 찾아야한다
내가 항상 하는 생각, 구구단 돌리듯이!
nested for loops를 사용해야 하는데 구조는 다음과 같은 형식일것이다
for i in 카테고리 개수: -> for loop (1)
for j in 음료 개수: -> for loop (2)
전체 카테고리 개수를 먼저 파악한 뒤, for loop (1)을 돌고
해당 카테고리 내 음료의 개수만큼 for loop (2)를 도는 구조!
개발자도구를 통해 카테고리 요소의 선택자를 파악해보쟈
나는 li
요소로 반복문을 돌렸지만, 정확히 하고싶다면 li
의 자식 요소인 label
까지 하는것이 맞다.
(뭐 코딩에 정답이 어디있겠나 싶지만 그래도..!)
이제 각 카테고리에 속하는 음료 요소를 가져올 차례!
처음엔 이부분이 너무 헷갈려서.. 제일 많이 헤맸던 것 같다
스타벅스 홈페이지는 dt
, dd
두 요소가 번갈아가면서 쓰이기 때문에 css nth-child
속성이 짝수 단위로 작성된 상황이었다.
👆🏻 요로케!
f'....'
이러한 형식으로 작성해주어야 한다!f'....'
로 감싸주지 않았기 때문에,각 카테고리 내 음료 개수만큼 데이터를 가져와서
해당 내용부분을 csv 파일 내에 입력해주겠다는 뜻!
남들 다 CRUD (2) 하는데 꿋꿋이 혼자 크롤링한 나..
지금까지 한번도 해본적 없는 기능이어서 너무 신기하고 재미있게 했던 것 같다
더 열심히 연습해서 나중엔 척척 해낼 수 있도록 해야지 ㅎㅅㅎ