Python 병렬처리로 크롤링 시간 단축하기

thread 와 concurrent.futures 사용으로 병렬 처리하기

1. thread 사용으로 병렬 처리

저번 코드에서 save_img 함수를 multi thread로 실행하면 좀 더 빠른 결과물을 얻을 수 있을 것 같다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import re
import threading
import time

t1 = time.time()
reg = re.compile('oimgurl: ".{0,300}", cpid')

url = 'https://search.daum.net/search?w=img&nil_search=btn&DA=NTB&enc=utf8&q=%EA%B0%95%EC%95%84%EC%A7%80'
html = requests.get(url=url)
html_raw_data = str(html.content)

reg_iter = reg.finditer(html_raw_data)
thread_list = []


def save_img(idx, img_url):
res = requests.get(img_url).content
with open(f'{idx}.jpg', 'wb') as f:
f.write(res)
print(f'save {idx}')


for idx, res_data in enumerate(reg_iter):
img_url = res_data.group().split('oimgurl:')[1].split(', cpid')[0].replace('"', '')
thread_worker = threading.Thread(target=save_img, args=(idx, img_url))
thread_worker.start()
thread_list.append(thread_worker)

for thread in thread_list:
thread.join()

t2 = time.time()
print(t2-t1)

작업결과

작업 시간이 1초대로 단축된 걸 확인 할 수 있다

2. concurrent.futures 사용으로 병렬 처리하기

concurrent.futures는 비동기 처리 고수준 인터페이스 모듈이다 이 모듈을 써서 작업 시간을 줄여보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import requests
import re
import time
from concurrent.futures import ThreadPoolExecutor

t1 = time.time()
reg = re.compile('oimgurl: ".{0,300}", cpid')

url = 'https://search.daum.net/search?w=img&nil_search=btn&DA=NTB&enc=utf8&q=%EA%B0%95%EC%95%84%EC%A7%80'
html = requests.get(url=url)
html_raw_data = str(html.content)

reg_iter = reg.finditer(html_raw_data)
thread_list = []

#url 이미지를 저장하는 함수
def save_img(idx, img_url):
res = requests.get(img_url).content
with open(f'{idx}.jpg', 'wb') as f:
# 이미지 관련 작업은 pillow 모듈을 사용하는게 좋다
# 예제에서는 사용 안함 (따로 설치가 필요)
f.write(res)
print(f'save {idx}')


with ThreadPoolExecutor(max_workers=10) as executor:
for idx, res_data in enumerate(reg_iter):
# url 을 뽑아내는 전처리 작업
img_url = res_data.group().split('oimgurl:')[1].split(', cpid')[0].replace('"', '')
executor.submit(save_img, idx, img_url)

t2 = time.time()
print(t2 - t1)

작업결과

마찬가지로 작업 시간이 1초대로 단축된 걸 확인 할 수 있다

결론

  • I/O 작업이 있을 때 병렬 처리 작업을 활용하여 작업 시간을 단축시킬수 있다
  • 상황에 따라 다르지만 될 수 있으면 thread 모듈보단 고수준 비동기 concurrent.futures 모듈을 사용하자 병렬처리 작업의 결과물을 리턴 받는 등 다양한 함수를 제공한다 참조링크
자세히 보기