프로젝트/COHO - 코인 호재 캘린더

[Django] 코호 - 실시간 코인 호재 모음 PROC 4

모영이 2021. 3. 17. 19:27

진짜 오류 찾기 힘들었지만 결국에는 내 실수. 하지만 해결해서 기분이 좋다.

 

해결한 문제

multiprocessing의 Process를 사용한 크롤링 병렬화

 

마주친 문제

multiprocessing의 변수 공유

검색해보면 알겠지만 (사실 여기서 막힌게 아니다)

multiprocessing().Manager().list() 이렇게 리스트 변수를 선언해서 함수의 인자로 넘겨주면 된다. 

 

multiprocessing.pool.MaybeEncodingError: Error sending result

'RecursionError('maximum recursion depth exceeded while getting the str of an object 

RecursionError: maximum recursion depth exceeded while pickling an object

<ListProxy object, typeid 'list' at 0x1df3dcad940; '__str__()' failed>

 

내가 구글에 검색한 오류들이다. 혹시나 비슷한 오류를 찾는 사람들에게 도움이 됐으면 좋겠다.

검색결과, 재귀함수의 제한이 걸려있어서 문제가 발생했다는 뜻이고 문자열이 아니라는 뜻이었다. 

재귀함수를 사용하지도 않는데 왜 이게 나오는지 너무 모르겠어서 문제점을 특정해봤다.

생각한 문제점 1 : urlopen에서 문제가 발생

생각한 문제점 2 : Manager().list() 사용의 오류

생각한 문제점 3 : result.append()의 실패

 

결국 답은 전처리 과정에 있었다.

수정전 : coin_title = coin_title_data[i].string

수정후 : coin_title = str(coin_title_data[i].string) 

beautifulsoup으로 select한 데이터를 .string 하면 당연히 str형태로 변환 해준 것인 줄 알았지만, 그렇지 않았다.

 

전체 코드

import os
import sys
from urllib.request import urlopen
from bs4 import BeautifulSoup
import multiprocessing
import time
import re

month = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11,
         'Dec': 12}

def getPageNumberFromcoinmarketcal():
    html = urlopen("https://coinmarketcal.com/en/")
    soup = BeautifulSoup(html, "html.parser")
    coin_maxpage_data = soup.select("a[class='page-link rounded']").pop()
    coin_maxpage = re.findall("\d+", str(coin_maxpage_data))
    return int(coin_maxpage.pop())


def packingDataFromcoinmarketcal(page_number, result):
    proc = os.getpid()
    url = "https://coinmarketcal.com/en/" + "?page=" + str(page_number)
    html = urlopen(url)

    # # 사이트에 문제가 있으면 함수 종료
    # if html.status != 200:
    #     return
    soup = BeautifulSoup(html, "html.parser")

    # 정보 -> 이름, 호재 시간, 추가된 시간, 제목, 상세내용
    coin_name_data = soup.select(
        "article.col-xl-3.col-lg-4.col-md-6.py-3 > div.card.text-center > div.card__body > h5.card__coins > a.link-detail")
    coin_goodnewstime_data = soup.select("h5[class = 'card__date mt-0']")
    coin_addedtime_data = soup.select("p[class = 'added-date']")
    coin_title_data = soup.select(
        "article.col-xl-3.col-lg-4.col-md-6.py-3 > div.card.text-center > div.card__body > a.link-detail > h5.card__title.mb-0.ellipsis")
    coin_detail_data = soup.select("p[class = 'card__description']")

    min_len = min(len(coin_name_data), len(coin_goodnewstime_data), len(coin_addedtime_data), len(coin_title_data),
                  len(coin_detail_data))

    # 전처리 이름[이름, 태그], 호재 시간[년, 월, 일], 추가된 시간[년, 월, 일], 제목[문자열], 상세내용[문자열]
    # 전처리 후 패킹
    one_page_data = []
    for i in range(0, min_len):
        # 이름 전처리
        coin_name = ' '.join(coin_name_data[i].string.split())
        coin_name = [coin_name[0: coin_name.find('(') - 1], coin_name[coin_name.find('(') + 1: coin_name.find(')')]]
        # 호재 시간
        coin_goodnewstime = coin_goodnewstime_data[i].string.split()
        coin_goodnewstime = coin_goodnewstime[:3]
        coin_goodnewstime[1] = str(month[coin_goodnewstime[1]])
        coin_goodnewstime.reverse()
        # 추가된 시간
        coin_addedtime = coin_addedtime_data[i].string.split()
        coin_addedtime = coin_addedtime[1:]
        coin_addedtime[1] = str(month[coin_addedtime[1]])
        coin_addedtime.reverse()
        # 제목
        coin_title = str(coin_title_data[i].string)
        # 상세내용
        coin_detail = ' '.join(coin_detail_data[i].string.split())

        # 패킹
        item_coin = {
            'name': coin_name,
            'goodnewstime': coin_goodnewstime,
            'addedtime': coin_addedtime,
            'title': coin_title,
            'detail': coin_detail
        }
        result.append(item_coin)



if __name__ == '__main__':
    start_time = time.time()
    manager = multiprocessing.Manager()
    result = manager.list()
    indxs = [i for i in range(1, getPageNumberFromcoinmarketcal() + 1)]
    procs = []

    for i, v in enumerate(indxs):
        proc = multiprocessing.Process(target=packingDataFromcoinmarketcal, args=(v, result))
        procs.append(proc)
        proc.start()

    for proc in procs:
        proc.join()
    print(time.time() - start_time)
    print(result)

 

해결해야 할 문제

데이터 전처리 수정, JSON파일 변환.