설대회

created : 2020-01-26T14:57:47+00:00
modified : 2022-03-25T18:32:44+00:00

계개모 설대회

1. 생각의 흐름

  • 설 대회로는 그 자체를 표현하라고 했다.
  • 사실 원래 계획은 Word2Vec를 통해서 9월 (혹은 10월) : 추석 = 1월 (혹은 2월) : 설 이라던가 송편과 떡국 간의 관계를 통해서 설이라는 단어를 결과값으로 뽑고 싶었다.
  • 체계단 내에서 누군가가 konlpy로 무언가를 하고 있는 것을 봤다. NLP라는 영역이 겹치는 것 같아서 뭔가 아이디어가 겹친다고 생각되어 처음부터 다시 생각하기로 했다.

과연 설은 무엇일까?

  • 구글 번역기에 영어로 돌려봤다. New Year’s Day라고 나온다.
  • New Yera’s Day라고 검색하니 별로 안나왔다.
  • 중국어로 춘절이라고 해서 검색해보니 중국 코로나 바이러스 사태 기사만 나온다.
  • 별 도움이 되지 않았다 ㅠ

깨달음

  • 아! 아무도 설에 대해서 모르는구나. 모두 설을 뭐라고 생각할까 알아보기로 했다.
  • 그렇다면 설은 어떻게 표현될까?
  • 잘 모르겠다. 설 당일 사람들이 검색하는게 곧 설이지 않을까라는 생각에 도달했다.

2. 구체화

  • 아이디어는 다음과 같다.
    1. 설 당일 네이버 실시간 검색을 1분 단위로 저장해논다.
    2. 이를 가공해서 사람들에게 보여주자! 그게 곧 설아니겠는가?

반전!

  • 사실 설이 일요일인줄 알고 토요일날 코딩해도 널널하겠네 라고 생각했는데 설이 알고보니 토요일이였다.
  • 이걸 깨달은건 토요일 아침 7시이다.
  • 이미 늦었다. 젠장OTL.
  • 생각해낸 아이디어는 시간이 제일 중요하다. 실시간 검색어를 바로 모으기로 했다.
  • 그래서 아침 8시부터 저녁 10시까지 1분 간격으로 크롤링했다.

2-1. 크롤링 구현

var request = require ("request");
var fs = require("fs");
request.get({url : "https://m.search.naver.com/search.naver?sm=mtp_sug.top&where=m&query=%EC%8B%A4%EC%8B%9C%EA%B0%84%EA%B2%80%EC%83%89%EC%96%B4&acq=%EC%8B%A8&acr=0&qdt=0" }, function (err, response, body){
  fs.writeFileSync(""+Date.now(), body);
});
  • 사실 별거 없다. 1분만에 짠 코드답다. 뭔가 처리하지도 않고 그냥 데이터를 저장만 한다.
  • 이걸 1분마다 실행해야 된다. node 로 해도 되는데, 먼가 에러 처리를 하나도 안해놔서 속된말로 쫄렸다.
  • 그래서 뭔가 에러나도 별 상관 없이 프로세스가 안죽었으면 했다.
  • 걍 프로세스가 죽어도 냅두기로 했다. 걍 1분마다 재실행 하는게 더 빠르겠더라.

    crontab -e

를 열어서 1분마다 위 코드를 실행하기로 했다.

그렇게 서버에 14시간 정도 방치해놨다.

2-2. 전처리

  • 역시 전체를 걍 저장하니 용량이 어마어마했다. 400MB나 됬다.
  • 이제 전체 검색 결과가 아니라, 실시간 검색어만 빼보자(사실 이렇게 하면 5MB 이내일듯)
  • 지금 시간 새벽 1시 5분 이제 전처리 시작한다 ㅠ
  • 1시간 정도 짯다 ㅠ 오프라인 극혐… node_modules를 까서 사용법을 읽어본 다음 짜려고 하니 너무 오래걸린다.
const fs = require('fs');
const cheerio = require('cheerio');

fs.readdir('./raw_data', (err, files) => {
  if (err)
    throw err;
  const data = files.map((filename) => {
    const body = fs.readFileSync(`./raw_data/${filename}`);
    const $ = cheerio.load(body);
    const keywords = $('._keyword');
    let retval = '';
    for (let i = 0, length = keywords.length;
      i < length;
      i += 1) {
      retval += keywords[i].children[0].data + ',';
    }
    return retval;
  }).reduce((retval, now) => retval+='\n'+now);
  
  fs.writeFileSync('data.csv', data);
});

데이터를 읽어서 오름차순의 형태로 1줄이 1분을 나타내도록 저장한다.

  • 결과적으론 1MB 짜리 파일이 하나 나왔다.

2-3. 시각화

  • 실제로 수치를 분석해서 우리가 상품을 제작할것도 아니고 대충 어떤 키워드들이 있는지 알아보기 위한거니 WordCloud를 시각화 도구로 사용하기로 했다.
  • WordCloud는 D3를 이용해서 만들껀데 지금 오프라인이라 파일을 다운 받을 방법이 없으니 일단은 여기까지- 현재시각 2시 15분 - (어휴 이정도면 많이 했다.)
  • 현재 시각 13시 5분, 방금 일어났다. 이제 시각화를 해보자

나중에야 정리 (2020-04-07)

  • http-server module을 설치해서 간단한 web-server를 연다.
  • 안그러면 csv파일 형식을 못연다.
  • output.html ```html <!DOCTYPE html>
 * wordcloud.js
```js
const width = 2080, height = 1920;
const svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);
d3.csv("worddata.csv").
  then(function (data) {
    showCloud(data)
  setInterval(function() {
    showCloud(data);
  }, 10000);
});

wordScale = d3.scaleLinear().domain([0, 100]).range([0, 150]).clamp(true);

svg.append("g").attr("transform", "translate(" + width * 2 + "," + height +")");

function showCloud(data) {
  d3.layout.cloud().size([width, height])
    .words(data)
    .rotate(function(d) {
      return d.text.length > 3 ? 0 : 90;
    })
    .font("Impact")
    .fontSize(function (d) {
      return wordScale(d.frequency);
    })
    .on("end", draw)
    .start();
  function draw(words) {
    var cloud = svg.selectAll("text").data(words)

    cloud.enter()
      .append("text")
      .style("fill", "#4052")
      .attr("text-anchor", "middle")
      .style("font-size", function (d) {
        return d.size + "px";
      })
    //.attr("font-size", 1)
      .text(function (d) {
        return d.text;
      });

    cloud
      .transition()
      .duration(600)
      .style("font-size", function (d) {
        return d.size + "px";
      }).attr("transform", function (d) {
        return `translate(${d.x+width/2}, ${d.y+height/2})rotate(${d.rotate})`
    }).style("fill-opacity", 1);
  }
}

결과 이미지

  • 생각만큼 잘 나오지 않았다.
  • 그리고 급하게 하느라고 그때 데이터가 아니라 다른 데이터로 그림을 만들었다.