이번 포스트에서는 python으로 Crawling(크롤링, 웹사이트의 이미지나 정보를 긁어오는 행위)을 배워보겠습니다.
당연히 웹사이트의 크롤링은 비상업적으로 진행합니다.
Python에서 크롤링은 주로 BeautifulSoup과 Selenium을 통해 이뤄집니다.
각각에 대한 간단한 소개와 예제를 다뤄보겠습니다.
Python Crawling에 대한 필요 모듈의 설치와 기본 설정은 이전 포스트를 참조 해주시면 되겠습니다.
1. BeautifulSoup
BeautifulSoup은 HTML과 XML 문서의 parsing을 하기 위한 Python 패키지입니다.
저장하는 파일은 csv나 json등으로 설정하겠습니다.
예제는 Vogue Korea(www.vogue.co.kr)의 사진과 그 타이틀을 가져오는 것을 목표로 하겠습니다.
참조할만한 내용은 크롬으로 열었을 때와 Safari(맥용 브라우저)로 열었을 때 보이는 이미지가 다르다는 것입니다.
저는 크롬으로 크롤링을 진행 했습니다.
예제의 동작을 미리 소개하면,
1) 원하는 정보를 chrome에서 태그 분석하기
2) csv 파일을 열고
3) 크롤링할 url에 대한 설정
4) BeautifulSoup 객체를 선언(parsing 종류 입력해야 합니다.)
5) 필요한 item에 대한 목록 받아오기
6) 반복문 통해 필요한 속성값 분리해 받고 csv 파일로 저장
먼저 1)의 과정입니다.
vogue korea 홈페이지에 접속합니다.
3분할된 사진이 보이시나요?
이 사진의 이미지 경로와 타이틀을 저장할 것입니다.

먼저 F12키를 눌러줍니다.
그러면 화면이 분할 되면서 한쪽에 코드들이 보일 것입니다.
이것을 개발자 도구라고 합니다.
Front End 개발에서는 땔 수 없는 툴 입니다.
개발자 도구 상단에 화살표에 화면을 누르는 듯한 버튼을 눌러줍니다.
아래 화면 처럼 파란색으로 변할 것입니다.
그리고 사진 위에 올려보면 마치 그 그림만 콕 찍어내듯이 정보가 나옵니다.

여기서 클릭까지 하시면 오른쪽에 html 소스에서 이 아이템이 어떤 대상인지 친절하게 알려줍니다.
저희가 '베일 벗은 싹쓰리 패션의 모든것'이라는 아이템만 가져올게 아니라 화면에 나온 12개만 가져와야 하므로 조금더 상단의 태그를 따올 것입니다.
위로 조금만 올라가면 post-container라는 전체를 담는 틀이 있고, 거기서 다시 조금만 내려가면 post-'숫자'라는 id를 가진 article 태그가 있습니다.
이 article 태그가 크롤링 하기위해 필요한 정보를 담고 있습니다.
해당 소스코드 위에 우클릭을 해서 copy > copy-element를 해줍니다.
이제 VSCode나 html을 보기 편한 곳으로 옮겨주거나 해서 조금 더 관찰해보겠습니다.
자세히 보면 하나의 post에 굉장히 많은 정보가 있습니다.
클릭하면 redirect 해주는 링크도 있고, 이미지도 있고 텍스트도 있습니다.
복사해온 HTML 소스의 중간쯤에 h2 태그로 되어있고 텍스트가 쓰여져 있을 것입니다.
바로 이 내용이 첫 번째 타겟인 title이 되겠습니다.
그리고 조금 더 올라가면 img 태그에 src가 있습니다.
이 내용은 image url로 마찬가지로 가져와야 할 대상입니다.
이제부터는 2)의 과정인데 여기서부터 python 파일로 진행합니다.
python 코드에 과정에 대한 comment를 달아 놓겠습니다.
from bs4 import BeautifulSoup
import requests
import re
import csv
# 2)csv 파일 열기
csv_filename = "vogue_fashion.csv"
csv_open = open(csv_filename, "w+", encoding='utf-8')
csv_writer = csv.writer(csv_open)
csv_writer.writerow( ('title','image_url' ) )
# 3)url 설정
crawling_url = "http://www.vogue.co.kr/category/fashion/page/1"
response = requests.get(crawling_url)
# 4)BeautifulSoup 객체 선언
bs = BeautifulSoup(response.text, 'html.parser' )
# 5)필요한 아이템 목록 가져오기
article_list = bs.find_all('article', {'id': re.compile('post-*')})
# 6)반복문 통해 필요한 속성값 분리해 받고 csv 파일로 저장
for article in article_list:
h2_title = article.find_all('h2')
#print("h2_title=", end=""), print(h2_title)
real_title = h2_title[0].text
#print("real h2 = ",end=""), print(real_title)
img = article.find('img')
print("type img=",end=""),print(type(img))
image_url = img['src']
print(image_url)
csv_writer.writerow( (real_title, image_url) )
csv_open.close()
2) csv 파일열기 에서는 csv 파일을 열고 write 권한을 줍니다.
첫 줄에는 칼럼 정보를 기입합니다.(title, image url)
3) 크롤링할 url에 대한 설정은 조금 전에 html 소스코드를 복사해서 VSCode에서 보는 것 같은 과정입니다.
Client에서 url로 request를 주면 웹사이트가 html 소스코드를 response로 줍니다.
python 파일에서 이를 변수로 받아 오는 것이죠.
4) BeautifulSoup 객체를 선언에서는 받아온 html 소스와 parser를 지정해서 객체로 만들어줍니다.
5) 필요한 아이템 목록 가져오기가 BeautifulSoup을 사용하는 핵심 중 하나 입니다.
가져온 객체 중에서 원하지 않는 아이템(html 태그)들이 많이 있습니다.
이 중에서 HTML 소스를 분석한 결과, 필요한 내용은 post-숫자 형태의 id를 가진 article 태그였습니다.
그렇기 때문에 정규표현식을 통해 모두 찾아온 것입니다.
print 해보면 저희가 타겟으로 하는 article 태그만 나옵니다.
6) 반복문 통해 필요한 속성값 분리해 받고 csv 파일로 저장은 마지막 과정입니다.
1)에서 분석한 title과 image url 태그는 각각 h2와 img 태그였습니다.
각각 태그만 분리하고 진짜 필요한 정보는 text와 src이기 때문에 이를 지정합니다.
최종적으로 csv파일에 저장하고 종료합니다.
2. selenium
다음으로 다뤄볼 툴은 selenium 입니다.
웹사이트를 크롤링 할 때, Vouge 사이트와 같이 처음부터 바로 원하는 화면을 볼 수 있는 사이트가 있지만,
검색내용을 입력하고 가져와야 하는 경우도 있습니다.
또는, 팝업을 닫아줘야만 정상적으로 화면을 볼 수 있는 웹사이트도 있습니다.
그리고 사용하는 이유중 가장 중요한게 바로 동적페이지(JavaScript)로 제공되는 HTML인 경우입니다.
이러한 동적페이지의 경우 HTML을 Client에 제공하고 화면에 각 요소들을 뿌려주는 형태로 단순히 BeautifulSoup만 사용했을 때, 찾는 element가 나오지 않을 수도 있습니다.
이런 상황에서 selenium을 통해 제어할 수 있습니다.
실제 크롤링 하는 도구는 BeautifulSoup이지만, 제어해주는 도구가 selenium 입니다.
selenium을 사용하기 위해서는 컨트롤 받는 웹 도구인 웹드라이버를 설치해야 합니다.
저는 가장 많이 사용되는 크롬 드라이버를 사용하겠습니다.
링크는 아래 링크에서 각 크롬 버전에 맞게 설치 하면 됩니다.
sites.google.com/a/chromium.org/chromedriver/downloads
구글크롬 버전확인은 크롬 상단 오른쪽에 3개의 점이 있는 곳을 클릭 > 설정으로 들어갑니다.
좌측 하단 메뉴 중 Chrome 정보 라는 메뉴를 누릅니다.
기다리시면, 중앙에 크롬 버전이 뜹니다!

설치를 하고 이제 예제를 통해 파악해보겠습니다.
대한민국 구석구석이라는 한국관광공사에서 개발한 웹페이지에서 여행정보를 검색해보겠습니다.
https://korean.visitkorea.or.kr/main/main.do
화면을 보면,

대한민국 구석구석이라는 텍스트에 검색이라는 아이콘을 누르고 검색어를 입력할 수 있는 칸이 뜨는데 바로 여기까지가 selenium을 통해 제어될 부분입니다.
그렇지만, 저 버튼을 누르기 전에 단계가 또 있습니다.
코로나-19 바이러스로 위 페이지에 들어가면 하나의 관문이 더 있는 것을 볼 수 있습니다.
해당 팝업레이어를 닫지 않으면, 위 이미지의 돋보기(검색) 버튼도 클릭 되지 않는다는 것을 알 수 있습니다.
아래 화면이 이를 설명해주고 있습니다.

select on element 툴을 가져다봐도 적용이 되질 않습니다.
다만, 적용되는 것은 저 팝업레이어 뿐입니다.
그렇다면 해당레이어를 '닫기'나 '오늘 하루 그만보기' 버튼을 눌러 닫는 방법 밖에 없습니다.
select on element로 움직여보니 팝업 레이어의 하단 창에 적용할 수 있는 것을 볼 수 있습니다.
해당 태그를 copy element 해줍니다.
<div class="viewNone">
<input type="checkbox" id="chkForm01" name="">
<label for="chkForm01">오늘하루 그만보기</label>
<button type="button" onclick="closeWin();">닫기</button>
</div>
체크박스로(오늘하루 그만보가)와 닫기 버튼이 있습니다.
여기서 닫기 버튼을 클릭하기로 결정하고 selenium으로 동작하게 했습니다.
driver = webdriver.Chrome('/Users/~~~/crawler_test/chromedriver')
driver.get("https://korean.visitkorea.or.kr/main/main.do")
driver.find_element_by_link_text('닫기').click()
driver 객체는 selenium에서 import한 webdriver 모듈을 입니다.
즉, 웹 컨트롤을 위한 객체인 것입니다.
변수로는 크롬 드라이버의 경로를 적어주시면 됩니다.
두 번째 라인은 '닫기'라는 텍스트를 가진 버튼 태그를 찾는 과정입니다.
그리고 .click은 인터넷에서의 클릭 동작과 동일한 역할을 합니다.
한 마디로 닫기라고 써져있는 버튼을 찾아, 클릭하는 동작을 python 코드로 작성 한것입니다.
위 과정을 다른 방법으로도 해보고 몇 번을 시도했지만, 좀 처럼 되지 않았습니다.
아래와 같은 에러가 출력 되었습니다.
selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <a href="javascript:hiddenbanner();" class="close">...</a> is not clickable at point (1153, 43). Other element would receive the click: <div id="safetyStay1" class="wrap_layerpop active">...</div> (Session info: chrome=83.0.4103.116)
한 마디로 클릭이 되지 않는 에러였습니다.
혹시나 이 포스트를 읽으시는 분들 중에서 이 에러를 바로 잡을 수 있는 분이 계시다면, 알려주시면 감사하겠습니다.
저는 이 닫기 버튼 대신 왼쪽에 있는 '오늘하루 그만보기'라는 버튼을 클릭하기로 했습니다.
driver = webdriver.Chrome('/Users/~~~/crawler_test/chromedriver')
driver.get("https://korean.visitkorea.or.kr/main/main.do")
driver.find_element_by_id('chkForm01').click()
id로 구분되는 element를 찾고 그 버튼을 클릭하게 하니 작동이 됐습니다!
이제 크롤링의 예제 코드를 살펴보겠습니다.
from bs4 import BeautifulSoup
from selenium import webdriver
import time
query_keyword = input("크롤링 키워드는?")
driver = webdriver.Chrome('/Users/gonholee/crawler_test/chromedriver')
driver.get("https://korean.visitkorea.or.kr/main/main.do")
time.sleep(4)
driver.find_element_by_id('chkForm01').click()
driver.find_element_by_id("btnSearch").click()
element = driver.find_element_by_id("inp_search")
element.send_keys(query_keyword)
driver.find_element_by_link_text("검색").click()
full_html = driver.page_source
soup = BeautifulSoup( full_html, 'html.parser' )
time.sleep(2)
코드는 parsing을 하기 전 까지의 단계입니다.
조금 전 설명드린대로 driver 정보를 설정하고, 제어할 링크를 엽니다.
그리고 그만보기 버튼을 클릭해 팝업을 닫고, 검색버튼을 눌러줍니다.
여기서 inp_search 즉, 검색어란을 입력하는 곳을 찾습니다. id가 inp_search로 할당 되어 있었기 때문에 id로 찾는 것입니다.
입력 받은 검색어(query_keyword)를 send_keys를 통해 전송합니다.
마지막으로 검색버튼을 클릭하면, 새로운 링크가 열리게 될 것입니다.
이 내용을 full_html이라는 변수에 담습니다.
그리고 조금 전 BeautifulSoup에서 다룬 것 같이 parser를 통해 BeautifulSoup 객체를 받습니다.
'Dev > Python' 카테고리의 다른 글
Python으로 Crawling 준비하기(Beautifulsoup4, Selenium 설치 & Chromedriver 설정) (0) | 2020.10.24 |
---|---|
[Python 기초] Closure & Decorator (0) | 2020.06.30 |
[Python 기초] - Iterator & Generator & Lazy Evaluation (2) | 2020.06.29 |
[Python 기초] Module & Package 이해하기 4(실습) (0) | 2020.06.27 |
[Python 기초] Module & Package 이해하기 3 (0) | 2020.06.27 |