[PHP] 네이버 카페 API를 이용한 싸이월드 클럽 => 네이버 카페 이전 후기

Posted by 적분 ∫2tdt=t²+c
2017.01.28 03:33 적분史

불과 10여 년 전까지만 해도 대학생 과 커뮤니티 100 중 99는 싸이월드 클럽을 사용했습니다. 과연 싸이월드의 전성기라고 할 수 있었죠. 하지만 시대가 변해 SNS가 등장하고 싸이월드가 망하면서 싸이클럽 역시 쇠락의 길로 접어들었습니다. 지금은 대부분의 대학생 커뮤니티가 페이스북을 기반으로 하고 있다고 알고있으며, 일부 카페를 사용한다고 하는데요, 페이스북 그룹의 특징 상 게시물을 카테고리화해서 분류하기가 어렵고, 과거 자료를 열람하는 것이 매우 불편합니다. 그래서 과 커뮤니티를 네이버 카페로 옮기기로 했습니다.

싸이월드 클럽 크롤러

문제는 02년부터 최근까지 10년 넘게 축적된 싸이클럽의 데이터를 어떻게 카페로 옮길 것인가! 였습니다. 만 개가 넘는 게시물을 어떻게 손으로 직접 옮길수는 없고, 프로그램을 이용해야할텐데 딱히 좋은 방법이 없더라구요. 다행히도 예전에 monoless 형님이 만들어 공개하준 싸이클럽 추출기(https://github.com/monoless/cyworld-club-exporter)가 있어서 이걸 포크해서 기능을 개선해서 https://github.com/bab2min/cyworld-club-exporter 를 만들었습니다. node js 기반으로 작성된 코드고, 이를 실행하여 싸이클럽에서 게시물은 JSON 형태로 가져오고 첨부된 파일과 사진을 모두 다운받아 저장했습니다.


네이버 카페 API

이제 네이버 카페에 자동으로 이 게시물을 올려야하는데, 이는 네이버에서 제공하는 카페 API를 이용하기로 했습니다. 사실 카페 API가 좀 부실하긴 합니다. 제공하는게 카페 가입과 글쓰기인데, 글쓰기는 말머리 선택이나 첨부파일 삽입 등이 안되고, 댓글도 달 수가 없습니다. 어쩔 수 없이 게시물 내에 댓글이나 기타 메타데이터 정보를 다 꾸겨넣는 형태로 이전을 하기로 결정했습니다.

네이버 API를 사용하려면 웹 서버가 필요하기에 PHP 위에서 돌리기로 하고 코드를 작성했습니다. 당연히 버전은 PHP 7.0입니다. 따라서 그 이하 버전의 PHP에서는 아래 코드가 정상적으로 작동되지 않을 수도 있습니다.


먼저 인증은 OAuth2.0 방식으로 수행됩니다. 제일 처음 인증을 요청하려면 다음과 같이 하면 됩니다.

<request.php>


request.php에 접속하면 네이버 로그인 창이 연결됩니다. 로그인이 성공하면 해당 앱의 작동을 허용할것인지 물어보구요, 여기서 승락을 하면 callback url로 넘어가게 됩니다.


callback url 측에서는 다음과 같이 처리해주면 되구요.

<callback.php>


넘겨받은 code와 state를 이용해 다시 네이버에 요청해 access_token을 받게 됩니다. 이 access_token이 있어야 카페 API를 비롯한 모든 로그인 API에 접속가능하게 됩니다.

(위의 code들은 네이버 개발자 페이지에서 가져와서 수정했습니다.)


multipart/form-data로 이미지 첨부를 처리하는게 까다롭더라구요. 카페 API를 편리하게 이용하기 위해 클래스를 만들었습니다.


access_token을 이용해 NaverCafe 클래스를 생성하고, write 메서드를 호출해서 카페에 게시물을 작성하는것이죠. write의 파라메터 중 $images는 첨부할 이미지 파일들의 경로를 배열에 넣어주어야합니다. 첨부할 이미지가 없다면 빈 배열을 넣어주면 됩니다.

첨부파일은... 아직 업로드할 방법을 찾아내지 못했네요. 일단 이미지의 비중이 크니 이미지부터 업로드시키고 나중에 생각해보렵니다.


JSON으로 받은 게시물은 MariaDB에 SQL로 입력하고, 첨부 사진/파일들은 서버에 업로드했습니다. 첨부 파일이 3기가가 넘는 관계로 업로드에 4시간이 넘게 걸렸어요... 네이버 카페로 이전된 게시물은 데이터베이스 측에서 체크하도록 하고, 오류가 발생한 게시물은 오류 내용까지 넣어두도록 했습니다. 

문제는..... 네이버의 게시물 작성 정책이었는데, 하루에 ID/IP당 게시물 작성 갯수를 200개로 한도를 두었습니다. 그리고 짧은 시간에 더 자주 업로드할수록 제한을 강하게 거는듯하구요. 1만개가 넘는 게시물을 이렇게 업로드하려면 50일이 넘게 걸려요. 또 access_token 만료기한이 1시간이기 때문에 1시간마다 재인증을 해줘야하니, 프로그램을 계속 돌리려해도 하루에 한 번씩, 최소 50번은 재인증을 해줘야하구요. 일단 다중계정으로 해결해보고자 합니다. 과연 이 작업이 언제 끝날지 심히 걱정되긴 하네요...ㅋㅋㅋㅋ

Tags
이 댓글을 비밀 댓글로
    • YS
    • 2017.03.26 17:49
    03년도부터 제작년까지 사용하던 싸이클럽의 게시글들을
    네이버 카페로 하나씩 옮기려 하다 검색을 통해 이 글을 발견하게 되어 기쁜 한 명의 컴알못입니다!

    GitHub의 사용법(??)을 몰라 친절하게 설정방법이나 실행 순서까지 적어주셨음에도 불구하고
    실행하지 못하다 댓글을 남깁니다 ㅜㅜ
    혹시 정말정말정말 기초라고 할 수 있는 설정이나 실행방법에 대해 알 수 있거나 도움받을 수 있는 곳이 있을까요?
    • 깃헙은 소스코드를 저장해주는 곳이라고 생각하시면 됩니다. 거기에 올려진 싸이월드 크롤러를 받아서 실행하셔야 하는데, 이게 node.js 기반으로 작성된 코드여서 이걸 실행하려면 node.js를 먼저 설치하셔야 합니다.

      즉 정리하자면
      1. node.js 설치
      2. https://github.com/bab2min/cyworld-club-exporter 에서 clone or download를 눌러서 소스 코드를 다운로드
      3. 해당 소스코드가 들어있는 폴더로 들어가 cmd 실행후 README.md에 있는 실행방법대로 실행.

      위 순서대로 하시면 될듯합니다. 혹여나 설명이 부족한 부분있으면 구체적으로 질문해주시면 더 잘 대답해드릴 수 있을듯합니다.
      • YS
      • 2017.03.27 13:08
      node js 설치와 설정, 그리고 실행까지는 할 수 있게 되었습니다 감사합니다 X)

      그런데 아래와 같은 오류가 납니다. 혹시 async도 실행하기 위해 필요한 프로그램인가요?

      Error: Cannot find module 'async'
      at Function.Module._resolveFilename (module.js:469:15)
      at Function.Module._load (module.js:417:25)
      at Module.require (module.js:497:17)
      at require (internal/module.js:20:19)
      at Object.<anonymous> (C:\Users\Kim\Downloads\cyworld-club-exporter-master\cyworld-club-exporter-master\01_articleListGrep.js:4:13)
      at Module._compile (module.js:570:32)
      at Object.Module._extensions..js (module.js:579:10)
      at Module.load (module.js:487:32)
      at tryModuleLoad (module.js:446:12)
      at Function.Module._load (module.js:438:3)
    • node.js 와 더불어 npm도 설치되어 있어야합니다.

      소스 코드가 있는 폴더에서 cmd를 실행하시고
      npm install async
      라고 입력해서 라이브러리들을 설치해주셔야 해요.
      async를 포함하여 다음 라이브러리가 모두 설치되어있는지 확인하시길 바랍니다.
      http
      https
      querystring
      async
      crypto
      stream
      fs
      iconv-lite
      cheerio
      html-entities
      follow-redirects

      번거로우시겠지만 모두 설치해야지 작동할거에요...
      • YS
      • 2017.03.27 19:05
      글은 전부 다 백업하였습니다!! 아마 이것만 해결하면..
      전부 다 백업할 수 있을 것 같습니다..
      우우.. 도대체 이건 무슨 문제이죠ㅠㅠㅠ 번거롭게 해 죄송합니다. 제가 기프티콘이라도 하나 사겠습니다..ㅠㅠ

      get auth
      paring cookies
      parsing first page
      D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\core\parseGalleryList.js:24
      result.articles.push(parseInt(link[1]));
      ^

      TypeError: Cannot read property '1' of null
      at module.exports (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\core\parseGalleryList.js:24:43)
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\03_galleryListGrep.js:38:43
      at nextTask (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:5177:14)
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:5171:13
      at apply (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:21:25)
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:56:12
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:844:16
      at IncomingMessage.<anonymous> (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\core\galleryList.js:31:13)
      at emitNone (events.js:91:20)
      at IncomingMessage.emit (events.js:185:7)
    • 음 어떤 이유인지는 몰라도 갤러리 리스트를 못 가져오고 있는듯 합니다. 클럽 페이지를 실제로 확인해보지 않아 어떤 이유로 갤러리 리스트를 못 긁어오는지는 알수가 없네요.
      혹시 모르니 해당 계정으로 클럽 전체 사진 보기가 잘 되는지 확인해보시길 바랍니다. 저는 한번 코드 쪽에 이상이 없는지 확인해봐야겠군요.
      • YS
      • 2017.03.27 21:41
      제가 관리자인 클럽은 아니지만 사진글 읽기, 쓰기, 댓글 권한은 다 있어요!
      일일히 저장하는 건 가능하네요..! 그러니 제 계정상 문제는 아닌 것 같습니다 ㅠㅠ
    • 음 그러면 혹시 전체 사진 보기 페이지에서 게시물 몇개 링크 주소를 복사해서 보여주실수 있나요?
      • 2017.03.28 12:02
      비밀댓글입니다
    • 코드 수정해서 github에 다시 올렸어요. 한번 코드 다시 받아서 해보시겠어요?
      • YS
      • 2017.03.28 16:33
      갤러리 목록 불러오기는 성공했어요!! 그런데 갤러리 파일 받기에서 멈추네요..!! Github에 04번 파일이 두 개 있어서 혹시 제가 안되는걸 받았나 했지만 같은 오류 문구입니다..
      짧은 영어실력을 통해 오류 문구를 읽어보나 어디서 trim 할지 몰라하는 것 같아요

      get galleries list
      galleries done
      get auth
      paring cookies
      download article - -178620065
      parsing article - -178620065
      D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\core\parseGalleryView.js:14
      contents: $('.box_article_content').html().trim()
      ^

      TypeError: Cannot read property 'trim' of null
      at module.exports (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\core\parseGalleryView.js:14:51)
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\04_galleryViewGrep.js:93:59
      at nextTask (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:5177:14)
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:5171:13
      at apply (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:21:25)
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:56:12
      at D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\node_modules\async\dist\async.js:844:16
      at IncomingMessage.<anonymous> (D:\Route\cyworld-club-exporter-master\cyworld-club-exporter-master\core\galleryView.js:30:13)
      at emitNone (events.js:91:20)
      at IncomingMessage.emit (events.js:185:7)
    • 해당 부분은 갤러리의 본문을 읽어오는 부분인데 그걸 자꾸 실패하고있는데, 원인을 정확히 모르겠네요.
      원인 발견하게 되면 코드 고쳐서 다시 업로드해볼게요.
      • YS
      • 2017.03.29 12:48
      ㅠㅠ 번거롭게 해 죄송합니다
      그리고 정말정말 감사합니다!!!
    • 확인해봤는데요, 운영자 권한이 아니어서 발생하는 문제였습니다.
      소스 코드 core 폴더의 galleryView.js 파일이 있는데 이 파일을 수정해주시면 해당 클럽에 잘 작동하도록 쓸수 있을거 같아요.

      galleryView.js 파일 9번째 줄에 path: '/club/board/image ... 부분이 있는데 여기서 &board_no=2 부분이 있을겁니다. 여기서 숫자 2를 95로 고쳐주세요. 그럼 아마 잘 작동할겁니다.
      • YS
      • 2017.03.31 22:07
      정말 감사합니다!!!
      문제없이 잘 parsing하고 있습니다!!!!ㅠㅠㅠ
      정말 소소하지만 초콜렛이라도 보내드리고 싶은데 무슨 방법이 있을까요!!!!
    • 아닙니다. 괜찮습니다ㅎㅎ
    • hw
    • 2017.11.22 09:43
    안녕하세요. 자세한 설명 감사합니다. 따라해보고 있는데 혹시 동영상도 이전이 되나요?
    • 아뇨 동영상은 저 방법으로는 동영상을 받을 수 없습니다. 그건 좀 어려울것 같아요
    • HJ
    • 2018.01.21 19:22
    안녕하세요! 제가 지금 이걸 따라 열심히 해보고 있는데, 오류가 떠서요ㅠㅠ
    (혹시나 너무 기본적인거라 실례라면 미리 죄송해요ㅠㅠ)

    Error: Cannot find module 'C:\Users\Hye\node_modules\npm\bin\npm-cil.js'
    at Function.Module._resolveFilename (module.js:538:15)
    at Function.Module._load (module.js:468:25)
    at Function.Module.runMain (module.js:684:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
    module.js:540
    throw err;
    ^

    이렇게 뜹니다ㅠㅠ 뭘 잘못했을까요...
    • 해당 메세지만 가지고는 어떤 문제인지 알기가 어렵네요. 설치한 nodejs 버전을 알려주실수 있으신가요?
      • 2018.01.22 21:28
      비밀댓글입니다
    • LHG
    • 2018.05.27 02:52
    안녕하세요!
    작성해주신 글보고 싸이월드 클럽에 있던 글들은 크롤링을 잘 마쳤습니다!
    진심으로 감사드립니다!

    다음으로 네이버 카페에 글을 업로드만 하면 되는데,
    제가 php를 사용한 적이 없어 친절하게 작성해주신 것을 따라할 수가 없었습니다ㅠㅠ
    동아리 후배들이 네이버 카페로 꼭 이전했으면 좋겠다고 해서 해보려고 하는데
    혹 참고할 만한 것들이나 실행 방법에 대해 도움받을 수 있을까요?

    답변주시면 감사드리겠습니다!
    • 위에서 사용한 네이버 카페 API는 웹서버가 있어야 사용가능합니다. 즉 웹 페이지가 필요한데요 아마 네이버에서 이렇게 해놓은 이유는 네이버 카페 API의 목적이 다른 웹 페이지에서 네이버 카페와 관련된 작업을 수행할 수 있게하는 것이지, 게시글을 자동으로 올리는 매크로를 작성하는게 아니라서 그런듯합니다.

      즉 원칙상 사용가능한 웹 서버가 있어야 사용하실수 있어요. 없으시다면 php 무료 호스팅을 이용하시거나, 컴퓨터에 xampp를 설치해서 웹서버로 쓰시는 방법 등이 있겠습니다. php 7.0 이상의 서버 환경이 구축되셔야, 그 다음 진행과정도 도와드릴수 있을거 같네요. 감사합니다!
    • 지나가던 사람
    • 2018.09.10 14:19
    galleryViewGrep를 node 시킬때 board_no의 값이 개인마다 다른것같습니다. 전 14로 하니 파싱이 되네요. board_no값도 파싱하는 기능이 추가되었으면 좋겠네요ㅎㅎ