<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Python on</title><link>https://taetaetae.github.io/tags/python/</link><description>Recent content in Python on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 09 Feb 2020 20:06:15 +0000</lastBuildDate><atom:link href="https://taetaetae.github.io/tags/python/index.xml" rel="self" type="application/rss+xml"/><item><title>Jupyter 설치하고 원격접속까지 (for 파.알.못)</title><link>https://taetaetae.github.io/2020/02/09/jupyter-install/</link><pubDate>Sun, 09 Feb 2020 20:06:15 +0000</pubDate><guid>https://taetaetae.github.io/2020/02/09/jupyter-install/</guid><description>&lt;p>파이썬이라는 언어는 다른 프로그래밍 언어들에 비해 쉽고 직관적이라 그런지 프로그래밍을 처음 시작하는 사람들에게 더욱이 주목을 받고 있는것 같다. 정말 다양한 모듈들이 많아 여러분야에서 활용되고 있고 &lt;!--more -->특히 언제부터인가 핫! 해진 분야(?)라 해도 과언이 아닐정도인 &amp;ldquo;머신러닝&amp;rdquo; 분야에서도 다양하게 사용되고 있는것 같다.&lt;/p>
&lt;p>마침 필자가 속해 있는 팀 내에 머신러닝 스터디가 시작이 되었고, 그에 파이썬을 이용하여 스터디를 해야하는 상황. 하지만 스터디를 하는 팀원 절반 이상이 파이썬을 이용한 개발 경험이 없었고, 서로 배운것을 공유를 하면서 스터디를 하면 더 좋겠다는 생각이 들때 즈음. 언제 어디선가 봤던것이 머릿속을 스쳐 지나간다. 그건 바로 Jupyter(이하 주피터).&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/jupyter-install/jupyter_logo.jpg" title="/images/jupyter-install/jupyter_logo.jpg" data-thumbnail="/images/jupyter-install/jupyter_logo.jpg" data-sub-html="&lt;h2>출처 : https://jupyter.org/&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/jupyter-install/jupyter_logo.jpg"
 data-srcset="https://taetaetae.github.io/images/jupyter-install/jupyter_logo.jpg, https://taetaetae.github.io/images/jupyter-install/jupyter_logo.jpg 1.5x, https://taetaetae.github.io/images/jupyter-install/jupyter_logo.jpg 2x"
 data-sizes="auto"
 alt="/images/jupyter-install/jupyter_logo.jpg" width="80%" />
 &lt;/a>&lt;figcaption class="image-caption">출처 : &lt;a href="https://jupyter.org/" target="_blank" rel="noopener noreffer ">https://jupyter.org/&lt;/a>&lt;/figcaption>
 &lt;/figure>
&lt;p>&lt;a href="https://jupyter.org/" target="_blank" rel="noopener noreffer ">주피터&lt;/a>는 수십 개의 프로그래밍 언어에서 대화 형 컴퓨팅을위한 오픈 소스 소프트웨어, 오픈 표준 및 서비스를 개발하기 위한 툴이라고 한다. 이 포스트를 작성하기 전까지만 해도 &amp;ldquo;주피터 == 파이썬 웹 개발툴&amp;rdquo; 이라고만 알고있었는데 좀더 찾아보니 &lt;a href="https://github.com/jupyter/jupyter/wiki/Jupyter-kernels" target="_blank" rel="noopener noreffer ">다양한 언어를 지원&lt;/a>하는것 같다.&lt;/p>
&lt;p>그럼 이러한 주피터를 특정 서버에 설치하고 로컬에 파이썬을 설치하지 않아도 원격으로 파이썬 코딩을 해보면 좀더 스터디에 도움이 되지 않을까 하는 마음이 들었다. 또한 학교에서 운동장에 잔디를 깔아서 맘껏 뛰놀수 있게 하는 느낌으로 팀원들을 위해 설치를 해두고 원격으로 접속할 수 있게 해두면 모두가 편하고 쉽게 파이썬에 대해 경험을 해볼 수 있지 않을까 하는 마음으로 주피터를 설치를 해 보고자 한다.&lt;/p>
&lt;p>본 포스팅의 목표는 다음과 같다.&lt;/p>
&lt;ul>
&lt;li>환경 : CentOS 7.4 64Bit, python 2.7 (기본)&lt;/li>
&lt;li>목표
&lt;ul>
&lt;li>anaconda 를 활용하여 시스템 기본 파이썬을 건드리지 않는 가상환경을 구축한다.&lt;/li>
&lt;li>주피터를 설치하고 원격으로 접속할 수 있도록 설정한다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>여기까지 보면 필자가 엄청나게 파이썬에 대해 잘 아는것처럼 보일수도 있어 미리 말하지만 필자는 찐 자바 개발자이면서 파이썬 개발 수준은 기본적인 스크립트를 작성하는 정도이다. 그러니 이 포스트를 읽고 있는 필자같은 파알못(?) 분들도 충분히 설치가 가능하다. (최대한 따라할수 있을 정도의 치트키 수준으로 작성 하고자 한다.)&lt;/p>
&lt;h2 id="아나콘다-설치-덤으로-설치되는-주피터">아나콘다 설치 (덤으로 설치되는 주피터)&lt;/h2>
&lt;p>우선 아나콘다를 설치하자. 아나콘다는 Anaconda(이전: Continuum Analytics)라는 곳에서 만든 파이썬 배포판으로, 수백 개의 파이썬 패키지를 포함하고 있다고 한다. 즉, 아나콘다를 설치하고 만들어진 가상환경에서 파이썬 개발을 하면 다양한 모듈이 이미 설치되어 있기 때문에 편리하다는 이야기.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/jupyter-install/ananconda.jpg" title="/images/jupyter-install/ananconda.jpg" data-thumbnail="/images/jupyter-install/ananconda.jpg" data-sub-html="&lt;h2>출처 : https://www.anaconda.com/&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/jupyter-install/ananconda.jpg"
 data-srcset="https://taetaetae.github.io/images/jupyter-install/ananconda.jpg, https://taetaetae.github.io/images/jupyter-install/ananconda.jpg 1.5x, https://taetaetae.github.io/images/jupyter-install/ananconda.jpg 2x"
 data-sizes="auto"
 alt="/images/jupyter-install/ananconda.jpg" width="40%" />
 &lt;/a>&lt;figcaption class="image-caption">출처 : &lt;a href="https://www.anaconda.com/" target="_blank" rel="noopener noreffer ">https://www.anaconda.com/&lt;/a>&lt;/figcaption>
 &lt;/figure>
&lt;p>더불어 시스템에 기본으로 설치되어 있는 파이썬을 건드리면 여러 복잡한 문제가 발생할 수 있기에. 아나콘다를 활용하여 파이썬 3을 사용하는 가상환경을 만들어 보자.
설치는 아주 간단하다. 아나콘다 설치파일을 다운받고 이를 실행하면 끝.
(user 레벨이 root 면 sudo 명령어를 생략해도 된다.)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ wget https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ sudo bash Anaconda3-2019.10-Linux-x86_64.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Welcome to Anaconda3 2019.10
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">In order to &lt;span class="k">continue&lt;/span> the installation process, please review the license
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">agreement.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Please, press ENTER to &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">===================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Anaconda End User License &lt;span class="nv">Agreement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">===================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Copyright 2015, Anaconda, Inc.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">~~~ 중략 ~~~
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Do you accept the license terms? &lt;span class="o">[&lt;/span>yes&lt;span class="p">|&lt;/span>no&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>no&lt;span class="o">]&lt;/span> &amp;gt;&amp;gt;&amp;gt; yes &lt;span class="c1"># yes!!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Anaconda3 will now be installed into this location:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/root/anaconda3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - Press ENTER to confirm the location
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - Press CTRL-C to abort the installation
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - Or specify a different location below
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>/root/anaconda3&lt;span class="o">]&lt;/span> &amp;gt;&amp;gt;&amp;gt; /home/anaconda3 &lt;span class="c1"># 설치될 경로를 설정해주고 기본 설정값에 설치하려면 그냥 엔터&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">~~~뭐가 엄청 설치된다. 물 한잔 먹고 오자.~~~
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">installation finished.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Do you wish the installer to initialize Anaconda3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">by running conda init? &lt;span class="o">[&lt;/span>yes&lt;span class="p">|&lt;/span>no&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>no&lt;span class="o">]&lt;/span> &amp;gt;&amp;gt;&amp;gt; yes &lt;span class="c1"># yes!!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이렇게 되면 설치는 끝. 환경변수를 설정해서 기본 파이썬 환경을 아나콘다에 의해 설정되도록 맞춰주자.&lt;/p></description></item><item><title>Jenkins에서 파이썬 출력을 실시간으로 보고싶다면?</title><link>https://taetaetae.github.io/2018/12/02/python-buffer/</link><pubDate>Sun, 02 Dec 2018 01:40:11 +0000</pubDate><guid>https://taetaetae.github.io/2018/12/02/python-buffer/</guid><description>&lt;p>필자가 운영하고 있는 &lt;a href="http://daily-devblog.com" target="_blank" rel="noopener noreffer ">Daily Dev Blog&lt;/a> 라는 서비스는 매일 동일한 시간에 주기적으로 데이터를 크롤링 하고 사용자에게 메일을 발송하는 일련의 작업을 수행하고 있다. 헌데 예상하지 못한 부분에서 예외가 발생하게 되면 어떤경우는 메일 발송을 못한다거나 기존에 발송했던 데이터를 다시 보내는 등 정상적이지 못한 상황을 맞이하게 된다.&lt;!-- more -->&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/python-buffer/ddb_duplication.png" title="/images/python-buffer/ddb_duplication.png" data-thumbnail="/images/python-buffer/ddb_duplication.png" data-sub-html="&lt;h2>메일이 하루라도 잘못오면 여기저기서 연락이 온다. 감사한 분들&amp;hellip;&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/python-buffer/ddb_duplication.png"
 data-srcset="https://taetaetae.github.io/images/python-buffer/ddb_duplication.png, https://taetaetae.github.io/images/python-buffer/ddb_duplication.png 1.5x, https://taetaetae.github.io/images/python-buffer/ddb_duplication.png 2x"
 data-sizes="auto"
 alt="/images/python-buffer/ddb_duplication.png" />
 &lt;/a>&lt;figcaption class="image-caption">메일이 하루라도 잘못오면 여기저기서 연락이 온다. 감사한 분들&amp;hellip;&lt;/figcaption>
 &lt;/figure>
&lt;p>이런저런 바쁜일들로 차일피일 미루다 마침 여유가 생겨 기존에는 Crontab 스케쥴로 파이썬 스크립트를 실행하던 것에서 Jenkins로 옮기는 작업을 했다. 젠킨스가 스케쥴링을 해주고 실행이력을 보여주며, 실시간으로 스크립트가 돌아가는걸 볼수 있을것 같다는 기대감에서이다. 위에서 이야기 했던 예외상황을 보다 빠르고 편하게 실시간으로 디버깅을 하기 위해서가 가장 컸다.&lt;/p>
&lt;h2 id="당연히-될거라고-생각했으나">당연히 될거라고 생각했으나&amp;hellip;&lt;/h2>
&lt;p>작업은 간단할꺼라 생각했다.&lt;/p>
&lt;ol>
&lt;li>우선 &lt;a href="https://taetaetae.github.io/2018/12/02/jenkins-install/" target="_blank" rel="noopener noreffer ">Jenkins를 설치&lt;/a>하고&lt;/li>
&lt;li>기존에 스크립트 파일을 Jenkins Job으로 옮긴후에&lt;/li>
&lt;li>적당한 코드 중간중간에 디버깅이 용이하도록 로그를 출력하게 해둔다음&lt;/li>
&lt;li>스케쥴링만 걸어두면 끝이라고 생각했다.&lt;/li>
&lt;/ol>
&lt;p>하지만, 이렇게 간단하게 끝날것만 같았던 작업이 은근 귀찮은 작업이 될줄이야. 디버깅을 위해 로그를 출력하도록 해놨는데 모든 스크립트가 끝이 나서야 해당 로그가 출력되는 것이였다. 로그를 실시간으로 볼수 없다면 Crontab에서 Jenkins로 옮기는 이유가 크게 없게 된다. 실제로 아래처럼 코드를 작성하고 Jenkins Job을 실행시켜보면 다 끝나고서야 출력이 되는걸 볼수 있었다.&lt;/p>
&lt;p>(1초에 한번씩 5초동안 로그를 찍는 간단한 코드다.)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;start&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">second&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">second&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">second&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;end&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/python-buffer/before.gif" title="/images/python-buffer/before.gif" data-thumbnail="/images/python-buffer/before.gif" data-sub-html="&lt;h2>스크립트가 다 끝나서야 출력을 볼수 있다ㅠ 실시간으로 디버깅이 어렵다.&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/python-buffer/before.gif"
 data-srcset="https://taetaetae.github.io/images/python-buffer/before.gif, https://taetaetae.github.io/images/python-buffer/before.gif 1.5x, https://taetaetae.github.io/images/python-buffer/before.gif 2x"
 data-sizes="auto"
 alt="/images/python-buffer/before.gif" />
 &lt;/a>&lt;figcaption class="image-caption">스크립트가 다 끝나서야 출력을 볼수 있다ㅠ 실시간으로 디버깅이 어렵다.&lt;/figcaption>
 &lt;/figure>
&lt;h2 id="그럼-어떻게-해야할까">그럼 어떻게 해야할까?&lt;/h2>
&lt;p>개발을 하면서 만나는 대부분의 문제들은 누군가 과거에 경험했던 문제였고, 이미 해결된 문제일 확률이 상당히 높은것들이 많다. 이번에도 역시, 갓 스택 오버플로우 : &lt;a href="https://stackoverflow.com/questions/107705/disable-output-buffering" target="_blank" rel="noopener noreffer ">https://stackoverflow.com/questions/107705/disable-output-buffering&lt;/a>&lt;/p>
&lt;p>위 링크에서 알려준것처럼 해보면 다음과 같이 로그가 출력되는대로 젠킨스에서 볼수 있게 된다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/python-buffer/after.gif" title="/images/python-buffer/after.gif" data-thumbnail="/images/python-buffer/after.gif" data-sub-html="&lt;h2>콘솔환경에서의 디버깅은 로깅이 최고!&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/python-buffer/after.gif"
 data-srcset="https://taetaetae.github.io/images/python-buffer/after.gif, https://taetaetae.github.io/images/python-buffer/after.gif 1.5x, https://taetaetae.github.io/images/python-buffer/after.gif 2x"
 data-sizes="auto"
 alt="/images/python-buffer/after.gif" />
 &lt;/a>&lt;figcaption class="image-caption">콘솔환경에서의 디버깅은 로깅이 최고!&lt;/figcaption>
 &lt;/figure>
&lt;p>정리해보면 다음과 같은 방법이 있겠다.&lt;/p>
&lt;ol>
&lt;li>&lt;code>Execute Python script&lt;/code> 을 활용하여 Jenkins 에 직접 코드를 작성하는 경우&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>print의 flush옵션을 활용 ( &lt;a href="https://docs.python.org/3/library/functions.html?highlight=print#print" target="_blank" rel="noopener noreffer ">https://docs.python.org/3/library/functions.html?highlight=print#print&lt;/a> )&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;hello&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">flush&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>매번 print 가 될때마다 flush가 되도록 재정의&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Unbuffered&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">stream&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">stream&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">writelines&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">datas&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">writelines&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">datas&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__getattr__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">attr&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stream&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">attr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">Unbuffered&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>&lt;code>Execute shell&lt;/code>을 활용하여 특정경로의 Python 파일을 실행할 경우&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>&lt;code>-u&lt;/code> 옵션을 줘서 실행시킨다. ( python -u python_module.py )&lt;/li>
&lt;/ul>
&lt;p>이렇게 두고보면 너무 간단한 작업인데 이런 방법을 모르는 상황에서는 작성된 Python Script를 Shell Script로 다시 감싸보거나 Python 코드를 쓰지 말까 까지 생각했었다&amp;hellip; 삽질의 연속들&amp;hellip; (Shell Script로 작성하면 바로바로 보였기 때문&amp;hellip;)&lt;/p>
&lt;p>다시한번 모르면 몸이 고생한다(?)라는걸 몸소 체험한 좋은&amp;hellip;시간이였다.&lt;/p></description></item><item><title>2018 Pycon. 그리고 첫 발표를 하다.</title><link>https://taetaetae.github.io/2018/08/28/pycon-2018/</link><pubDate>Tue, 28 Aug 2018 23:43:16 +0000</pubDate><guid>https://taetaetae.github.io/2018/08/28/pycon-2018/</guid><description>&lt;p>IT관련 행사에 참여하면 여러가지 정보를 얻을수 있다. 개인적으로는 사실 정보를 얻기 위함보다 그곳의 분위기를 현장에서 몸소 느끼고 참여한 사람들의 눈빛을 보며 해이해진 마음가짐을 다시 다잡을수 있음이 가장 큰 목적이다. 그에 올해 Pycon도 하나의 전환점이 되길 바라는 마음으로 신청을 하게 되었다.&lt;/p>
&lt;!-- more -->
&lt;h2 id="등록">등록&lt;/h2>
&lt;p>&lt;a href="https://www.pycon.kr" target="_blank" rel="noopener noreffer ">https://www.pycon.kr&lt;/a>
얼리버드 등록을 한다고 Facebook에서 홍보를 하길래 그런가보다 했는데 잠깐 회사일에 집중하고 다시 보니 이미 매진이 되어있었다. 사실 Pycon 은 올해가 처음 가보는거라 인기를 실감할수 없었는데 이정도일줄은 상상도 못했다. (나중에 알게 된 사실이지만 올해가 가장 인원이 많았다고&amp;hellip;) 그래서 나중에 진행되었던 일반표 등록은 휴대폰 알람까지 걸어두며 늦지않게 등록할수 있었다. 세부 일정들이 업데이트가 되고 어떤 세션을 들을까 고민하면서 간략 소개를 하나둘씩 보게 되었는데 Python을 만지며 평소에 궁금했던거나 재밌어 보이는 세션들이 너무많아 고민을 많이 했다. 한가지 아쉬운건 로그인 기반이 아니다 보니 (임시 로그인기반?) 내 시간표 설정하는게 없었다. 나는 별도로 적어서 갔지만 나중엔 그런 기능이 생겼으면 좋겠다.&lt;/p>
&lt;blockquote>
&lt;p>2019년 Pycon엔 크롬 익스텐션으로 기능을 만들어 로그인 여부와 상관없이 몇시에 내가 어떤 세션을 들을건지에 대한 설정을 하고 이를 이미지로 캡쳐해서 출력/다운 받을수 있는 걸 만들어 보고 싶다. (그전에 미뤄뒀던 크롬 익스텐션 개발하는 방법부터 공부하자&amp;hellip;)&lt;/p>&lt;/blockquote>
&lt;h2 id="첫째날">첫째날&lt;/h2>
&lt;p>개인적으로 아침잠이 너무 많은데 알림이 울리기도 전에 눈이 떠졌고 행사장에 도착해보니 후원사 부스는 아직 텅텅 비어있었고, 밤새가면서 준비를 하셨는지 자원봉사자 분들은 여기저기 빈백에 누워(쓰러져) 자고 있었다. 그만큼 Pycon에 대한 기대가 컸나보다. 시간이 지나니 하나둘씩 사람들이 등록을 하며 오기 시작하였고 역시나 행사에 꽃중에 꽃인 후원사 부스에서 나눠주는 이벤트 상품들을 받기 바빴다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/pycon-2018/day1.png" title="/images/pycon-2018/day1.png" data-thumbnail="/images/pycon-2018/day1.png" data-sub-html="&lt;h2>DIVE INTO DIVERSITY !!&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/pycon-2018/day1.png"
 data-srcset="https://taetaetae.github.io/images/pycon-2018/day1.png, https://taetaetae.github.io/images/pycon-2018/day1.png 1.5x, https://taetaetae.github.io/images/pycon-2018/day1.png 2x"
 data-sizes="auto"
 alt="/images/pycon-2018/day1.png" />
 &lt;/a>&lt;figcaption class="image-caption">DIVE INTO DIVERSITY !!&lt;/figcaption>
 &lt;/figure>
&lt;p>키노트를 시작으로 사람들은 각자 듣고싶은 세션에 참가하며 행사는 시작이 되었다. 전체적으로 기술의 난이도는 초급 수준의 발표였던걸로 느껴졌다. (물론 나는 초초초급도 안되는 꼬꼬마 수준이지만&amp;hellip;) 대부분 Python으로 어떤걸 해봤고, 어떤 어려움이 있었고, 이러저러한 상황들을 만났으며, 요런 경우에서는 어떻게 하며 해결을 하였다는 등 기술을 활용한 &amp;ldquo;경험기&amp;quot;에 대한 내용들을 들을수 있었다.
Pycon의 슬로건인 &lt;code>DIVE INTO DIVERSITY&lt;/code>에 걸맞게 아주 &lt;code>다양한 주제&lt;/code>로 흥미있는 발표내용들이였다. 기억나는 것들중에 인상깊었던 부분들을 정리해본다.&lt;/p>
&lt;ul>
&lt;li>파이썬 문화(?)중의 하나는 몰라서 물어보는 사람에게 구글링을 하라기보다 직접 알려주라는 것이다.&lt;/li>
&lt;li>배우고 싶다면 다른사람들을 가르치는것부터(알려주는것부터) 시작하라.&lt;/li>
&lt;li>여성 개발자, 여성 발표자들도 점점 늘어나고 있다.&lt;/li>
&lt;li>파이썬을 개발 현장(?)이 아닌 다른곳에서 사용한다면 작업 속도도 빠르고 얻어내는 가치또한 훨씬 더 방대하다.&lt;/li>
&lt;li>엑셀로 할수 있는 작업을 파이썬으로 할수 있다.&lt;/li>
&lt;li>파이썬의 다양한 라이브러리는 일상의 도움을 준다.&lt;/li>
&lt;/ul>
&lt;p>행사를 들으며 꼭 질문을 해야지 하는 마음을 갖고 있었는데 (그래야 오래 기억에 남으니) 마침 어떤 세션에서 궁금한게 있어 질문을 할수 있었다. (질문을 하니 파이썬 관련 책 선물도 받았다.^^)
그리고 마지막 &lt;code>라이트닝 톡&lt;/code>이라는 세션이 있었는데 여러 발표자들이 짤막하게 5분동안 하고싶은 이야기를 하는 세션이였다. 5분이라는 제한이 있기에 다들 쉽고 편하게 발표하는듯 보였으나 발표 자료나 발표내용을 보면 꼭 그렇게 간단하게 발표하는건 아니였다. 본 세션에서 말하기엔 다소 분량이 작은 알차고 깨알같은 발표도 있었고, 매년 Pycon 라이트닝톡에 발표하는게 목표이신 분도 있었다.
발표를 들으면서 난 언제 저런자리에 가서 발표를 할수 있을까 하는 마음이 스쳐 지나갈때 쯤. &amp;ldquo;왜못하지? 나 파이썬으로 만든거 있잖아?&amp;rdquo; 라고 혼잣말로 궁시렁거리며 둘째날에 있는 라이트닝톡에서 발표하기로 마음을 먹고 서둘러서 참가 신청을 보냈다. 그러고서는 저녁을 먹고 집에 늦게 돌아와 새벽 3시넘어서야 발표자료를 완성하였지만 &amp;ldquo;발표&amp;rdquo; 라는 부담감때문에 어렵게 잠에 들었다.&lt;/p>
&lt;h2 id="둘째날">둘째날&lt;/h2>
&lt;p>어제와는 달리 오늘은 잠을 많이 못자서 인지 늦게 일어나 첫 세션이 시작하고서 거의 끝날 즈음에 행사장에 도착하게 되었다. &amp;ldquo;괜히 발표 한다고 한걸까&amp;rdquo; 라는 생각이 들며 진행위 본부에 가서 발표 순서를 확인해보니 첫번째&amp;hellip; 슬슬 머리가 아파오기 시작했다. 그래도 듣기로한 세션은 들어보고 싶어서 집중해서 세션들을 돌아가며 들었지만 머릿속에는 온통 &amp;ldquo;발표 발표 발표&amp;quot;라는 생각때문에 오히려 다른분께서 하시는 발표를 집중해서 듣지 못하였다.&lt;/p></description></item><item><title>기술블로그 구독서비스 개발 후기 - 1부</title><link>https://taetaetae.github.io/2018/08/05/daily-dev-blog-1/</link><pubDate>Sun, 05 Aug 2018 10:27:21 +0000</pubDate><guid>https://taetaetae.github.io/2018/08/05/daily-dev-blog-1/</guid><description>&lt;p>이번 포스팅은 약간의 자투리 시간을 활용하여 이것저것 만져보다 만들게 된 &lt;code>Daily DevBlog&lt;/code>(기술블로그 구독서비스)에 대해 이야기 하려고 한다. &lt;!-- more -->
하나의 글에 관련 내용을 모두 담기에는 양이 많아서 읽는사람도 지루하고, 글을 쓰는 필자 또한 &lt;code>어불성설&lt;/code> 할것같아 크게 3개의 시리즈로 나눠서 최대한 자세하고 현장감(?)있게 글을 써보려고 노력했다.&lt;/p>
&lt;ul>
&lt;li>1부 : &lt;a href="https://taetaetae.github.io/2018/08/05/daily-dev-blog-1/" target="_blank" rel="noopener noreffer ">왜 만들게 되었는가 그리고 어떤 구조로 만들었는가&lt;/a>&lt;/li>
&lt;li>2부 : &lt;a href="https://taetaetae.github.io/2018/08/09/daily-dev-blog-2/" target="_blank" rel="noopener noreffer ">문제발생 및 Trouble Shooting&lt;/a>&lt;/li>
&lt;li>3부 : &lt;a href="https://taetaetae.github.io/2019/02/17/daily-dev-blog-3/" target="_blank" rel="noopener noreffer ">앞으로의 계획과 방향성&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>글에 들어가기 앞서 최종 결과는 &lt;a href="http://daily-devblog.com" target="_blank" rel="noopener noreffer ">http://daily-devblog.com&lt;/a> 에서 확인할수 있다.&lt;/p>
&lt;hr>
&lt;h2 id="무엇이-나를-움직이게-했는가">무엇이 나를 움직이게 했는가&lt;/h2>
&lt;p>얼마전까지 오픈소스는 정말 실력있는 개발자나 유명한 사람들 말고는 금기의 영역(?)이라고 생각했었지만 최근 &lt;a href="https://taetaetae.github.io/2018/07/01/open-source-software-develpoer-story-review/" target="_blank" rel="noopener noreffer ">오픈소스 개발자 이야기 세미나&lt;/a>를 다녀온뒤 마음속에 있었던 벽이 사라지는듯 했다. 세미나를 들으면서 &amp;lsquo;나도 무언가를 만들어 볼수는 없을까?&amp;rsquo;, &amp;lsquo;회사라는 명찰을 떼면 난 어느 수준에서 개발을 하고 있는 것일까?&amp;rsquo; 등 여러 생각들이 머리를 멤돌다 &lt;a href="https://www.slideshare.net/zzsza/intro-102870757" target="_blank" rel="noopener noreffer ">개발자를 위한 글쓰기&lt;/a>라는 글에서 기술블로그들을 모아놓은 &lt;a href="https://awesome-devblog.herokuapp.com" target="_blank" rel="noopener noreffer ">awesome-devblog&lt;/a>를 소개하는 글을 보게 되었고 내 머릿속에 정리안되던 그 생각들은 &amp;ldquo;이 데이터를 활용해서 무언가를 만들어보자!&amp;ldquo;로 귀결되었다.&lt;/p>
&lt;blockquote>
&lt;p>다른 이야기 이지만, awesome-devblog 을 보고 당장 내 블로그도 등록해야지 했었는데 이미 등록이 되어 있었다;; 등록해주신 분께 감사하다는 생각이 들기전에 내 블로그가 누군가에게 보여지고 있구나 하며 새삼 놀라움이 더 컸다.&lt;/p>&lt;/blockquote>
&lt;h2 id="요구사항과-도구-그리고-설계">요구사항과 도구 그리고 설계&lt;/h2>
&lt;p>만들려고 생각해봤던 요구사항은 다음과 같다. 마치 회사에서 개발전 스펙을 정리하듯&amp;hellip;&lt;/p>
&lt;ol>
&lt;li>웹페이지를 활용해서 구독하고자 하는 사람들의 이메일을 수집할수 있어야 한다.&lt;/li>
&lt;li>매일 전날 작성된 글을 수집하고 조합하여 구독하고자 하는 사람들에게 메일을 보낼수 있어야 한다.&lt;/li>
&lt;/ol>
&lt;p>위 두가지만 보면 너무 간단했다. 또한 기존에 사용하지 않았던 기술들을 사용해보면서 &lt;code>최대한 심플하게&lt;/code> 개발하는것을 첫 개인 프로젝트의 목표로 하고 싶었다. 하여 생각한 아키텍처는 다음과 같다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/daily-dev-blog-1/architecture.png" title="/images/daily-dev-blog-1/architecture.png" data-thumbnail="/images/daily-dev-blog-1/architecture.png" data-sub-html="&lt;h2>최대한 심플하게 설계해보자.&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/daily-dev-blog-1/architecture.png"
 data-srcset="https://taetaetae.github.io/images/daily-dev-blog-1/architecture.png, https://taetaetae.github.io/images/daily-dev-blog-1/architecture.png 1.5x, https://taetaetae.github.io/images/daily-dev-blog-1/architecture.png 2x"
 data-sizes="auto"
 alt="/images/daily-dev-blog-1/architecture.png" />
 &lt;/a>&lt;figcaption class="image-caption">최대한 심플하게 설계해보자.&lt;/figcaption>
 &lt;/figure>
&lt;p>데이터는 해당 github에 있길래 그냥 가져다 쓰려고 했으나 그래도 데이터를 관리하시는 분께 허락을 받고 사용하는게 상도덕(?)인것 같아 수소문끝에 연락을 해서 허락받는데 성공하였다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/daily-dev-blog-1/message.png" title="/images/daily-dev-blog-1/message.png" data-thumbnail="/images/daily-dev-blog-1/message.png" data-sub-html="&lt;h2>데이터 사용을 허락해주신 천사같으신분&amp;hellip;&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/daily-dev-blog-1/message.png"
 data-srcset="https://taetaetae.github.io/images/daily-dev-blog-1/message.png, https://taetaetae.github.io/images/daily-dev-blog-1/message.png 1.5x, https://taetaetae.github.io/images/daily-dev-blog-1/message.png 2x"
 data-sizes="auto"
 alt="/images/daily-dev-blog-1/message.png" />
 &lt;/a>&lt;figcaption class="image-caption">데이터 사용을 허락해주신 천사같으신분&amp;hellip;&lt;/figcaption>
 &lt;/figure>
&lt;blockquote>
&lt;p>이 자리를 빌어 데이터를 사용할수 있도록 &lt;a href="https://www.facebook.com/sarojaba" target="_blank" rel="noopener noreffer ">허락해주신분&lt;/a> 께 감사인사를 표합니다.&lt;/p>&lt;/blockquote>
&lt;p>홈페이지를 만들기 위해서는 이제껏 삼겹살에 소주처럼(응?) Java에 Spring을 사용해 왔었지만 이번엔 좀 다른 방식을 사용하고 싶었다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/daily-dev-blog-1/language_framework.png" title="/images/daily-dev-blog-1/language_framework.png" data-thumbnail="/images/daily-dev-blog-1/language_framework.png" data-sub-html="&lt;h2>물론 삼겹살에 맥주, 치킨에 소주를 먹어도 되긴 하지만&amp;hellip;&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/daily-dev-blog-1/language_framework.png"
 data-srcset="https://taetaetae.github.io/images/daily-dev-blog-1/language_framework.png, https://taetaetae.github.io/images/daily-dev-blog-1/language_framework.png 1.5x, https://taetaetae.github.io/images/daily-dev-blog-1/language_framework.png 2x"
 data-sizes="auto"
 alt="/images/daily-dev-blog-1/language_framework.png" />
 &lt;/a>&lt;figcaption class="image-caption">물론 삼겹살에 맥주, 치킨에 소주를 먹어도 되긴 하지만&amp;hellip;&lt;/figcaption>
 &lt;/figure>
&lt;p>최근에 Flask라는 python기반 웹 프레임워크를 만져본 &lt;a href="https://taetaetae.github.io/2018/06/29/simple-web-server-flask-apache/" target="_blank" rel="noopener noreffer ">경험&lt;/a>이 있어서 이렇다할 고민없이 빠른 결정을 할수 있었다. 또한 DB는 mysql 이나 기타 memory DB를 사용할까 했지만 이또한 심플하게 파일을 활용하는 sqlite3 을 사용하고자 하였다.&lt;/p>
&lt;h2 id="웹서버_최종_수정_파이널_진짜_확정">웹서버_최종_수정_파이널_진짜_확정&lt;/h2>
&lt;p>Flask를 활용하기 위해서는 당연히 웹서버가 필요했다. 처음엔 &lt;code>awesome-devblog&lt;/code>에서도 사용하고 있던 &lt;a href="https://www.heroku.com/" target="_blank" rel="noopener noreffer ">https://www.heroku.com/&lt;/a> 를 이용해서 해보려 했으나 매일 구독자들에게 메일을 보내는 등 스케쥴러 기능같은건 구현하기 힘들었고 인스턴트 어플리케이션을 등록하는 형태라 사용자의 메일을 입력받고 저장하는 로직을 만들기는 어려워 보였다. (필자가 heroku를 너무 수박 겉핥기식으로 봐서 일수도 있다&amp;hellip;)
좀더 찾아보니 &lt;a href="https://www.pythonanywhere.com/" target="_blank" rel="noopener noreffer ">https://www.pythonanywhere.com/&lt;/a> 라는 제한적이지만 무료 서비스가 있었는데 웹콘솔도 지원하고 상당히 매력있어 보여서 &lt;code>이거다!&lt;/code> 하며 개발을 시작을 했으나 (나름 도메인까지 그럴싸하게 만들었지만&amp;hellip; &lt;a href="http://dailydevblog.pythonanywhere.com/" target="_blank" rel="noopener noreffer ">http://dailydevblog.pythonanywhere.com/&lt;/a> ) 세상에 공짜는 없다는 말을 실감하며 앞서 말했던 요구사항을 완벽하게 구현할 수 없는 상황이였다.(request 제한, 스케쥴러 등록 개수 제한 등 보다 여러기능을 사용하기 위해서는 돈을 내고 써야&amp;hellip;)
마지막 희망으로 언제샀는지 서랍속 깊이 자고있던 라즈베리 파이를 꺼내서 공유기 DDNS설정을 하고 라즈베리안을 설치하며 웹서버를 위한 셋팅을 시도해보았으나 언제나 그렇듯 (시험공부 하기전에 책상 정리하고 괜히 방청소까지 하다가 피곤해서 자버리는듯한 느낌) 배보다 배꼽이 클것같아 이또한 진행하다가 중단하게 된다.
결국 AWS에서 1년동안은 무료로 사용할수 있는 &lt;a href="https://aws.amazon.com/ko/free/" target="_blank" rel="noopener noreffer ">Free Tier&lt;/a> 라는걸 발견하고 이참에 나도한번 사용해보자라는 마음을 가지고 과금되지 않게 조심조심 셋팅을 할수 있었다. 물론 뒤에서 이야기 하겠지만 약간의 과금은 필요했다ㅠ (나름 심도깊었던 고민을 한방에 해결해버리는 AWS 짱;; 이래서 AWS~ AWS~ 하는가 싶었다.)&lt;/p></description></item><item><title>초간단 API서버 만들기 - 1부 (Python + Flask + Apache)</title><link>https://taetaetae.github.io/2018/06/29/simple-web-server-flask-apache/</link><pubDate>Fri, 29 Jun 2018 23:00:00 +0000</pubDate><guid>https://taetaetae.github.io/2018/06/29/simple-web-server-flask-apache/</guid><description>&lt;p>Static한 HTML이 아닌 로직이 필요한 API서버를 구성한다고 가정해보자. (이제까지 지식으로)처음 머릿속에 떠오르는건 Java를 사용하고 스프링으로 어플리케이션을 만들고 apache에 tomcat을 연동한 다음 &amp;hellip;&lt;!-- more --> 이러한 방법으로 API서버를 구성할수 있겠지만 프로토타이핑 또는 테스트 목적으로 만들기 위해서는 설정하는 시간이 은근 많이 소요된다. (물론 Java Config, Spring Boot 등 간소해졌지만&amp;hellip;)
얼마전부터 Python에 대한 매력을 뼈저리게 느끼고 있다보니 Python으로 API서버를 구성할순 없을까 알아봤고 (모바일 게임 듀랑고 서버가 python이라고 하기도 하고&amp;hellip;) &lt;code>Flask&lt;/code>와 &lt;code>Django&lt;/code>가 있어서 둘다 써본 결과 필자는 &lt;code>Flask&lt;/code>가 맞겠다고 생각해서 정리를 해볼까 한다.&lt;/p>
&lt;blockquote>
&lt;p>&amp;lsquo;장고&amp;rsquo;라고도 불리는 Django에는 모든것들이 다 들어가 있어서 사용하기 너무 편리하다. (DB, 어드민 등 ) 하지만 Flask는 내가 사용할 것들만 import해서 사용하는 방식이라 어떤 측면에서는 아무것도 없다 할수 있겠으나 커스터마이징에 용이하다고 볼수 있었기에 Flask를 선택하게 되었다. (Django가 Flask보다 안좋다는 말은 아니니 오해는 하지 마시길&amp;hellip;)&lt;/p>&lt;/blockquote>
&lt;p>글쓰기에 앞서 본 포스팅은 2개의 포스팅에 걸쳐 시리즈(?)형식으로 작성할 예정이다. 1부에서는 Flask가 무엇이고 이를 어떻게 사용하며 Apache와 연동하는 방법을 소개하고, 2부에서는 Nginx와 연동하는 방법을 소개한다.
환경은 다음과 같다.&lt;/p>
&lt;ul>
&lt;li>CentOS 7.4&lt;/li>
&lt;li>Python 3.6 (기본은 2.7이였으나 추가로 설치)&lt;/li>
&lt;/ul>
&lt;h2 id="flask---">Flask ( &lt;a href="http://flask.pocoo.org/" target="_blank" rel="noopener noreffer ">http://flask.pocoo.org/&lt;/a> )&lt;/h2>
&lt;p>공식 홈페이지에서도 보면 알수 있듯이 너~무 간단하다. 단지 아래 코드 몇줄만 작성하면 우리가 모든 프로그램 초기 작성시 항상 만나는 &amp;ldquo;Hello World&amp;quot;를 볼수 있다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#hello_world.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Flask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">hello&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Hello World!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>위와같이 작성하고 &lt;code>python hello.py&lt;/code>로 실행해두고 브라우저에서 &lt;code>http://127.0.0.1:5000&lt;/code> 을 요청하면 반가운 Hello World를 만날수 있다. (너무 간단;;) 자세한 문법은 &lt;a href="http://flask.pocoo.org/docs" target="_blank" rel="noopener noreffer ">도큐먼트&lt;/a>를 참조하면 될듯하고 이 Flask를 잘만 활용한다면 보다 빠르고 간단하게 API서버를 구성할수 있을거라 생각한다.&lt;/p>
&lt;p>Hello World를 찍었으면 된거 아닌가 라고 질문할수도 있겠으나 실제 서비스에서 사용하기 위해서는 앞단에 웹서버를 두는게 여러 측면에서 효율적이다. 주로 사용하는 웹서버는 Apache 와 Nginx가 있는데 여기서는 Apache와 연동하는 방법을 정리 해보고자 한다.&lt;/p>
&lt;h2 id="apache-설치---">Apache 설치 ( &lt;a href="http://archive.apache.org/" target="_blank" rel="noopener noreffer ">http://archive.apache.org/&lt;/a> )&lt;/h2>
&lt;p>우선 필자는 &lt;code>yum&lt;/code> 이나 &lt;code>apt-get&lt;/code>처럼 패키지 관리자로 설치하는것을 그렇게 좋아하지 않는다. 이유는 커스터마이징을 할 경우 시스템 어느곳에 설치되어있는지를 한눈에 파악하기 어렵고 윈도우경우 &lt;code>Program Files&lt;/code>처럼 내가 추가로 설치하고 관리하는 프로그램들을 한곳에서 관리하고 싶기에 왠만하면 소스를 직접 컴파일하여 설치하곤 한다. 이번 역시 아파치도 소스로 설치하려고 한다.
현재 아파치는 2.4버전이 Stable버전으로 되어있지만 보다 레퍼런스가 많은 2.2버전으로 설치하기 위해 어렵게 아카이빙된 경로를 통해 다운을 받고 설치를 한다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 다운을 받고
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ wget http://archive.apache.org/dist/httpd/httpd-2.2.29.tar.gz 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 압축을 푼 다음
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ tar xvzf httpd-2.2.29.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 해당 폴더로 들어가
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ cd httpd-2.2.29
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 컴파일 후 설치 경로를 정해주고
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ./configure --prefix=/~~~/apps/apache
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> make 파일을 만든다음
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ make
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 설치를 해준다.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ make install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이렇게 되면 /~~~/apps/apache/ 하위에 필요한 파일들이 설치가 되는데 root계정이 아닌 일반계정으로 실행하기 위해서는 /bin하위에 있는 httpd에 대한 실행/소유권한을 변경해줘야 한다. (아니면 그냥 root권한으로 시작/종료. 왜? Apache는 80port를 사용하는데 일반적으로 리눅스에서는 1024 아래 port를 컨트롤 하기 위해서는 root권한이 있어야 사용이 가능, 그게 아니라면 이처럼 별도의 설정이 필요하다.)&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo chown root:계정명 httpd
$ sudo chmod +s httpd
&lt;/code>&lt;/pre>&lt;h2 id="mod_wsgi-설치---">mod_wsgi 설치 ( &lt;a href="https://code.google.com/archive/p/modwsgi/" target="_blank" rel="noopener noreffer ">https://code.google.com/archive/p/modwsgi/&lt;/a> )&lt;/h2>
&lt;p>웹 서버 게이트웨이 인터페이스(WSGI, Web Server Gateway Interface)는 웹서버와 웹 애플리케이션의 인터페이스를 위한 파이선 프레임워크다. 라고 정의되어있다. 즉, 웹서버(Apache)와 위에서 만든 Flask 어플리케이션을 연동해주기 위한 프레임워크이다. 이또한 소스로 설치해보자. (위와 같은 이유로~)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 다운을 받고
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ wget https://github.com/GrahamDumpleton/mod_wsgi/archive/3.5.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 압축을 푼 다음
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ tar -zxvf 3.5.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 폴더에 들어가서
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ cd mod_wsgi-3.5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 아파치의 빌드툴인 apxs의 경로를 설정해주고
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 필자와 같이 기본 python 버전을 사용하지 않을꺼라면 꼭 python경로를 설정해줘야 한다! (중요)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ./configure --with-apxs=/~~~/apps/apache/bin/apxs --with-python=/usr/bin/python3.6
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> make 파일을 만들고
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ make
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">-&lt;/span> 설치~
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ make install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이렇게 설치를 하면 자동으로 아파치 하위 /modules 폴더안에 mod_wsgi.so 파일이 생긴다. (필자는 이것도 모르고 mod_wsgi.so파일을 다운 받으려고 구글링을 몇일째 했던 기억이 ㅠ)&lt;/p></description></item><item><title>시계열 데이터를 분석하여 미래 예측 하기(Anomaly Detection)</title><link>https://taetaetae.github.io/2018/05/31/anomaly-detection/</link><pubDate>Thu, 31 May 2018 17:03:41 +0000</pubDate><guid>https://taetaetae.github.io/2018/05/31/anomaly-detection/</guid><description>&lt;p>급변하는 날씨를 예측하려면 어떠한 정보가 있어야 할까?
또는 마트를 운영하는 담당자인 경우 매장 운영시간을 정해야 한다면 어떠한 기준으로?
뜨거운 감자인 비트코인 시장에서 수익을 얻으려면 어떤 정보들이 있어야 물리지(?) 않을수 있을까?&lt;/p>
 &lt;!--more --> 
&lt;p>위 질문에 공통된 정답은 &lt;code>예전 기록들&lt;/code>인것 같다. 날씨예측은 기상청에서 과거 기록들을 보고 비가 올지 말지를 결정하고 ( 과거 날씨 서비스를 담당해봤지만 단순히 과거 기록들로 예측한다는건 불가능에 가깝긴 하다. ) 매장 운영시간은 예전에 손님들이 언제왔는지에 대한 데이터를 보고. 비트코인이나 주식은 차트를 보고 어느정도는 상승장일지 하락장일지 추측이 가능하다고 한다. ( 물론 호재/악재에 따라 흔들리지만..ㅠㅠ..?? )
이처럼 시간의 흐름에 따라 만들어진 데이터를 분석하는것을 &lt;code>시계열 데이터 분석&lt;/code>이라 부르고 있다. 필자가 운영하는 서비스에서 시계열 데이터 분석을 통해 장애를 사전에 방지하는 사례를 공유 해보고자 한다.&lt;/p>
&lt;h2 id="상황파악부터">상황파악부터&lt;/h2>
&lt;p>손자병법에는 지피지기 백전불태 라는 말이 있다. 그만큼 현 상황을 잘 알아야 대응을 잘할수 있다는것. 필자가 운영하는 서비스는 PG(Payment Gateway) 서비스로 쇼핑몰같은 온/오프라인 사업자와 실제 카드사와의 중간 역활을 해주고 있다. 이를테면 사용자가 &lt;code>생수를 10,000원에 XX카드로 구매해줘&lt;/code> 라고 요청이 오면 그 정보를 다시 형식에 맞춰 카드사로 전달하여 사용자가 물건을 구매할수 있도록 해준다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/anomaly-detection/pg.png" title="/images/anomaly-detection/pg.png" data-thumbnail="/images/anomaly-detection/pg.png" data-sub-html="&lt;h2>PG서비스 : 쇼핑몰과 카드사의 중간에서 릴레이 해주는 역활이라 보면된다.&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/anomaly-detection/pg.png"
 data-srcset="https://taetaetae.github.io/images/anomaly-detection/pg.png, https://taetaetae.github.io/images/anomaly-detection/pg.png 1.5x, https://taetaetae.github.io/images/anomaly-detection/pg.png 2x"
 data-sizes="auto"
 alt="/images/anomaly-detection/pg.png" />
 &lt;/a>&lt;figcaption class="image-caption">PG서비스 : 쇼핑몰과 카드사의 중간에서 릴레이 해주는 역활이라 보면된다.&lt;/figcaption>
 &lt;/figure>
&lt;h2 id="요구사항-및-과거-데이터-분석">요구사항 및 과거 데이터 분석&lt;/h2>
&lt;p>서비스를 운영해보니 감지하기 어려운 상황들이 있었다.&lt;/p>
&lt;ul>
&lt;li>연동하는 쇼핑몰에서 문제가 발생하거나 네트워크 문제가 발생할경우 즉, 트래픽이 평소보다 적게 들어올 경우&lt;/li>
&lt;li>정상적인 에러(e.g. 잔액부족) 가 갑자기 많이 발생할 경우&lt;/li>
&lt;/ul>
&lt;p>이를 분석하기위해 기존의 트래픽/데이터를 분석해봐야 했다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/anomaly-detection/trade_count.png" title="/images/anomaly-detection/trade_count.png" data-thumbnail="/images/anomaly-detection/trade_count.png" data-sub-html="&lt;h2>결제건수 Kibana Visualize, 기영이 패턴&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/anomaly-detection/trade_count.png"
 data-srcset="https://taetaetae.github.io/images/anomaly-detection/trade_count.png, https://taetaetae.github.io/images/anomaly-detection/trade_count.png 1.5x, https://taetaetae.github.io/images/anomaly-detection/trade_count.png 2x"
 data-sizes="auto"
 alt="/images/anomaly-detection/trade_count.png" />
 &lt;/a>&lt;figcaption class="image-caption">결제건수 Kibana Visualize, 기영이 패턴&lt;/figcaption>
 &lt;/figure>
&lt;p>위 그래프는 결제데이터 카운트 인데 어느정도 패턴을 찾을수 있다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/anomaly-detection/error_count.png" title="/images/anomaly-detection/error_count.png" data-thumbnail="/images/anomaly-detection/error_count.png" data-sub-html="&lt;h2>에러건수 Kibana Visualize, 악어 패턴..(무리수..)&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/anomaly-detection/error_count.png"
 data-srcset="https://taetaetae.github.io/images/anomaly-detection/error_count.png, https://taetaetae.github.io/images/anomaly-detection/error_count.png 1.5x, https://taetaetae.github.io/images/anomaly-detection/error_count.png 2x"
 data-sizes="auto"
 alt="/images/anomaly-detection/error_count.png" />
 &lt;/a>&lt;figcaption class="image-caption">에러건수 Kibana Visualize, 악어 패턴..(무리수..)&lt;/figcaption>
 &lt;/figure>
&lt;p>위 그래프는 에러카운트 인데 일정한 패턴 속에서 어느 지점에서는 튀는것을 확인할수 있다. (빨간색 영역) 그렇다면 어떤 방법으로 장애상황보다 앞서서 감지를 할수 있을까? ( 장애 : 어떠한 내/외부 요인으로 인해 정상적인 서비스가 되지 않는 상태 )&lt;/p>
&lt;h2 id="장애발생-전에-먼저-찾아보자">장애발생 전에 먼저 찾아보자!&lt;/h2>
&lt;p>가장 간단하게는 기존 데이터를 보고 수동으로 설정하는 방법이 있을수 있다. 예로들어 자정 즈음에는 결제량이 가장 많기때문에 약 xx건으로 설정해두고, 새벽에는 결제량이 가장 적기 때문에 약 yy건으로 설정해둔 후 에러 건수나 결제건수에 대해 실시간으로 검사를 해가면서 설정한 값보다 벗어날 경우 알림을 주는 방법이다.
하지만 아무리 과거 데이터를 완벽하게 분석했다 할지라도 24시간 모든 시점에서 예측은 벗어날 수밖에 없다. (예로들어 쇼핑 이벤트를 갑작스럽게 하게되면 결제량은 예측하지 못할정도로 늘어날테고&amp;hellip;) 또한 설정한 예측값을 벗어날 경우 수동으로 다시 예측값을 조정해줘야 하는데, 이럴꺼면 24시간 종합 상황실에서 사람이 직접 눈으로 보는것 보다 못할것 같다. (인력 리소스가 충분하다면 뭐&amp;hellip; 그렇게 해도 된다.)&lt;/p>
&lt;h2 id="지난-데이터와-비교하기">지난 데이터와 비교하기&lt;/h2>
&lt;p>일주일 기준으로 지난 일주일과의 데이터를 비교해보는 방법또한 있다. 간단하게 설명하면 이번주 월요일 10시의 데이터와 지난주 월요일 10시의 데이터의 차이를 비교해보는 방법이다. 키바나에서 클릭 몇번만으로 시각화를 도와주는 Visualize 기능을 통해 지난 일주일과 이번주를 비교해보면 아래 그래프처럼 표현이 가능하다.&lt;/p>
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/anomaly-detection/visualize.png" title="/images/anomaly-detection/visualize.png" data-thumbnail="/images/anomaly-detection/visualize.png" data-sub-html="&lt;h2>일주일 전 데이터와 단순 비교&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/anomaly-detection/visualize.png"
 data-srcset="https://taetaetae.github.io/images/anomaly-detection/visualize.png, https://taetaetae.github.io/images/anomaly-detection/visualize.png 1.5x, https://taetaetae.github.io/images/anomaly-detection/visualize.png 2x"
 data-sizes="auto"
 alt="/images/anomaly-detection/visualize.png" />
 &lt;/a>&lt;figcaption class="image-caption">일주일 전 데이터와 단순 비교&lt;/figcaption>
 &lt;/figure>
&lt;p>이 경우도 지난주 상황과 이번주 상황이 다른 경우에는 원하는 비교 항목 외에 다른 요인이 추가되기 때문에 원하는 비교를 할수가 없고 위에서 수동으로 설정하는 방법과 별반 다를바 없을것으로 생각된다.&lt;/p>
&lt;h2 id="조금더-우아하게-언제부턴가-우아하단-말을-좋아하는것-같다">조금더 우아하게! &lt;code>(언제부턴가 우아하단 말을 좋아하는것 같다..)&lt;/code>&lt;/h2>
&lt;p>개발자는 문제에 대해서 언제나 분석을 토대로 접근을 하는것을 목표로 해야한다. 언제부턴가 Hot한 머신러닝을 도입해 보고 싶었으나 아직 그런 실력이 되질 못하고&amp;hellip; 폭풍 구글링을 통해 알게된 Facebook에서 만든 &lt;a href="https://facebook.github.io/prophet/" target="_blank" rel="noopener noreffer ">Prophet&lt;/a>이라는 모듈을 활용해보고자 한다.
&lt;a href="https://opensource.fb.com/#artificial" target="_blank" rel="noopener noreffer ">https://opensource.fb.com/#artificial&lt;/a> 이곳에 가보면 여러 Artificial Intelligence 관련된 오픈소스들중에 Prophet 모듈을 찾을수 있다. 다행히도 &lt;a href="https://namu.wiki/w/BSD%20%EB%9D%BC%EC%9D%B4%EC%84%A0%EC%8A%A4" target="_blank" rel="noopener noreffer ">BSD License&lt;/a>라서 실무에서도 다양하게 활용할수 있을것으로 보인다. 친절하게도 &lt;code>Quick Start&lt;/code>을 통해 어떤식으로 예측을 하는지 보여준다. 참고로 Python 과 R 을 지원한다. (python 의 대단함을 다시금 느끼며&amp;hellip;)
구성은 CentOS 7 + python3.6 + jenkins 를 활용한다. (python 경험이 부족하므로 코드가 허접할수도 있으니 양해바란다.)
데이터 분석시 가장 많이 사용된다는 &lt;code>Pandas&lt;/code>와 대규모 다차원 배열을 쉽게 처리 할 수 있게 해주는 &lt;code>numpy&lt;/code>, 그리고 &lt;code>bprophet&lt;/code>를 비롯한 필요한 모듈들을 pip로 설치해준다.&lt;/p></description></item><item><title>linux(centOS)에서 selenium 설정하기 (feat. python)</title><link>https://taetaetae.github.io/2018/02/01/linux-selenium/</link><pubDate>Thu, 01 Feb 2018 14:52:10 +0000</pubDate><guid>https://taetaetae.github.io/2018/02/01/linux-selenium/</guid><description>&lt;p>테스트 코드로 안되는 실제 브라우저단 사용성 테스트를 하고싶은 경우가 있다. 이를테면 화면이 뜨고, 어떤 버튼을 누르면, 어떤 결과가 나와야 하는 일련의 &lt;code>Regression Test&lt;/code>. 이때 활용할수 있는게 다양한 도구가 있지만 이번엔 &lt;code>selenium&lt;/code> 에 대해서 알아보고자 한다.&lt;!-- more -->&lt;/p>
&lt;p>처음부터 사실 web application 테스트를 하려고 selenium 를 알아보게 된건 아니고, 내가 참여하고 있는 특정 밴드(네이버 BAND)에서 일주일에 한번씩 동일한 형태의 글을 올리고 있는데 (일종의 한주 출석체크 같은&amp;hellip;) 이를 자동화 해볼순 없을까 하며 밴드 API를 찾아보다 selenium 라는것을 알게되었고, 매크로처럼 어떤버튼 누르고 그다음 어떤버튼 누르고 하는 일련의 과정을 코드로 구성할수 있다는 점에 감동을 받아(?) + 별도의 API를 발급받지 않아도 되어 사용하게 되었다. (물론 UI가 바뀌면 골치아프겠지만&amp;hellip;)&lt;/p>
&lt;blockquote>
&lt;p>여기서는 selenium 이 무엇인지에 대한 설명은 하지 않는다. (인터넷에 나보다 정리 잘된글이 많으니&amp;hellip;) 단, linux 환경에서 셋팅하는 정보가 너무 없고 몇일동안 삽질을 한게 아쉬워서 그 과정을 포스팅 해본다. (나같은 분이 이 글을 보고 도움이 되실꺼라는 기대를 갖으며&amp;hellip;)&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>※ 주의 : 본 포스팅은 밴드 서비스에 글을 올릴수 있는 비 정상적인 방법의 공유가 아닌, selenium에 대한 사용 후기(?)에 대한 글입니다. (참고로 막혔어요 -ㅁ-)&lt;/p>&lt;/blockquote>
&lt;h2 id="설정하기">설정하기&lt;/h2>
&lt;p>서버 환경은 CentOS 7.4 64Bit + Python 3.6.3 + jdk 8 이다. 우선 selenium 을 설치해준다.&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo python3.6 -m pip install selenium
&lt;/code>&lt;/pre>&lt;p>그 다음 CentOS에서 크롬브라우저를 설치하기 위하여 yum 저장소를 추가한다. (꼭 크롬이 아니더라도 파이어폭스나 지금은 지원이 끊긴 팬텀JS 같은것으로 활용할수도 있으나 다른것들도 해봤는데 자꾸 설정에서 걸려서 크롬에 대한 내용을 포스팅 한다.)&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo vi /etc/yum.repos.d/google-chrome.repo
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
&lt;/code>&lt;/pre>&lt;p>그리고는 yum 으로 크롬 브라우저를 설치한다. (내가 설치했을때의 버전은 &lt;code>google-chrome-stable.x86_64 0:64.0.3282.119-1&lt;/code>)&lt;/p>
&lt;pre tabindex="0">&lt;code>$ yum install google-chrome-stable
&lt;/code>&lt;/pre>&lt;p>크롬드라이버를 설치해야한다. 다음 url에서 받을수 있는데 &lt;a href="https://sites.google.com/a/chromium.org/chromedriver/downloads" target="_blank" rel="noopener noreffer ">https://sites.google.com/a/chromium.org/chromedriver/downloads&lt;/a> 나는 2.35 linux64 버전을 받았다. 다운받고 unzip 하면 딱하나 파일이 있는데 나중에 selenium 을 사용할때 이용되니 path를 알아두자.&lt;/p>
&lt;p>그다음 파이썬 코드를 작성한다. 내가 짠 파이썬 코드는 다음과 같은 순서로 실행이 된다.&lt;/p>
&lt;ul>
&lt;li>밴드 접속 ( &lt;a href="https://band.us/home" target="_blank" rel="noopener noreffer ">https://band.us/home&lt;/a> )&lt;/li>
&lt;li>로그인&lt;/li>
&lt;li>특정 밴드 선택&lt;/li>
&lt;li>글쓰기 버튼 누르고 양식에 맞춰 글 작성&lt;/li>
&lt;li>글 등록&lt;/li>
&lt;/ul>
&lt;p>파이썬 코드는 아래처럼 작성하였다. (중요부분만.. 그 아래는 자유)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.chrome.options&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Options&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 초기화 --------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">chrome_options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Options&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">chrome_options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--headless&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Chrome&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">executable_path&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;home/~~~/chromedriver&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">chrome_options&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chrome_options&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">implicitly_wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://band.us/home&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 로그인 --------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_class_name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;_loginLink&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span>&lt;span class="n">생략&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 실행을 해보면 작동이 잘~ 된다.
&lt;figure>&lt;a class="lightgallery" href="https://taetaetae.github.io/images/linux-selenium/result.png" title="/images/linux-selenium/result.png" data-thumbnail="/images/linux-selenium/result.png" data-sub-html="&lt;h2>selenium &amp;#43; python 으로 자동작성된 밴드 글&lt;/h2>">
 &lt;img
 class="lazyload"
 src="https://taetaetae.github.io/svg/loading.min.svg"
 data-src="https://taetaetae.github.io/images/linux-selenium/result.png"
 data-srcset="https://taetaetae.github.io/images/linux-selenium/result.png, https://taetaetae.github.io/images/linux-selenium/result.png 1.5x, https://taetaetae.github.io/images/linux-selenium/result.png 2x"
 data-sizes="auto"
 alt="/images/linux-selenium/result.png" />
 &lt;/a>&lt;figcaption class="image-caption">selenium + python 으로 자동작성된 밴드 글&lt;/figcaption>
 &lt;/figure>&lt;/p>
&lt;h2 id="마치며">마치며&lt;/h2>
&lt;p>&lt;code>selenium&lt;/code> 에 대해 찾아보면 거의 윈도우 환경에서 돌아가는것들에 대한 포스팅이 많았다. 난 리눅스 환경에서 스케쥴러(젠킨스 같은)를 통해 자동으로 화면없이 작동시키고 싶었는데 아무리 찾아봐도 + 삽질해도 잘 안되었다. 결국 사내에도 나같은 삽질을 하신 분을 찾고 묻고 물어 &lt;code>크롬드라이버&lt;/code>만 있어야 하는것이 아니라 &lt;code>크롬앱&lt;/code>또한 있어야 동작을 한다는것을 알게 되었다.
&lt;strong>역시, 내가 한 삽질은 누군가 이미 한 삽질이라는걸 다시한번 깨닳은 좋은(?) 시간이였다.&lt;/strong>&lt;/p>
&lt;p>이걸로 나중에 내가 맡고있는 서비스에 대한 웹 자동 테스트 툴도 만들어 볼 생각이다.&lt;/p></description></item><item><title>파이썬 버전 업그레이드 (2.6 > 3.6)</title><link>https://taetaetae.github.io/2018/01/08/python-2-to-3/</link><pubDate>Mon, 08 Jan 2018 13:44:50 +0000</pubDate><guid>https://taetaetae.github.io/2018/01/08/python-2-to-3/</guid><description>&lt;p>파이썬 2.x 에서는 depreate 된 모듈도 많고 3.x에서만 지원되는 버전들이 많아지면서 실컷 개발을 해도 파이썬 버전때문에 다시 짜야하는 상황이 생긴다. 파이썬 버전업을 하고싶어 구글링을 해보면 이렇다할 정리된 문서가 잘 안나온다. (영어로된 포스트는 많이 있긴 하나, 필자의 환경과는 맞지 않는 &amp;hellip;)&lt;!-- more --> 그래서 이것저것 삽질을 한 결과 파이썬 버전을 올릴수 있었고, 이를 포스팅 해보고자 한다.&lt;/p>
&lt;blockquote>
&lt;p>그러보고니 2018년 첫 포스팅이네&amp;hellip; 올해는 정말 적어도 한달에 1~2개는 올릴수 있는 내가 되기를&amp;hellip;&lt;/p>&lt;/blockquote>
&lt;h2 id="환경">환경&lt;/h2>
&lt;ul>
&lt;li>CentOS 6.9&lt;/li>
&lt;li>기본으로 python 2.6 이 설치되어 있는것을 확인할수 있다. (환경마다 다를수 있음.)&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ python -V
Python 2.6
&lt;/code>&lt;/pre>&lt;h2 id="설치순서">설치순서&lt;/h2>
&lt;ul>
&lt;li>필요한 유틸리티를 설치한다.&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ sudo yum update
$ sudo yum install yum-utils
$ sudo yum groupinstall development
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>yum 저장소에서는 최신 파이썬 릴리즈를 제공하지 않으므로 RPM 패키를 제공하는 IUM 이라는 추가 저장소를 설치&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ sudo yum install -y https://repo.ius.io/ius-release-el7.rpm
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>파이썬 3.6 버전을 설치&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ sudo yum install python36u
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>pip 등 패키지 관련 모듈도 함께 설치&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>sudo yum install python36u-pip
sudo yum install python36u-devel
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>여기까지 하면 기존 파이썬 &lt;code>2.6&lt;/code>과 새로 설치된 파이썬 &lt;code>3.6&lt;/code> 이 설치되어있다.&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ ll /usr/bin/python*
-rwxr-xr-x 1 root root 9997450 Jan 2 16:02 python
lrwxrwxrwx 1 root root 6 Jan 1 06:02 python2 -&amp;gt; python
-rwxr-xr-x 1 root root 9032 Aug 19 2016 python2.6
-rwxr-xr-x 1 root root 1418 Aug 19 2016 python2.6-config
-rwxr-xr-x 2 root root 6808 Oct 12 08:19 python3.6
lrwxrwxrwx 1 root root 26 Jan 2 20:48 python3.6-config -&amp;gt; /usr/bin/python3.6m-config
-rwxr-xr-x 2 root root 6808 Oct 12 08:19 python3.6m
-rwxr-xr-x 1 root root 173 Oct 12 08:19 python3.6m-config
-rwxr-xr-x 1 root root 3339 Oct 12 08:16 python3.6m-x86_64-config
lrwxrwxrwx 1 root root 16 Apr 25 2017 python-config -&amp;gt; python2.6-config
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>환경변수를 설정해준다.&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ sudo mv python python_backup
$ sudo ln -s python3.6 python
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>확인&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ python -V
Python 3.6.3
&lt;/code>&lt;/pre>&lt;h2 id="pip-를-이용한-모듈-설치">pip 를 이용한 모듈 설치&lt;/h2>
&lt;ul>
&lt;li>pip란 Python Package Index 의 약자로 공식홈페이지는 다음과 같다. ( &lt;a href="https://pypi.python.org/pypi/pip" target="_blank" rel="noopener noreffer ">https://pypi.python.org/pypi/pip&lt;/a> )&lt;/li>
&lt;li>설치할 모듈을 다음과 같이 설치해주면 된다. ex : requests 모듈인 경우&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>$ sudo python3.6 -m pip install requests
&lt;/code>&lt;/pre></description></item></channel></rss>