2013년 7월 7일 일요일

PHP, 스누피 클래스를 이용해서 현재 주가 긁어오기

PHP로 작성된 강력한 외부 소켓 클래스인 스누피(Snoopy)클래스를 이용하면 웹사이트 내용을 쉽게 스크래핑 해 올 수 있습니다. 제 경우에는 투자를 위해서 스누피 클래스를 사용하고 있습니다. 현재 주가를 실시간으로 긁어와서 제가 생각하는 목표 가격대와 괴리율이 얼마인지 한눈에 볼 수 있어서 편리합니다. 또 각 포털사이트와 신문사의 기사 중 관심 키워드가 포함된 신문 기사도 실시간으로 긁어와서 구독하고 있기 때문에 편리합니다.


스누피 클래스를 응용하는 방법은 많겠지만 오늘은 포털 사이트 다음에서 제공하는 실시간 주가를 스크래핑해서 가져오는 방법을 간단하게 소개 드리겠습니다.

스누피 클래스 설치


스누피 클래스는 따로 설치할 필요없이 다운로드만 받아 프로젝트 내에 복사하면 됩니다. 스누피 클래스를 다운로드 받을 수 있는 주소는 다음과 같습니다.

다운로드 : http://sourceforge.net/projects/snoopy/files/latest/download

다운로드를 받고 나서 압축을 풀면 Snoopy-1.2.4라는 폴더가 생깁니다. 이전 1.2.3버전에서는 구문 오류가 몇 군데 있었던 것 같은데 이번 버전에서는 고쳐진 것 같네요. Snoopy-1.2.4 디렉토리를 열어보면 아래와 같은 파일들이 있습니다.


스누피 클래스가 지원하는 기능이나 사용법에 대해서 궁금하신 부분이 있으면 README 파일을 읽어보시면 됩니다. 가장 핵심적인 파일은 Snoopy.class.php 파일 입니다. 저 파일을 우리가 만들고자 하는 프로젝트 내에 위치시키면 바로 사용할 수 있는 준비가 됩니다. 설치라고 할 것도 없네요. 이것으로 스누피 클래스가 준비되었습니다.

페이지 스크래핑 테스트(네이버 메인 페이지 긁어오기)


그럼 스누피 클래스를 이용해서 웹페이지 하나를 테스트로 스크래핑 해 보겠습니다. 일단 test.php 파일을 하나 생성해서 HTML의 <body>태그안에 다음과 같은 코드를 작성해 보았습니다.
include_once 'Snoopy.class.php';
$snoopy = new snoopy;
$snoopy->fetch("http://www.naver.com");
$txt = $snoopy->results;
print_r($txt);
구글 블로그에서 Syntax Highligher를 쓰니 일부 구문이 깨지거나 왜곡 되네요. 감안하여 코드를 읽어주시면 감사 드리겠습니다.

스누피 클래스를 현재 프로젝트에 인클루드 하여(이 예제의 경우 스누피 클래스 파일이 동일한 폴더내에 있다고 가정), $snoopy에 새 객체를 만들어서 담았습니다. fetch 구문을 이용해서 네이버의 메인페이지를 모두 긁어오라고 구문 한 줄을 추가했고, 긁어온 구문은 $txt변수에 담아서 이를 print_r 해서 화면에 뿌려주는 간단한 구문입니다.

정말 너무너무 간단하고 강력합니다. 아래는 위 구문을 실행해서 네이버 메인페이지를 스크래핑해서 긁어온 결과입니다. (스타일 시트는 당연히 안 긁어옵니다.)


너무너무 쉽고 간단하게 네이버 메인 페이지의 내용들을 스크래핑 해 왔습니다. 정말 쉽고 강력합니다.

원하는 부분만 가져오기 (주가만 긁어오기)


웹페이지 전체를 긁어오지 않고 원하는 부분만 가져올 수 없을까요? 당연히 그것도 가능합니다. 아래 화면은 포털 사이트 다음에서 제공하는 주식 종목 정보 페이지 입니다.


'수출포장'이라는 종목 정보 페이지입니다. 이 종목 페이지 내용을 전부 긁어오고 싶은게 아니라, 현재가만 가져오려고 합니다. 그러려면 먼저 이 페이지의 URL을 알아야겠습니다.

다음 증권 종목 페이지 주소 : 
http://stock.daum.net/item/main.daum?code=002200

주소에서 가장 마지막 숫자 6자리는 종목코드입니다. 이 예제에서는 종목코드 '002200'번  즉, 수출포장 종목의 시세를 가져오도록 하겠습니다.

현재가 부분을 가져 오려면 HTML DOM 구조를 파악해야 합니다. 해당 페이지 소스 보기를 하거나 개발자 도구를 이용해서 현재가 부분의 마크업을 살펴보도록 하겠습니다.


우리가 가져 올 현재가는 <em class="curPrice up"></em> 이라는 방법으로 마크업이 돼 있네요. 보니까 시세는 curePrice라는 클래스를 사용하는 것 같고, 뒤에 up, down 으로 하락인지, 상승인지, 보합인지 색상을 입혀주는 클래스가 추가로 적용돼 있는 것 같습니다.

그럼 정규식을 이용해서 저런 마크업을 찾아 저기 있는 숫자만 빼내 오도록 하겠습니다. 참, 동일한 페이지 내에서 동일한 마크업을 사용하는 부분이 다른 곳에도 있다면 스크래핑이 여러번 되므로 저렇게 마크업 한게 저 부분 뿐인지 꼭 확인해야 합니다.
include_once 'Snoopy.class.php';
$snoopy=new snoopy;
$o="";
$snoopy->fetch("http://stock.daum.net/item/main.daum?code=002200");
$txt=$snoopy->results;
$rex="/\<em class=\"curPrice.+\"\>(.*)\<\/em\>/";
preg_match_all($rex,$txt,$o);
print_r($o[0][0]);
아까 네이버 메인 페이지 전체를 긁어온 코드를 조금 수정했습니다. fetch는 다음 증권 페이지 수출포장 종목을 바라 보도록 했습니다.

그리고 $rex 변수에 담기는 정규식을 잘 봐주세요. <em>태그에 curePrice라는 클래스를 가지고 있는 부분을 찾는 구문입니다. <em>~</em>태그 사이에 숫자만 뽑아와 $rex 변수에 담았습니다.

그리고 PHP의 정규 함수인 preg_match_all 함수에 이를 담아 정규식을 해석하고 print_r로 가져 온 가격 정보를 화면에 뿌려주는 간단한 코드입니다. 이 코드를 실행한 결과는 아래 화면과 같습니다.


정규식으로 추출한 <em>태그가 잘 스크래핑 돼 가져와 졌음을 확인할 수 있습니다. 이런식으로 스누피 클래스를 응용하면 다양한 벙법으로 나만의 편리한 도구를 만들어서 사용할 수 있습니다.

만약 DB에 종목 모드 정보를 넣어 놓고 동적으로 종목별 가격 정보를 얻어 오고 싶다면 다음과 같이 코딩하면 됩니다.

먼저 아래와 같은 코드를 작성해서 DB에 연결을 해야겠죠.
// DB 연결
$connect = mysql_connect("localhost","root","root") or die("DB에 연결할 수 없습니다.<br>");
mysql_query('set names utf8');
mysql_select_db("stocks",$connect);

// 종목 목록 가져오기
$query="SELECT*FROM list";
$result=mysql_query($query,$connect);
DB연결에 성공하고 종목 목록 정보를 가져 왔다면 while 문을 이용해서 종목 개수 즉, DB의 row 개수 만큼 반복을 돌립니다.
while ($row=mysql_fetch_array($result)) {
  // 여기에 스크래퍼에서 가져 온 마크업 정보를 뿌려주면 되겠죠.
}
그리고 while 문 안에,
include_once 'Snoopy.class.php';
$snoopy=new snoopy;
$o="";
$snoopy->fetch("http://stock.daum.net/item/main.daum?code=".$row[s_code]);
$txt=$snoopy->results;
$rex="/\<em class=\"curPrice.+\"\>(.*)\<\/em\>/";
preg_match_all($rex,$txt,$o);

<tr>
 <th>현재가</th>
 <td><? print_r($o[0][0]); ?></td>
</tr>
이와 같은 식으로 코드가 들어가면 됩니다. snoopy 객체 fetch 하는 부분에서 다음 증권 URL 마지막 숫자 6자리는 종목 코드라고 했습니다. 위 예시 코드에서는 DB에서 종목코드를 저장할 때 필드명을 's_code'로 지정했기 때문에 .$row[s_code] 라고 받아오면 동적으로 처리가 가능합니다.

그리고 루프를 돌면서 <tr>태그를 한 줄씩 뿌려가며 가격 정보를 보여주겠죠. 간단하지만 강력한 스누피 클래스를 이용한 스크래핑 방법에 대해서 알아보았습니다.

스크래핑 시 주의 사항


이미 잘 알고 계시는 독자분들도 많으시겠지만, 스크래핑을 할 때는 몇 가지 주의해야 할 사항들이 있습니다.

  • 웹페이지의 디자인이 바뀌어 마크업 DOM구조가 바뀌면 스크래핑 코드도 바꿔줘야 합니다. 혹시 스크래퍼 제대로 페이지 내용을 스크래핑 해오지 못하면 가장 먼저 긁어 올 대상 웹페이지의 디자인이 바뀌지 않았는지를 체크해야 합니다.
  • 스크립트를 이용해서 스크래퍼가 매일 같은 시간에 지속적으로 대량의 트래픽을 발생시켜 스크래핑을 한다면 내 서버쪽 IP가 차단돼 해당 사이트에 접속이 안 될수도 있습니다. 당연히 스크래핑은 안되겠죠. 불규칙적 비정기적, 다양한 IP로 스크래핑 하는 것이 편법이기는 하지만 안전합니다.
  • 아예 서버에서 외부 스크래핑을 막는 경우도 있으니 스크래핑 하기 전 간단하게 테스트를 해봐야 합니다.

스누피 클래스


스누피클래스는 스크래퍼 이외에도 소켓 통신을 위한 다양한 기능을 지원하는데 이 부분에 대해서는 추후 시간이 나면 다시 설명드릴 수 있도록 하겠습니다. 간단한 프로그래밍으로 투자 효율을 높이시기 바랍니다.

2013년 7월 7일
송종식 드림