• mksong8

[데이터 수집] 파이썬으로 구현하는 비동기식 웹스크래핑


​다양하고 복잡한 정보가 웹사이트에서 제공됨에 따라 비동기 웹스크래핑의 난이도도 높아지고 있습니다. 또한 점점 더 많은 기업들이 데이터 분석 결과에 따라 의사결정을 하는 경향이 늘어나는 추세입니다. 동기식 웹스크래핑을 사용한다 하더라도 고객이 요구하는 일반적인 사항은 어렵지 않게 만족시킬 수 있습니다. 그러나 수집할 데이터의 양이 많다면 시간이 많이 걸리긴 합니다.

이번 글에서는 웹사이트에서 많은 양의 데이터를 수집하는 동안 발생하는 문제를 살펴 보기로 하겠습니다. 또한 방대한 양의 데이터를 수집하는데 있어 빠르고 효과적으로 크롤러를 작동시키는 비동기식 웹스크래핑에 대해 알아보겠습니다.

웹스크래핑이란?

웹스크래핑은 웹사이트에서 데이터를 수집하는 것을 말합니다. 수집해야 할 데이터의 양이 적으면 수동으로 복사 & 붙이기를 하는 것이 일반적인 방법이지만 수집해야 하는 데이터의 양이 증가하면 웹스크래핑이 필요합니다. 웹스크래핑을 하기 위한 도구가 다양하게 존재하는데, Beautiful Soup와 Scrapy와 같은 라이브러리는 Python에서 사용할 수 있는 웹스크래핑 도구 중 하나 입니다.

웹스크래핑으로 데이터 분석이나 기타 다른 용도에 필요한 웹데이터를 수집합니다. 수집한 데이터는 일반적으로 PC나 데이터베이스에 저장합니다. 웹스크래핑은 웹사이트에서 데이터를 수집하므로 웹사이트를 분석하여 필요한 데이터가 어디에 있는지 미리 알아두어야 합니다.

웹스크래핑의 도전 과제

웹스크래핑은 웹사이트에서 데이터를 수집하려는 사람에게는 유용한 방법이지만, 웹사이트의 관리자는 웹스크래핑으로 발생되는 문제를 해결해야 하는 경우가 종종 발생하기도 합니다. 아마도 웹사이트 관리자는 웹스크래핑을 막아야 할 필요성을 느낄 수 있을 것입니다. 그래서 웹사이트 관리자는 지나치게 많은 요청을 보내는 IP를 찾아내고 그 IP를 차단합니다.

일반적으로 수집 해야하는 데이터의 양이 일정수준 이상으로 방대하면 웹스크래핑 작업에 소요되는 시간이 굉장히 길어지게 되고 결국엔 실패할 수도 있습니다. 전체 프로세스의 처리 속도가 떨어지지 않으면서 웹사이트에서 방대한 데이터를 수집 할 수 있는 솔루션이 필요합니다. 이와 같은 문제를 해결하기 위해 바로 ​비동기식 프로그래밍이 필요합니다.

다음에서 비동기식 프로그래밍으로 방대한 데이터를 빠르고 효율적으로 수집하는 방법에 대해 알아보겠습니다.​

















비동기식 웹스크래핑으로 문제 해결하기

비동기 웹스크래핑을 설명하기 전에 먼저 비동기 프로그래밍에 대해 알아보도록 하겠습니다. 간단한 예를 들어보겠습니다.

유펜씨는 매일 아침 출근을 하기 위해 샤워를 하고 서류를 챙기는 등의 일을 합니다. 이 일을 다 하는데 보통 45분이 걸리는데, 어떻게 하면 이 일을 단축하거나 최적화 할 수 있을까요?

일단 모든 작업을 직렬이 아닌 병렬로 진행 할 수 있을 것입니다. 먼저 물을 데우고 물이 데워지기를 기다리면서 서류를 챙깁니다. 그리고 물이 데워지자마자 샤워를 하면 물이 데워지는 동안 서류를 챙기는데 시간을 효과적으로 사용한 꼴이 됩니다. 이렇게 하면 서류를 준비하는데 걸리는 출근 준비 시간을 15분 줄일 수 있습니다. 이것이 바로 비동기식 프로그래밍의 핵심 개념입니다.

비동기식 웹스크래핑을 통해 방대한 규모의 웹사이트에서 데이터를 동시에 빠르게 수집할 수 있습니다. 바로 파이썬의 병렬 쓰레드(Parallel Thread)를 이용하면 해결 할 수 있습니다. 한 페이지의 데이터를 모두 수집 완료할 때까지 더 이상 기다릴 필요가 없습니다.

비동기식 웹스크래핑의 작동방식

대부분의 프로그래핑 언어에서 동기식과 비동기식의 성능 차이는 단순한 이유에서 발생합니다. 프로그램 코드는 위에서 아래로 실행되며 이런 방식이 동기식 프로그래밍 입니다. 한줄씩 프로그래밍이 실행되다가 함수가 호출되면 호출된 함수가 실행되고 함수를 호출한 그 다음 줄 부터 다시 프로그래밍이 실행됩니다.

비동기식 웹스크래핑의 경우에는 크롤러가 병렬로 실행되며 한줄씩 프로그래밍을 실행 하지 않습니다. 한 크롤러가 작업을 마치면 다른 작업을 바로 실행하거나 대기중인 처리해야 할 작업을 전달 받는 즉시 작업을 시작합니다.
















파이썬을 이용한 비동기식 웹스크래핑

이번에는 파이썬을 이용하여 비동기식 웹스크래핑을 구현해 보겠습니다. 동기식과 비동기식 웹스크래핑을 비교해 보기 위해 두가지 방법 모두 프로그래밍을 구현 하여 실행 시간의 차이를 살펴보도록 하겠습니다.

파이썬은 Beautiful Soup 라이브러리를 이용하여 웹사이트의 데이터를 수집합니다. 아래 예제는 휴대 전화 관련 데이터가 있는 웹사이트 10개 페이지 링크에서 데이터를 수집 합니다. 10개의 페이지에서 가능한 빠른 시간내에 모든 데이터를 수집해 보도록 하겠습니다.

먼저 동기식 프로그램부터 시작하도록 하겠습니다. 다음의 코드는 변수를 초기화 하는 부분 입니다.

### Importing libraries ###

from bs4 import BeautifulSoup

import grequests

import requests

import time</span></pre>

### Starting the timer ###

start_time = time.time()

### List of urls to scrape data from ###

links = [

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=1",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=2",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=3",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=4",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=5",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=6",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=7",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=8",

"https://www.croma.com/phones-wearables/mobile-phones/c/10?q=%3Arelevance%3AskuStockFlag%3Atrue&page=9"

]

동기식 웹스크래핑

변수를 설정하고 휴대폰 데이터 수집을 시작합니다. 수집해야 할 데이터는 각각의 웹링크 페이지에 있는 제품명, 제품 가격, 할인율 입니다. 리퀘스트 라이브러리를 이용하여 웹컨텐츠를 가져오고 BeautifulSoup 라이브러리를 이용하여 컨텐츠 구문을 분석하고 필요한 부분을 가져옵니다. 아래 코드는 설명한 부분을 구현한 코드 입니다.

for link in links:

req = requests.get(link)

soup = BeautifulSoup(req.text, 'lxml')

lists = soup.find_all('a', attrs={'class':"product__list--name"})

#print(lists[0].text)

prices = soup.find_all('span', attrs={'class':"pdpPriceMrp"})

#print(prices[0].text)

discount = soup.find_all("div", attrs={"class":"listingDiscnt"})

#print(discount[0].text)

print("--- %s seconds ---" % (time.time() - start_time))


위의 코드를 실행시키면 다음과 같은 결과 화면이 나타납니다. 10개의 페이지에서 각각의 데이터를 수집하는데 약 4초가 걸렸습니다.








다음은 비동기 프로그래밍 예를 보여 드리겠습니다. 똑같은 예제로 아래에 비동기식 프로그래밍을 구현해 보겠습니다.


비동기식 웹스크래핑

비동기식 웹스크래핑을 실행하기 위해 GRequests를 사용합니다. 한 페이지의 데이터 수집이 완료 될때까지 기다리지 않고 모든 웹페이지의 데이터를 병렬로 수집합니다. GRequests를 이용하면 Gevent Request을 이용하여 비동기식 HTTP 요청을 구현 할 수 있습니다.

아래의 코드는 10개의 서로 다른 웹사이트 링크에서 데이터를 수집하기 위해 비동기식 웹스크래핑을 구현한 것입니다.

reqs = (grequests.get(link) for link in links)

resp = grequests.imap(reqs, grequests.Pool(10))

for r in resp:

soup = BeautifulSoup(r.text, 'lxml')

results = soup.find_all('a', attrs={"class":'product__list-name'})

#print(results[0].text)

prices = soup.find_all('span', attrs={'class':"pdpPriceMrp"})

#print(prices[0].text)

discount = soup.find_all("div", attrs={"class":"listingDiscnt"})

#print(discount[0].text)

print("--- %s seconds ---" % (time.time() - start_time))


위 코드를 실행해 보면 데이터를 비동기식으로 수집하는 것이 얼마만큼의 어떤 효과가 있는지 쉽게 확인 할 수 있습니다. 비동기식으로 10개의 페이지에서 각각의 데이터를 수집하는데 약 2.8초가 걸렸습니다.







​​

맺는말

결론적으로, 10개의 웹페이지에서 휴대폰 데이터를 동기식으로 데이터를 수집하는 경우보다 비동기식으로 데이터를 수집하는 경우 1.2초를 절약할 수 있었습니다.

10개의 웹페이지 에서만 데이터를 수집하는 경우는 비동기식이나 동기식으로 데이터를 수집하는데 1.2초의 차이는 실무에서 별 차이가 없어 보이지만 실제로 방대한 양의 데이터를 수집할 경우 이 차이는 유의미한 결과를 가져다 줄 것입니다. 그리고 비동기식 웹데이터 수집은 데이터를 수집을 하는데 걸리는 시간을 단축시켜줄 뿐만 아니라 안정적으로 데이터를 수집하는데 필요한 기본 요소임에 틀림이 없습니다.



조회 161회

​고객센터

Tel: 02-596-8900  Fax : 02-6930-5709

10시 - 오후 7시(토, 일요일 및 공휴일은 휴무)

개인정보관리책임자 : 황재준   상호 : 유펜솔루션   대표자 : 김재훈   사업자등록번호 : 426-86-00939
주소 : (본사)대전광역시 유성구 엑스포로446번길 38, 3층 302호 / (지사 및 연구소)서울시 성동구 연무장 15길 11, B동 2층
​ⓒ 2019 UpennSolution Co., Ltd. All rights reserved.