본문 바로가기

문돌이 존버/코딩연습

파이썬 웹크롤링(web-crwaling) 파헤치기! feat. BeautifulSoup, Selenium

반응형

이번에 회사 동료분이 슬랙, 라인웍스, 잔디, 워크플레이스 등 여러 기업용 메신저 블로그 포스트를 정리해야 했는데요. 그 많은 포스트를 수동으로 작업하려고 하니 앞길이 막막해 보이더라구요. 저도 웹크롤링 공부도 할겸 포스트를 긁어주겠다고 말했고, 짧지 않은 시간을 들여 코딩해봤습니다. ㅋ

사이트마다 html 구조가 달라 다소 귀찮았지만... 덕분에 html 공부도 했네요. 긁어와야 할 정보는 날짜, 제목, URL 이었습니다. 저는 Selenium을 쓸 때, find_elements_by_css_selectorfind_elements_by_xpath를 혼용해서 사용했습니다. 

잔디의 경우, 페이지 이동이 아닌 "더보기" 버튼을 클릭하는 구성이었습니다. 즉 더보기를 계속 누르면서 무한 스크롤을 해야 하는 것이죠. 

---------------------------------------------잔디 블로그------------------------------------------------

from selenium import webdriver
import csv
import time
import pandas as pd

url = 'http://blog.jandi.com/ko/category/introduce/jandi_tip/'

#웹 드라이버
driver = webdriver.Chrome('./chromedriver.exe')
driver.implicitly_wait(30)
driver.get(url)

post_list = []

SCROLL_PAUSE_TIME = 2

# 스크롤 높이 
last_height = driver.execute_script("return document.body.scrollHeight")      

while True:
    # 스크롤 무빙                                                    
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # 페이지 로드 대기
    time.sleep(SCROLL_PAUSE_TIME)                                               
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight-50);")  
    time.sleep(SCROLL_PAUSE_TIME)

    # 새로운 스크롤 동작 높이와 이전 스크롤과의 비교  
    new_height = driver.execute_script("return document.body.scrollHeight")

    if new_height == last_height:                                               
        break

    last_height = new_height
    
dates = driver.find_elements_by_css_selector('span.time')
titles = driver.find_elements_by_css_selector('h2.title')
urls = driver.find_elements_by_css_selector('a.post-title.post-url')

for item in zip(dates, titles, urls):
    post_list.append(
        [
            item[0].text,
            item[1].text,
            item[2].get_attribute("href"),
        ]
    )

    
post_infos = pd.DataFrame(post_list, columns=['date', 'title', 'url'])
post_infos.to_csv('post_infos(잔디).csv', encoding='utf-8-sig')

driver.quit()

 

슬랙의 경우, 날짜가 포스트 리스트에 나타나지 않고 꼭 포스트를 클릭해야 볼 수 있더라구요. 이것까지 커버하려 했으나, 이번엔 넘어가기로 했습니다. 또한, 잔디와 다르게 url에 페이지 넘버가 표시되고 있어 BeautifulSoup을 이용하는게 훨씬 편리했습니다. 

---------------------------------------------슬랙 블로그------------------------------------------------

import urllib.request
import urllib.parse
from bs4 import BeautifulSoup

post_list = []

pageNum = 2 # 슬랙의 경우, 첫 페이지 구조가 달라서 첫 페이지는 따로 긁었습니다. 

while pageNum < 47: # 해당 부분은 블로그마다 다릅니다. 
    
    url = f'https://slackhq.com/categories/collaboration/page/{pageNum}'
        
    html = urllib.request.urlopen(url).read()
    soup = BeautifulSoup(html, 'html.parser')
    
    titles = soup.select('header > h3 > a')

    for title in titles:
        post_list.append([title.text, title.get('href')])
        
    pageNum += 1
    
post_infos = pd.DataFrame(post_list, columns=['title', 'url'])
post_infos.to_csv('post_infos(slack).csv', encoding='utf-8-sig')

가장 난감했던 블로그가 라인웍스였는데요. 크롤링할 카테고리마다 구성도 달랐고, 네이버 블로그 플랫폼이다 보니 목록 더보기에, 공지에... 여러 가지를 아래와 같이 다 짬뽕시켰더라고요. 

<출처: 라인웍스 공식 블로그>

이렇다 보니, Selenium을 사용해서 페이지를 이동하면서 긁을 수 밖에 없었습니다. 

---------------------------------------------라인웍스 블로그------------------------------------------------

from selenium import webdriver
import csv
import time
import pandas as pd

url = f'https://blog.naver.com/PostList.nhn?blogId=works_mobile&categoryNo=18&parentCategoryNo=18&skinType=&skinId=&from=menu&userSelectMenu=true'

driver = webdriver.Chrome('./chromedriver.exe')
driver.implicitly_wait(30)
driver.get(url)

post_list = []

pageNum = 1

while pageNum < 11:

    elements = driver.find_element_by_xpath(f'//*[@id="toplistWrapper"]/div[2]/div/a[{pageNum}]')
    elements.click()
    time.sleep(1)

    dates = driver.find_elements_by_css_selector('span.date.pcol2')
    for date in dates:
        post_list.append([date.text])
        
    pageNum += 1
    
post_infos = pd.DataFrame(post_list, columns=['date'])
post_infos.to_csv('post_infos(라인웍스).csv', encoding='utf-8-sig')

driver.quit()

문제는 1~10 페이지는 잘 긁어오지만 "다음" 버튼을 눌러야 나오는 11~20 페이지를 처리하는 것이었는데요. 크롬을 열자마자 "다음" 버튼을 누르고 시작하면 되겠다 고민하던 순간... 라인웍스 블로그를 다시 보니 UI가 2개 있는 것을 발견하였고... 지금 발견한 UI가 크롤링하기 훨씬 쉽다는 것을 깨달았습니다. (진작에 저한테 아래의 블로그 url을 줬다면... 왜 위와 같은 UI 페이지 url을 보여준 것인지 ㅠㅠ)

아래의 경우라면, 잔디 블로그를 긁어왔던 코드를 그대로 적용하면 될 듯하네요. 무한 스크롤을 하면 쭉쭉 긁어오게 될 것입니다. 

<출처: 라인웍스 공식 블로그>

 

728x90
반응형