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 모듈을 사용하자 병렬처리 작업의 결과물을 리턴 받는 등 다양한 함수를 제공한다 참조링크
자세히 보기

Beautifulsoup으로 이미지 크롤링 안될 때 다른 방법으로 크롤링하기

이미지 태그나 클래스명 등으로 크롤링 하려는데 안될 때 어떻게 해야할까?

여러가지 방법이 있겠지만 이번 글에서는 python, re(정규식) 모듈, requests 모듈을 이용해서 크롤링을 해보려고한다
다음 이미지에서 강아지를 검색하면 브라우저 검색창에 아래 url이 나온다

1
https://search.daum.net/search?w=img&nil_search=btn&DA=NTB&enc=utf8&q=%EA%B0%95%EC%95%84%EC%A7%80

이 url을 이용해서 python으로 request를 날려보자
아래 사진을 보면 이미지 불러오는 url이 보인다 저 url을 정규식으로 추줄해보자
더 좋은 정규식이 있을 텐데 저는 저렇게 해서 추출했습니다
(정규식 내용은 분량이 큽니다 관심이 있으면 따로 찾아보자)
code url

  1. 코드를 보자 정규식을 선언하고
  2. url을 뽑아내는 전처리 작업을하고
  3. 이미지를 저장하는 코드룰 볼 수 있다
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
import requests
import re
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)

#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}')

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

t2 = time.time()

print(t2-t1)

이렇게 하면 이미지가 저장되는 걸 볼 수 있다
강아지 이미지
작업이 4초 넘게 걸렸는데 다음 포스트에서는 thread 와 비동기 함수를 사용하여
작업 시간을 단축시키는 포스트를 올려보겠습니다

하둡 공부 순서

하둡 공부 순서

  1. HDFS
  2. MapReduce
  3. YARN
  4. Avro
  5. Parquet
  6. Flume
  7. Sqoop
  8. Pig
  9. Hive
  10. Crunch
  11. Spark
  12. Hbase
  13. Zookeeper

하둡 에코 시스템

하둡 에코 시스템

HDFS, MapReduce, YARN은 하둡 기반 구성 요소라서 정확하게 이해할 필요성이 있다
다른 요소들은 필요한 순서대로 공부하면 될 듯

속도를 높이는 파이썬 코드

기존 파이썬 코드를 빠르게 만드는 방법

  • 상황에 맞는 정확한 데이터 구조 사용
    (list, tuple, set, dict, etc…)
  • for 루프 대신 while 루프 사용
  • 컴프레헨션 사용
  • 복수 할당 사용 ( a, b = 1, 2)
  • 될 수 있으면 global 키워드를 줄이자 연산 작업에 많은 시간을 소요한다
  • 라이브러리를 활용
  • 제너레이터 사용
  • .사용 자제 (use sqart instead of math.sqart)
  • 무한 반복문에 1 사용 True 사용 보다 런타임 줄일수 있음
  • 큰 데이터 처리는 pandas, numpy, scipy 사용

참조링크

하둡을 왜 쓰는 것일까?

하둡을 왜 쓰는 것일까?

빅데이터 처리

  • 인터넷 사용자들의 기록(비정형 데이터)
  • 생물학의 데이터 과학 등

대용량 처리하기에는 기존 RDBMS는 비효율적

  • 비정형 데이터 분석 불가
  • 확장하기가 힘들다
  • 빅데이터 처리하기에 운영 비용이 기하급수적으로 비싸진다
  • 빅데이터 처리 속도가 하둡 보다 느리다