2월 162017
 

PS4 Pro가 나온지 벌써 3개월이 지났지만 여전히 재고는 없고 검색을 조금만 해보면 가격을 높혀 파는 매물만 존재하는 듯 하다. 이에 몇몇 사람들은 포기하고 PS4 Slim을 구매하는 사람들도 있고 어떤 분들은 해외에서 직구를 하거나 윗돈을 주고 중고나라에서 구매하는 사람들도 존재하는 것 같다. 본인 같은 경우는 A/S가 확실치 않은 직구를 하고 싶진 않고 중고를 그다지 좋아지지 않는 나는 이 길을 택하지도 않을 것이고 급하지도 않기 때문에 매물이 있는 PS4 슬림을 구매하지는 않는다. 그러면 한국에서 일반적인 경로로 물건을 구매하게 될텐데 크게 두 가지 경로가 있을 것이다. 하나는 오프라인을 통해서 구매하는 방법이 있고 다른 한 가지 방법이 온라인을 통한 방법이다. 오프라인의 경우 회사 휴가를 쓸 수도 없고 구매하는 곳까지 가야하고 줄도 서야하고 너무 귀찮기 때문에 온라인을 노려보기로 했다. 그런데 재고가 들어왔을 때 알려주는 기능이 있다면 상관 없지만 그게 아니기 때문에 귀찮은 것을 싫어하는 개발자 입장에서 홈페이지에 주기적으로 접속해서 재고 여부를 확인하는 프로그램을 만들고자 하였다.

요구사항

  • 지금 사용하고 있는 개인 서버(리눅스)에서 쉽게 설정해서 쓸 수 있을 것
  • 만드는데 10분안에 뚝딱 만들 것
  • 최대한 로직 간단하게 하기

그 결과 쉘 스크립트가 가장 만만한 선택지였고 홈페이지에서 웹페이지를 다운로드 받아서 문자열 분석해서 구현하는 것으로 하였다. 쉘 스크립트는 가끔씩 만들어 본 적이 있어서 익숙하다는 점도 한 목 했다.

알고리듬

1) PS4 구매 페이지를 다운받는다.
2) "재고없음"이란 글자가 있는지 확인한다.
3) 만일 "재고없음"이 존재하면
  3-1) n초 기다린다
  3-2) 1로 돌아감
4) 만일 "재고없음"이 없으면
  4-1) 비프음을 울리고 이메일 전송
  4-2) 종료

한계점 : 네트워크가 안된다던지 하는 경우는 제외, 구매 페이지 자체의 형식이 바뀌는 부분은 제외 등

구현 준비

웹 페이지의 구성 확인

간단한 구현을 위해서 웹페이지의 소스의 문자열을 파악하는 방식으로 구현하는 것을 고려하였다. 이에 따라서 재고가 있는 페이지와 재고가 없는 페이지를 비교했다. 어떤 차이점이 있는지를 알아야 문자열 비교를 할 수 있기 때문이다. 제일 좋은 점은 재고 있는 경우 또는 재고 없는 경우에 특정한 문자열(단어)이 존재하는 것이 최고이다. 운이 좋게도 “재고없음”이라는 단어가 재고가 있는 경우는 등장하지 않는 것을 확인 가능했다.

아래는 이를 위해 이용한 url이다. 물론 이건 2017년 2월 15일 현재에 확인한 결과이니 나중에 재고 없는데 왜 있냐라거나와 같은 이야기가 안나오기를 바란다.

크롬에서 공식PS4판매 페이지 소스코드 보기

리눅스 명령어 조사

리눅스 명령어를 조합해서 만드는 것이 매우 직관적이고 불필요한 재개발을 줄일 수 있는 좋은 선택이기 때문에 최대한 사용해 보겠다.

| – 파이프라인 (pipeline)

쉘에서 파이프(|)는 파이프 좌측 명령의 stdout을 파이프 우측 명령의 stdin으로 입력해주는 역할을 한다.

지금까지 조사했던 내용을 조합해 보면 wget -qO- https://store.sony.co.kr/handler/ViewProduct-Start?productId=50150445 | grep -c '재고없음'을 입력하면 재고가 없을 때 1이상의 값이 되며, 재고가 있을 때 0이 출력되게 되는 코드가 만들어 진다.

명령어 치환 (Command Substitution, “)

\`\을 이용하면 \`blah\라는 명령어를 실행하고 그에 따른 stdout텍스트로 치환하는 기능이다.
예를 들면 ls error.log.`date "+%Y%m%d"`라고 실행하면, ls error.log.20170216이 실제로 실행되게 된다.

wget – 웹페이지 다운로드

wget을 이용하면 웹 페이지의 내용을 가져올 수 있다. https나 http에 필요하면 로그인, 쿠키 등도 붙일 수 있고 옵션을 붙이면 stdout으로 결과를 뽑아볼 수 있기 때문에 다른 명령어와 연동하기에 편리하다.
여기서는 wget -qO- <<http location>>을 이용하여 웹 페이지(html)를 가져와서 stdout으로 출력한다.

grep – 문자열 검색

grep은 리눅스에서 잘 사용하면 많은 것을 할 수 있는 기능으로써 입력된 문자열에서 특정 문자열을 검색하는데 사용한다. 여기서 주목한건 -c옵션인데, 이를 이용하면 그 문자열이 입력된 문자열에서 몇 번 등장했는지 횟수를 stdout으로 출력할 수 있다.

예를 들어 echo "거북이 밥먹어 하하하" | grep -c '거북이'라는 코드를 입력하면 1을 출력하게 되는 것이다. 만약 echo "토끼 밥먹어 하하하" | grep -c '거북이'라는 코드를 입력하면 ‘거북이’라는 문자열이 없기 때문에 0이 리턴된다.

echo – 입력을 그대로 출력

셀 스크립트를 구현할 때, 현재 진행상황을 출력하기 위해서 사용되는 명령어이다. echo hello를 입력하면 stdout으로 hello가 출력된다.
-n 옵션 사용시 뒤에 개행을 하지 않는다. -e옵션 사용시 escape 문자열을 해석한다. ASCII에서 문자열 역할을 하지 않는 코드들을 생각하면 된다.
따라서 비프음을 쉘에서 울리고 싶다면, ASCII에서 비프를 의미하는 0x07 BEL을 이용한다. 응용해 보면 echo -ne '\007'을 입력하면 비프음이 울리게 된다.

sleep – 지정한 시간만큼 멈춤

sleep <<seconds>>명령어는 입력한 만큼의 숫자의 초만큼 프로그램을 정지시키는 명령어이다. 소수점도 이용 가능하다. 예를 들면, sleep 0.1이라고 입력하면 0.1초 동안 정지된다.

mail – 메일을 확인하거나 보내는 명령어

mail명령어를 전부 설명하면 범위를 벗어나기 때문에 보내는 방법에만 집중해보면, echo “PS4 Pro 재고가 있어요!!!” | mail -s “[알림]PS4Pro 재고 있음!!” blah@gmail.com과 같이 입력하면 제목을 [알림]PS4Pro 재고 있음!!으로, 내용은 PS4 Pro 재고가 있어요!!!, 보내는 주소는 blah@gmail.com이 되는 것이다. 혹시 전송이 안되거나 스팸메일함으로 전달 된다면, 믿을 수 있는 smtp 서버를 지정하면 되는데, 이 부분은 범위를 벗어나니 linux sendmail이란 키워드로 검색해 보는 것을 추천한다.

exit – 종료

쉘에서 나갈 때는 exit를 사용하면 종료되게 된다.

쉘 스크립트 언어

지금까지 위의 명령어를 이용하면 위의 알고리듬을 실행하기 위한 구성요소들은 거의 다 준비되었다고 볼 수 있다. 하지만 여기서 문제는 재고없으면 어떻게 다시 실행시킬 것인지 재고가 있는 경우 어떻게 알릴 것인지가 해결이 되지 않았다.
이 부분을 쉘 스크립트를 통해서 해결한다. 여기서는 많이 사용되고 있는 bash쉘을 이용하여 구현해 보겠다.

시작 부분

쉘 스크립트의 시작부분에는 #!/bin/bash를 입력한다. 그러면 이 쉘 스크립트의 내용을 실행할 때 /bin/bash를 통하여 동작시키게 된다. bash를 사용하지 않았으면 해당하는 언어를 적으면 된다. 파이썬이나 펄도 마찬가지 방법으로 이용할 수 있다.

변수대입

변수 대입은 변수명=대입할내용를 통해서 할 수 있다. 숫자 10abc란 변수에 넣고 싶으면 abc=10이라고 입력하면 된다.

변수사용

변수를 사용할 때는 변수명 앞에 $기호를 붙인다. 예를 들어서 abc란 변수를 사용할 떄는 $abc로 입력한다.

조건문

아래와 같은 형식으로 조건문을 사용할 수 있다.

if [<<조건>>]; then
   <<내용>>
fi

반복문

while 인 경우

while <<조건>>
do
   <<내용>>
done

for를 쓸 경우 (1~30까지 1씩 증가하면서 변수 i에 넣음)

for i in {1..30}
do
   <<내용>>
done

숫자계산

쉘 스크립트에서 숫자에 대한 사칙연산 등은 아래의 명령어를 사용한다.
$((<<expr>>))

예)
a=$((1+2+3)) => $a6입력
b=$((a+10)) => $a6이므로 $b16이 입력
c=$((b-1)) => $a6, $b16이므로 $c에는 10이 입력

주석처리

# 등장 후 개행까지는 전부 주석으로 취급함

실제 코드 구현

위에서 간단하게 배워본 쉘 스크립트를 통하여 실제 프로그램을 구현해 보았다.
알고리듬을 기준으로 구현한 코드는 아래와 같다.

#!/bin/bash

retry_count=0

while true
do
        # 50150247 : PS4 slim
        # 50150445 : PS4 Pro

        echo "try #$retry_count... "
        retry_count=$((retry_count + 1))

        result=`wget -qO- https://store.sony.co.kr/handler/ViewProduct-Start?productId=50150445 | grep -c '재고없음'`

        if [ $result == 0 ] ; then
                echo '재고 풀렸음!!!'

                # beep 음
                for i in {1..30}
                do
                        echo -ne '\007'
                        # 30fps
                        sleep 0.03
                done

                # 메일 전송
                echo “PS4 Pro 재고가 있어요!!!” | mail -s “[알림]PS4Pro 재고 있음!!” blah@gmail.com

                # 종료
                exit
        fi

        # retry each 60 seconds
        sleep 60
done

vinano와 같은 텍스트 에디터를 열어서 ps4_checker.sh이라는 이름으로 만든다.
그 이후 쉘이 실행될 수 있도록 chmod u+x ps4_checker.sh을 실행하여 실행권한을 부여한다.

비프음의 경우 sleep으로 끊어서 처리하지 않으면 중첩되서 한 번 밖에 들리지 않게 된다.

실행방법

./ps4_checker.sh 을 실행한다. 그러면 60초마다 한 번 씩 재고유무를 체크하게 된다.
실제로 재고 있을 때 동작하는지 ‘PS4 Slim’웹페이지 주소를 이용하여 테스트 해보도록 하자.

재고 있는 경우

$ ./ps4_checker.sh
try #0...
재고 풀렸음!!!
$

성공적으로 이메일이 오는 것을 확인할 수 있다. 만약 안보이면 스팸메일함을 확인해 보자. 그래도 없으면 mail관련 리눅스 설정이 추가적으로 필요할 수도 있다.

재고가 있다는 이메일을 받은 화면

재고 없는 경우

$ ./ps4_checker.sh
try #0...
try #1...
try #2...
try #3...
try #4...
try #5...

강제 종료는 “Ctrl+C”를 하면 된다.

한계

“재고없음”이라는 글자가 없는 것을 판단하기 때문에, 인터넷이 끊기게 되면 재고있다고 오작동 하게 된다. 이 부분은 여러분이 수정해 보도록 하자! 🙂

결론

이 글은 어떻게 이 프로그램을 만들게 되었고 어떤 요구사항을 따르게 해야하는지 정리하였으며 구현 시작하기에 앞서 실제 PS4판매 페이지의 특성을 분석해보았으며 이에 알맞는 프로그램을 개발하기 위해서 쉘 스크립트 언어와 여러 리눅스 명령어를 조사하여 실제로 구현하여 잘 동작하는 것을 확인할 수 있었다. 물론 인터넷이 끊기거나 홈페이지가 변경되었을 때에 대응책에 대한 부분은 최대한 간단히 만들기 위해서 고려상황에서 제외하였다. 또한 대몬(daemon)화 시켜서 동작시키는 부분도 범위 밖이기 때문에 다루지 않았다. 이 글을 통해 꼭 C나 자바와 같은 프로그래밍 언어를 공부해야만 프로그램을 만들 수 있는게 아니라 리눅스에서 제공하는 유용한 명령어들을 조합하여 구현하는 것으로도 충분히 쓸만한 유용한 프로그램을 만들 수 있다는 것을 알 수 있었다. 이를 응용하면 꼭 이 상황뿐만 아니라 다른 홈페이지를 감시하는 경우에도 활용할 수 있을 것이다.