Let’s go!

  • 웹 크롤러+워드클라우드

    웹 크롤러+워드클라우드

    python으로 보기싫은 좃선, 중앙 제안 키워드를 빼고 뉴스를 검색해 보자. 계획은 아래와 같다.

    • 웹 크롤러를 만들어 조선, 중앙 인터넷 페이지를 접속한다.
    • 헤드라인을 긁어 파일로 저장한다.
    • 파일을 읽어 워드클라우드로 주요 키워드를 확인한다.
    • 구글뉴스로 키워드를 검색어 제외한다.

    웹 크롤러는 인터넷에 많이 공개되어 있어 쉽게 만들었다. 코드 몇 줄로 원하는 기능을 구현했다. 어려웠던 점은 복사한 코드를 수정한 점이다. 인터넷 코드가 json 형식으로 파일을 저장했다. 이를 텍스트로 변경하는 과정에 문제가 있었다. csv의 writerow를 dictionary 인자로 넣으면 한 글자마다 컴마를 찍는다. dictionary를 [] 괄호로 감싸야 된다.

    워드클라우드 역시 쉽다. 한글폰트를 명시하여 generate하면 바로 된다. 나머지 부족한 부분(plot을 파일로 저장 등)을 과거 코드에서 복사해서 해결했다.

    구글뉴스가 – 기호로 검색어를 제외하는 기능을 제공한다. +키워드없이 모두 -로 넣으면 범위를 너무 크게 잡는다. 한국어, 최근 1주일 등 범위를 좁혔다. 검색어 제외와 보통 검색을 비교해 보면 좀 효과가 있는 듯 하다.

    # -*- coding: utf-8 -*-
    import requests
    from bs4 import BeautifulSoup
    import os
    import csv
    
    from wordcloud import WordCloud
    
    import matplotlib
    matplotlib.use('Agg')
    import matplotlib.pyplot as plt
    
    
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    
    req = requests.get('http://www.chosun.com/')
    req.encoding=None
    html = req.text
    
    
    soup = BeautifulSoup(html, 'html.parser')
    
    
    #조선일보는 dl형식으로 헤드라인을 작성한다.
    my_contents = soup.find_all('dl', {'class':'news_item'}, 'dt')
    
    
    data = {}
    
    
    #임의의 키를 만들어서 저장.
    index = 0
    
    for content in my_contents:
        data[index] = content.text
        index = index + 1
    
    
    ###중앙일보
    req = requests.get('https://joongang.joins.com/')
    req.encoding=None
    html = req.text
    soup = BeautifulSoup(html, 'html.parser')
    
    #중알일보는 li형식으로 헤드라인을 만든다.
    my_contents = soup.find_all('li')
    
    
    for content in my_contents:
        data[index] = content.text
        index = index + 1
    
    print(data.values())
    
    with open(os.path.join(BASE_DIR, 'result.csv'), 'w', encoding='utf8') as csv_file:
        writer = csv.writer(csv_file)
        for key in data.keys():
        #writer = csv.DictWriter(csv_file, data.keys())
        #writer = csv.writer(csv_file, delimiter=',')
            #print(data[key])
            writer.writerow([data[key]])
    
    csv_file.close()
    
    ##word cloud
    
    
    text = open(os.path.join(BASE_DIR, 'result.csv'), 'r', encoding='utf8').read()
    
    #한글 폰트를 사용하기 위해, 명시
    wordcloud = WordCloud(font_path='/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf', background_color='white').generate(text)
    
    plt.figure()
    plt.imshow(wordcloud, interpolation="bilinear")
    plt.axis("off")
    plt.show()
    plt.savefig('./wordcloud.jpg',format='jpg', dpi=300)
    

    고해상도 이미지를 원하면 아래와 같이 작업한다.

    wordcloud = WordCloud(width=800, height=400).generate(text)
    plt.figure( figsize=(20,10) )
    plt.imshow(wordcloud)

    참조 사이트

    https://datamod.tistory.com/104

    json으로 저장할 경우, utf8 방식으로 저장.

    https://beomi.github.io/2017/01/20/HowToMakeWebCrawler/

    웹 크롤러 기본.

    http://pythonstudy.xyz/python/article/403-%ED%8C%8C%EC%9D%B4%EC%8D%AC-Web-Scraping

    requests 한글 사용.

    https://twpower.github.io/84-how-to-use-beautiful-soup

    beautifulsoup 기본.

    https://medium.com/@gis10kwo/converting-nested-json-data-to-csv-using-python-pandas-dc6eddc69175

    json to csv, pandas

    https://www.programiz.com/python-programming/working-csv-files

    write to csv

    https://stackoverflow.com/questions/1816880/why-does-csvwriter-writerow-put-a-comma-after-each-character

    writerow 할 때, 각 글자뒤에 comma 삽입될 때.

    https://myjamong.tistory.com/48

    wordcloud 사용에 한글 폰트 설정

    https://stackoverflow.com/questions/28786534/increase-resolution-with-word-cloud-and-remove-empty-border/28795577

    고해상도 wordcloud

  • 일자리 전쟁

    일자리 전쟁

    isbn: 9788991186859

    세계 인구 70억명 중 일하고 싶어하는 사람이 30억명이다. 그러나 좋은(정규직) 일자리는 12억개만 있다. 제한된 자원을 차지하기 위한 경쟁이다. 전쟁이다. 이렇게 시작한다.

    거창한 시작과 다르게, 초점은 오직 미국에 있다. 2010년 나온 책이 현재 미국에 사정없이 따귀 맞는 중국 상황을 반영하지 못했다. 과거 미국이 떠오르는 중국 위협에 대응하기 위해 혁신이 필요하다 주장했다.

    미국이 세계 2차 대전 일본과 독일을 이겼다. 이 후 경제 경쟁에서 다시 일본과 독일을 이겼다. 너무나 미국 중심적이다.

  • 플랫폼, 시장의 지배자

    플랫폼, 시장의 지배자

    isbn: 9788997396665

    맹자를 너무 오랫동안 읽었다. 이 책은 금방 읽혔다. 상식을 정리했다.

    여러 종류 IT 서비스 플랫폼을 설명했다. 가장 확실한 플랫폼 OS, 사회적 네트웍 페이스북, 검색엔진 구글, 가상현실 오큘러스 리프트 등 요즘 뜨고 과거 유명했던 서비스와 제품을 소개했다.

    IT 업계 외 자동차 제조업도 플랫폼을 사용한다. 그 효과는 자원을 효율적으로 이용하고, 시장에서 제품 영향력을 키운다. 제조업에는 개발자가 그 업계에 속해있다. 플랫폼이 제한적 영향을 준다. 다양한 차종을 개발할 수 있는 정도다.

    그러나 IT 플랫폼 개발자는 많다. 어느 회사에 속해있지도 않다. 개발자가 편한 플랫폼을 성공한다. 개발자와 플랫폼 디자이너와 의사소통이 중요하다. 일관된 철학, 기준으로 여러 개발자를 감동시켜야 한다. 소위 너드가 종교를 창시하고 그 추종자를 감동시켜야 한다. 양덕이 많은 미국에서 이런 플랫폼을 많이 나오는게 이치에 맞다.

    한국에서 덕질할 시간도 없다. 경영자가 개입하면 초기 철학은 숨어버린다. 이래서 한국 IT 업계가 감동 플랫폼을 못 만든다. 병맛나는 짓을 하도록 충분한 시간과 사회적 인식이 필요하다. 스마트폰은 늦었지만 다음 제품 플랫폼이 한국에서 나오길 기대한다.

  • 이우재의 맹자 읽기

    이우재의 맹자 읽기

    isbn: 9788950935160

    드디어 맹자 완역을 읽었다. 종이책도 800 페이지를 넘겼는데 과거 죽간에 기록되었을 때 상상된다. 정말 수레가 필요하다.

    공자가 죽고 수백년 지나 맹자가 활동했다고 알았다. 그러나 그 차이가 고작 100년이다. 이 사이가 춘추시대와 전국시대를 나눈다. 춘추시대를 떠돈 공자는 자신을 알아주지 않는 군주를 한탄하고, 세상을 떠돌다 죽었다. 그러나 맹자는 더 치열한 전국시대를 자신있게 살았다. 제후가 불러도 섣불리 움직이지 않았다. 그 뜻을 따라주지 않으면 과감하게 떠났다.

    이런 자신있던 맹자 의지와 다르게 유가가 전국시대를 끝냈을지 의문이다. 진시황제가 유가를 받아들였다면 전국을 통일했을까? 사람이 착하게 산다면 천하가 그 뜻을 따라줄까? 그러면 지금 불량국가 존재는 어떻게 설명해야 하나? 과거 제국주의 국가를 누가 심판했는가? 미국이 정의를 실현하기 위해 2차 대전에 개입했는가? 모두 설명할 수 없다. 능력있는 군주, 집중화 권력, 훌륭한 장수, 다른 나라를 압도하는 경제력이 전국시대를 끝낼 수 있었다. 혼란을 끝내는 강함이 유가에 없다.

    이미 위무제가 능력위주 인사로 국가를 운영해야 한다 보여줬다. 지금도 효과적인 방법이다. 과거, 현대 훌륭한 지도자는 능력에 맞게 그 인물에게 자리를 주었다. 이 과정에 많은 비극과 갈등이 있었다. 영국 동인도회사, 미국의 석유/철도재벌, 2차 대전 독일군 등 악하나 그 분야 전문가는 너무나 많다. 유가는 현실을 소극적으로 바라본다. 초나라, 진나라 강함의 이유를 설명하지 않고, 때를 기다리는 의지가 강하다. 적극적으로 행동해도 어려운데 언제까지 기다리는가? 현실에 분노하고, 남을 억압하고, 욕망을 추구함으로 세상을 바꾸겠다는 의지가 약하다. 세계는 착한 방향으로 변하지 않았다.

    동양 관료, 엘리트가 광신적으로 유가를 접하다보니 세상을 바꿀 기회를 놓쳤고, 새로운 흐름을 타지 못했다. 유가로 국가를 운영할 수 없다. 모든 능력있는 사람이 착할 수 없으니까. 그러나 개인 수양에는 사용할만 하다.

  • Qlik으로 수입지출 분석

    새로배운 Qlik으로 작년 수입/지출을 분석했다. 뱅크샐러드를 사용하면 1년간 수입/지출을 파일로 받을 수 있다. 인터넷에서 제공하고 있는 일별 주유가격과 내가 과거 사용한 주유비용을 보면 아래와 같다.

    • 2019년 2월에 가장 많이 소비했다.
    • 평균기름 가격이 다행히 19년 2월에 가장 쌌다.
    • 19년 2월 자동차 운행이 가장 많았다. 공사로 맨날 찰 끌고 다닌다는 듯.
    • 1년동안 340,000원 사용했다. 자동차 가동율이 너무 떨어졌다.
    • 1,200 원/리터, 15km/리터로 계산하면 약 일년에 4,275km 이동.
    • 수입: 월급 외 별도 수입이 거의 없음.
    • 지출의 23%가 카드로 결제 됨. 거의 생활비.
    • 지출의 22%를 대출 갚는데 사용.
    • 지출의 11%를 보험비로 지출.
    • 수입 – 지출 = -4,000,000원. 대출을 마이너스로 땡겨 갚았다.

    일단 데이터를 로딩하고, Qlik에서 항목을 수정했다.

    [과거 기름값]:
    LOAD
    	[번호],
    	[지역],
    	[상호],
    	[주소],
        [기간],
       	MakeDate(left([기간],4),mid([기간],5,2),right([기간],2)) as [날짜],
    	[상표],
    	[경유]
     FROM [lib://금융/과거_판매가격(주유소)20180308-20190308.csv]
    (txt, codepage is 949, embedded labels, delimiter is ',', msq);
    [필터된 경유]:
         load [경유],
         year([날짜])&'.'&month([날짜]) as [연월]
        Resident [과거 기름값];
    
    drop Table [과거 기름값];

    기름가격 날자가 “.” 로 구분되어 굳이 이렇게 구분해야 Qlik에서 인식했다. 추가 블럭에 이리 로딩한 [과거 기름값]을 부르고, 날자 포멧으로 수정했다. 연관성을 없애기 위해 [과거 기름값]을 지웠다.

    뱅크 샐러드에서 테이블을 부르면 카테고리가 대략 맞지만, qlik으로 원하는 부분을 수정하기 힘들다. 강력한 정규식을 지원하는 python pandas를 사용했다.

    #_*_ coding: utf-8 _*_
    
    import pandas as pd
    import numpy
    
    #Pandas로 업데이트
    df = pd.read_csv("./test.csv")
    
    #정규 표현식으로 다시 정리.
    conditions = [
            (df["내용"].str.contains("?????") & (df["대분류"] == "미분류")),
            (df["내용"].str.contains("성과급지급") & (df["대분류"] == "미분류")),
            (df["내용"].str.contains('\d{3}-\d{4}') & (df["대분류"] == "미분류")),
            (df["내용"].str.contains('마이너스|??|월급통장|??') & (df["대분류"] == "미분류")),
            (df["내용"].str.contains('????') & (df[">대분류"] == "미분류"))
            ]
    
    choices = ["급여","급여","보험","대출","기타수입"]
    
    df["급여"]=numpy.select(conditions, choices, default = df["대분류"])
    
    df.to_csv("./20190313.csv",index=True)

    pandas를 잘 사용하지 못해 시간을 많이 썼다. 그러나 qlik을 배워서 함보다 낫다.