Codong's Development Diary RSS 태그 관리 글쓰기 방명록
2021-03-31 21:08:26

개요


scraping을 진행하면서, beautiful soup으로 하나씩 셀렉터로 접근해서 a_tag의 href를 가져와서 그곳에 들어가서 데이터를 가져오는것이 목표였다.

문제는 속도가 너무 느린것이다..... 약 10000번 정도를 진행하는데, 너무 오래걸려서 다른 방법 없을까 찾다가, scraping을 위한 scrapy, autoscraper 등 다른 라이브러리들을 찾아봤다. 하지만 이미 쓰는거에서 Multiprocessing을 이용해서 사용하는 방법이 있길래 이것을 이용해보기로했다.

추가로 동시성을 활용한 Asyncio scraping에 대해서 알고싶은 분은 참고 부탁드립니다!

2021.08.07 - [python/Scraping] - [Python] 동시성(Concurrency) Asyncio scraping

 

[Python] 동시성(Concurrency) Asyncio scraping

개요 내가 예전에 멀티 프로세싱(Multi processing)을 이용한 scraping 방법에 대해 포스팅을 한 적이 있다. (궁금하신 분들은 아래 링크 참조) 2021.03.31 - [python/Scraping] - [Python] beautifulsoup multipr..

codong.tistory.com

 

Task


가져온 데이터를 종류별(ex. 제목:내용)로 dictionary로 구분해서 담고싶었다. 우선 코드부터 확인해보자.

import requests
from bs4 import BeautifulSoup
from multiprocessing import Pool, Manager
from itertools import repeat

def crawl_data(word,dic):
    url=f'https://www.coupang.com/np/search?component=&q={word}&channel=user'
    response = requests.get(url)
    soup=BeautifulSoup(response.text,'html.parser')

    div_=soup.find_all('div',id="name")
    # selector 부분 생략 ...

    dic[title]=price

if __name__=='__main__':
    manager = Manager()
    result_dic = manager.dict()

    # request의 parameter 리스트
    search_list=['삼겹살','불고기','오리고기','돼지고기', ... ]

    pool = Pool(processes=4) #4개의 프로세스 동시에 작동

    # 각 프로세스별로 딕셔너리 적용 시키기 위해 repeat 사용.
    pool.starmap(crawl_data, zip(search_list,repeat(result_dic)))
    print(result_dic)

위와 같이 크롤링 할 검색어와 manager를 사용해서 dictionary를 만들어야 전역으로 사용이 된다고 한다.
게다가 repeat를 사용해서 인자로 주고, 함수와 zip으로 묶어서 pool.starmap의 인자로 넣어준다.

이렇게 딕셔너리로 담아서 json파일로 만들어서 사용할 수도 있다.

 

➕ 추가적인 예제( 2021/04/15 수정 )


다시 사용할 일이 있어서 pool을 이용한 추가 예제를 적어 본다. multiprocessing 은 특히 담으려는 데이터의 순서가 상관없을 때 사용하기 좋은 것 같다. 어떠한 데이터를 불러와서 순서 상관없이 리스트에 담기만 할 것이라면, 이것만 생각하자.

🙋 각 프로세서에게 해야할 일(실행함수) 알려주고, 필요한 재료(파라미터) 손에 쥐어주기!

코드부터 보는게 낫겠지? 예를 들어 문장 데이터를 가져와 명사만 추출해서 리스트에 담는다고 가정해보자.

from multiprocessing import Pool, Manager
from konlpy.tag import Okt


def split_str(str,okt,result_list):
    nouns=okt.nouns(str)
    result_list.append(nouns)

if __name__=='__main__':
      corpus=[                    # 문장 100개가 들어있다 가정하자.
      ['안녕하세요 파이썬 너무 어려워요']
      ['에이 무슨 소리에요']
      ['파이썬이 얼마나 쉬운데']
      ['사실 진짜 어려움']
      ...
      ['그래도 포기하지 말고 해보자']
      ] 
    okt=Okt()                    # Okt 전처리 라이브러리 객체 생성

    process = multiprocessing.cpu_count())     # 프로세서 개수 확인

    m = Manager()                # 데이터 공유를 위한 Manager 객체 생성
    result=m.list()            # 결과 리스트 생성

    pool = Pool(process)        # default 값은 4. 4가 적당한 거 같다.

    # 가장 중요한 실행 부분. starmap의 첫번째 인자로 실행 함수를 주고, 
    # 두번째 인자로 실행 함수의 파라미터를 리스트에서 하나씩 꺼내 튜플로 담아서 하나씩 넘긴다 
    pool.starmap(split_str, [(str, okt, result) for str in corpus])

    pool.close()                # 끝나면 닫아주고
    pool.join()                # 다른 프로세서들이 끝날 때까지 기다린다.

    print(result)                # 결과 확인

 

마무리


가뜩에나 시간이 부족한 우리에게 딱 필요한 기술이지 않나 싶다. 컴퓨터가 신나게 일하도록 해주자~~ 깊게 공부하진 못해서 아쉽긴한데... 언젠가 다시 알게될 날이 있지 않을까..? 그때그때 수정하자 😄

 

reference

'python > Scraping' 카테고리의 다른 글

[Python] 동시성(Concurrency) Asyncio scraping  (0) 2021.08.07