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

[Django] 코호 - 실시간 코인 호재 캘린더 PROC 9

모영이 2021. 3. 30. 23:01

오늘은 시간을 조금 들였다. 가끔 의욕이 많은 날이 있는 것 같다.

 

해결 한 문제

딕셔너리 구조를 바꿨다. 캡쳐도구로 그린거여서 글씨가 이상하다. 캘린더에 날짜별로 추가를 하기때문에 데이터를 날짜별로 가공하는게 좋겠다고 말했다. 같은 날짜에 같은 코인 정보가 여러개였고, 이를 묶어서 저장하기로 했다. 원래는 parser.py에서 크롤링 함수도 구현하고, 멀티프로세스도 돌렸는데 점점 복잡해져서 코인마켓컬 사이트 크롤링 함수를crawler_coinmarketcal.py여기에 넣고, 코인스캘린더 크롤링 함수를 crawler_coinscalendar.py여기에 넣었다. 훨씬 간단해진 느낌이다. 

 

마주친 문제

우선 시간이 90초가 넘게 걸린다. 멀티 프로세스를 사용해도 이렇다. 이건 어쩔수가 없는 것 같다. 코인스캘린더 사이트의 정보들이 너무 많다. 880개 정도다. 시간을 줄이는 방법을 찾아야겠지만, 찾아보니 멀티프로세스가 최선인 듯 싶다. 하지만 계속 찾아보겠다.  + 찾아보니깐 멀티 스레드와 멀티 프로세스를 둘다 사용하면 될 것 같다.

 

해결해야 할 문제

시간 줄이기.

 

crawler_coinmarketcal.py

from urllib.request import urlopen
from bs4 import BeautifulSoup
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):
    url = "https://coinmarketcal.com/en/" + "?page=" + str(page_number)
    html = urlopen(url)

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

    # 정보 -> 이름, 호재 시간, 추가된 시간, 제목, 상세내용
    coin_link_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")
    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_date_data = soup.select("h5[class = 'card__date mt-0']")
    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")

    min_len = min(len(coin_name_data), len(coin_date_data), len(coin_title_data),)

    # 전처리 이름[이름, 태그], 호재 시간[년, 월, 일], 추가된 시간[년, 월, 일], 제목[문자열], 상세내용[문자열]
    # 전처리 후 패킹
    for i in range(0, min_len):
        # 링크 전처리
        coin_link = str(coin_link_data[i])
        coin_link = coin_link[coin_link.find('href="') + 6 : coin_link.find('" title')]
        coin_link = "https://coinmarketcal.com" + coin_link
        # 이름 전처리
        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_date = coin_date_data[i].string.split()
        coin_date = coin_date[:3]
        coin_date[1] = str(month[coin_date[1]])
        coin_date.reverse()
        coin_date = coin_date[0] + "-" + coin_date[1] + "-" + coin_date[2]
        # 제목
        coin_title = str(coin_title_data[i].string)
        # 패킹
        item_coin = {
            'symbol': coin_name[1],
            'name' : coin_name[0],
            'date' : coin_date,
            'title': coin_title,
        }
        print(item_coin)
        result[coin_link] = item_coin

 

crawler_coinscalendar.py

from urllib.request import urlopen
from bs4 import BeautifulSoup
import collections
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 getPageNumberFromcoinscalendar():
    html = urlopen("https://coinscalendar.com/")
    soup = BeautifulSoup(html, "html.parser")
    coin_maxpage_data = soup.select("a[class='page-link']").pop()
    coin_maxpage = str(coin_maxpage_data)
    coin_maxpage = coin_maxpage[coin_maxpage.find("page/") + 5 : coin_maxpage.find('">')]
    return int(coin_maxpage)

def packingDataFromcoinscalendar(page_number, result):
    url = "https://coinscalendar.com/" + "page/" + str(page_number)
    html = urlopen(url)

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

    # 정보 -> 이름, 호재 시간, 추가된 시간, 제목, 상세내용
    coin_link_data = soup.select("a[class='event-name']")
    coin_name_data = soup.select("a[class='coin-name']")
    coin_date_data = soup.select("div[class='coin-date']")
    coin_title_data = soup.select("a[class='event-name']")

    min_len = min(len(coin_name_data), len(coin_date_data), len(coin_title_data), len(coin_link_data))
    # print(coin_link_data)
    # print(coin_name_data)
    # print(coin_date_data)
    # print(coin_title_data)
    # 전처리 이름[이름, 태그], 호재 시간[년, 월, 일], 추가된 시간[년, 월, 일], 제목[문자열], 상세내용[문자열]
    # 전처리 후 패킹
    for i in range(0, min_len):
        # 링크 전처리
        coin_link = str(coin_link_data[i])
        coin_link = coin_link[coin_link.find('href="') + 6 : coin_link.find('">')]
        coin_link = "https://coinscalendar.com" + coin_link
        # 이름 전처리
        coin_name = str(coin_name_data[i])
        coin_symbol = coin_name[coin_name.find('(') + 1 : coin_name.find(')')]
        coin_name = coin_name[coin_name.find('">') + 2: coin_name.find("<small>")-1]
        # 호재 시간
        coin_date = coin_date_data[i].string.split()
        coin_date = coin_date[:3]
        coin_date[1] = str(month[coin_date[1]])
        coin_date.reverse()
        coin_date = coin_date[0] + "-" + coin_date[1] + "-" + coin_date[2]
        # 제목
        coin_title = str(coin_title_data[i].string)
        # 패킹
        item_coin = {
            'symbol': coin_symbol,
            'name' : coin_name,
            'date' : coin_date,
            'title': coin_title,
        }
        print(item_coin)
        result[coin_link] = item_coin

 

parser.py

import json
import collections
import multiprocessing
import time
import crawler_coinmarketcal
import crawler_coinscalendar
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "websaver.settings")
import django
django.setup()
from parsed_data.models import BlogData

def preprocessingDict(dic : dict):
    coin_dict = collections.defaultdict(dict)
    for key, value in dic.items():
        if value['symbol'] in coin_dict[value['date']]:
            coin_dict[value['date']][value['symbol']].append([key, value['title'], value['name']])
        else:
            coin_dict[value['date']][value['symbol']] = [[key, value['title'], value['name']]]
    return coin_dict

if __name__ == '__main__':
    start_time = time.time()
    manager = multiprocessing.Manager()
    result = manager.dict()

    procs = []

    for i in range(1, crawler_coinmarketcal.getPageNumberFromcoinmarketcal() + 1):
        proc = multiprocessing.Process(target=crawler_coinmarketcal.packingDataFromcoinmarketcal, args=(i, result))
        procs.append(proc)
        proc.start()

    for i in range(1, crawler_coinscalendar.getPageNumberFromcoinscalendar() + 1):
        proc = multiprocessing.Process(target=crawler_coinscalendar.packingDataFromcoinscalendar, args=(i, result))
        procs.append(proc)
        proc.start()

    for proc in procs:
        proc.join()

    print(time.time() - start_time)
    print(json.dumps(preprocessingDict(result.copy()), indent="\t"))
    # for t, l in result.items():
    #     BlogData(title=t, link=l).save()