pupperteer를 이용한 화면 캡처 기능 개발

이번에 개발하는 기능중에 화면을 캡처해서 다운로드를 제공해야 하는 기능이 있다.

처음 시도한 방법은 html2canvas을 이용한 방법 이었는데... 실패 했다.

화면에 보여주는 부분은 잘 캡쳐가 되지만, 스크롤에 숨겨진 부분이 캡쳐가 되지 않았다.

하루를 날리고, 다음으로 시도한 방법은 pupperteer를 이용해서 요청이 오면 내부에서 새로운 페이지를 띄우고 해당 페이지를 로딩해서 캡쳐 하는 방식이다.

만든 코드는 다음과 같다.

router.post('/capture', async (req, res, next) => {
  const file_name = `${shortid.generate()}.png`;
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.setViewport({ width: 1366, height: 768, });
  await page.goto(CAPTURE_URL+Buffer.from(JSON.stringify(req.body)).toString('base64'), {waitUntil: 'domcontentloaded'});
  await page.waitFor(1000);
  await page.waitForSelector('#endarea');
  await page.screenshot({fullPage: true, path: `public/images/${file_name}`});
  await browser.close();
  res.json({image_url:`/images/${file_name}`})
});

요청이 들어오면 해당 페이지로 넘어온 파라메터를 다시 전달해서 화면을 캡쳐 한다.

await page.screenshot({fullPage: true, path: public/images/${file_name}});이 부분에 보이는 부분을 전체 화면으로 캡쳐를 해서 저장을 하는 기능을 수행한다.

저장된 이미지를 웹에서 다운로드를 하는 코드는 다음과 같다.

function forceDownload(url, fileName){
        var xhr = new XMLHttpRequest();
        xhr.open("GET", url, true);
        xhr.responseType = "blob";
        xhr.onload = function(){
            var urlCreator = window.URL || window.webkitURL;
            var imageUrl = urlCreator.createObjectURL(this.response);
            var tag = document.createElement('a');
            tag.href = imageUrl;
            tag.download = fileName;
            document.body.appendChild(tag);
            tag.click();
            document.body.removeChild(tag);
        }
        xhr.send();
    }

이와 같이 실행하면 fileName으로 다운로드가 진행된다.

인터넷과 함께면 난 못하는게 없다.

참고자료

Posted by lahuman

댓글을 달아 주세요

MongoDB aggregate 사용

다음과 같은 형식의 여러 ROW의 데이터를 하나의 데이터로 표현 하고 싶었다.

# DATA
{
    "_id" : ObjectId("5c864b1e1cd4038eed5b5633"),
    "link_tag" : [ 
        "#핫앤쿨", 
        "#마스크팩", 
        "#홈케어", 
        "#리뉴메디", 
        "#젊줌마", 
        "#예뻐지는시간"
    ],
    "name" : "홈케어",
    "text" : "젊어지는시간\n. .\n\n#핫앤쿨 #마스크팩 #홈케어\n#리뉴메디 #젊줌마 #예뻐지는시간",
    "owner" : "10961953345",
    "shortcode" : "Bu3eX2iHIFG",
    "display_url" : "https://scontent-icn1-1.cdninstagram.com/vp/c330b55401b96aca266acca202386b42/5D08D97D/t51.2885-15/e35/54446467_181108306201409_5180562059450456961_n.jpg?_nc_ht=scontent-icn1-1.cdninstagram.com",
    "is_video" : false,
    "accessibility_caption" : "Image may contain: 1 person",
    "writed_date" : ISODate("2019-03-11T11:44:00.000Z"),
    "hash" : "086e2b6a65b823c887ef1afc19734f67",
    "createdAt" : ISODate("2019-03-11T11:48:46.276Z"),
    "updatedAt" : ISODate("2019-03-11T12:22:43.532Z"),
    "__v" : 3
}

/* 2 */
{
    "_id" : ObjectId("5c864b1e1cd4038eed5b5632"),
    "link_tag" : [ 
        "#토니슈어", 
        "#다낭까지와서", 
        "#이러고있다", 
        "#간절한걸어떡함", 
        "#플라즈마", 
        "#갈바닉", 
        "#너네둘만믿는다", 
        "#동안피부", 
        "#얼굴마사지기", 
        "#피부개선", 
        "#탄력", 
        "#피부미용기기", 
        "#미용", 
        "#홈케어", 
        "#피부미인", 
        "#데일리", 
        "#뷰티", 
        "#살균", 
        "#셀프", 
        "#피부질환", 
        "#플라즈마", 
        "#트러블케어", 
        "#피부", 
        "#피부과", 
        "#선물", 
        "#물광피부", 
        "#보습", 
        "#안티에이징", 
        "#led마스크", 
        "#미백", 
        "#콜라겐"
    ],
    "name" : "홈케어",
    "text" : "토니느님~ 제 피부를 10년전으로 돌려주세요\n\n제발요....♡ .\n\n#토니슈어 #다낭까지와서 #이러고있다 #간절한걸어떡함 #플라즈마 #갈바닉 #너네둘만믿는다 #동안피부 가즈앙~ \n#얼굴마사지기 #피부개선 #탄력 #피부미용기기 #미용 #홈케어 #피부미인 #데일리 #뷰티 #살균 #셀프 #피부질환 #플라즈마 #트러블케어 #피부 #피부과 #선물 #물광피부 #보습 #안티에이징 #led마스크 #미백 #콜라겐",
    "owner" : "10698447319",
    "shortcode" : "Bu3e2n_jrrE",
    "display_url" : "https://scontent-icn1-1.cdninstagram.com/vp/97d840dbdea55753d2a976302f90002b/5D065CE9/t51.2885-15/fr/e15/s1080x1080/53176269_319394038719034_3474616797099883761_n.jpg?_nc_ht=scontent-icn1-1.cdninstagram.com",
    "is_video" : false,
    "accessibility_caption" : "Image may contain: outdoor and water",
    "writed_date" : ISODate("2019-03-11T11:48:12.000Z"),
    "hash" : "c9a418d8295391c1c83553f0316d1127",
    "createdAt" : ISODate("2019-03-11T11:48:46.266Z"),
    "updatedAt" : ISODate("2019-03-11T12:22:43.527Z"),
    "__v" : 3
}

원하는 결과 데이터

[
    { "tag" : "#미백", "count" : 3},
    { "tag" : "#물광", "count" : 4},
    { "tag" : "#보습", "count" : 10},
    ...
]

구글을 검색하니 $push명령어를 찾았다.

내가 처리한 Query는 다음과 같다.

db.hashtag.aggregate([
    { $match: { $and: [{ name: "테그명" }, { "createdAt": { $gte: (new Date()), $lt: (new Date()) } }] } },
    {$unwind: "$link_tag"},
    {$group:{_id:null, clrs: {$push: {name: "$link_tag", count:1}}}},
    {$unwind: "$clrs"},
    {$group:{_id:"$clrs.name", size: {$sum:"$clrs.count"}}},
    { $sort: { size:-1} },
    { $limit : 5 },
    {$project: {_id:1, size:1 }
  ]);

이렇게 처리 하면 다음과 같은 결과를 받을 수 있다.

[
    { _id:"#물광", size:15 },
    { _id:"#홈케어", size:13 }
    { _id:"#대일리", size:12 }
]

다음은 매 시간별로 수집된 데이터를 counting 하는 query 이다.
내가 원하는 결과는 다음과 같다.

[
    {"date": "2018-03-14 10", "count":30},
    {"date": "2018-03-14 11", "count":20},
    {"date": "2018-03-14 12", "count":33},
    {"date": "2018-03-14 13", "count":34}
]

다행이 이번 QUERY는 한방에 처리 하였다.

db.hashtag.aggregate([
    { $match: { $and: [{ name: "태그명" }, { "createdAt": { $gte: (new Date()), $lt: (new Date()) } }] } },
    {
      $group:
      {
        _id:
        {
          hour: { $hour: "$createdAt" },
          day: { $dayOfMonth: "$createdAt" },
          month: { $month: "$createdAt" },
          year: { $year: "$createdAt" }
        },
        value: { $sum: 1 },
        date: { $first: "$createdAt" },
        sortDate: { $first: "$createdAt" }
      }
    },
    {
      $project:
      {
        date:
        {
          $dateToString: { format: "%Y-%m-%d %H", date: "$date" }
        },
        sortDate: 1,
        value: 1,
        _id: 0
      }
    },
    { $sort: { sortDate: 1 }}
  ])

분명히 많은 기능을 Mongodb에서 제공해주고 있는데, 잘 쓰지 못하고 있다...

노력하자.

참고 자료

Posted by lahuman

댓글을 달아 주세요

puppeteer를 설치하고 구동하기

설치는 아주 간단하다. npm 을 이용해서 설치 하면 바로 되는데, 문제는 설치후 기동하면 오류가 난다.

# 설치
npm install --save puppeteer

# 실행
node app.js

# error 발생

에러 메시지에서는 puppeteer troubleshooting를 보라고 하지만, 내게 도움되는 내역이 없었다.

구글의 도움을 받아 찾은 puppeteer not working on Ubuntu 16.04 but works on 14.04에서 다음 라이브러리를 설치하라는 메시지를 확인하였다.

sudo apt-get install libpangocairo-1.0-0 libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxi6 libxtst6 libnss3 libcups2 libxss1 libxrandr2 libgconf2-4 libasound2 libatk1.0-0 libgtk-3-0

설치를 하고 나서 실행하면 문제 없이 잘된다.

그러하다~

참고 주소

Posted by lahuman

댓글을 달아 주세요

cert, key 파일을 pem 파일로 변환 하기

nginx에서 사용하던 인증서를 nodejs에서 바로 사용을 하기 위해 pem 파일 형식으로 변경 해야하는 일이 생겨서 검색을 해보았다.
파일 형석의 변환은 다음과 같이 쉽게 할 수 있다.

# key 변경
openssl rsa -in server.key -text > private.pem
# crt 변경
openssl x509 -inform PEM -in server.crt > public.pem

추가 팁] nodejs 에서 https 설정

nodejs에서 https 사용을 위해서는 https 모듈을 추가로 설치 해야 한다.

이후 소스내에 다음과 같이 인증서를 options을 추가 하면 된다.

const https = require('https');
const fs = require('fs');
const options = {
  ca: fs.readFileSync('인증서경로/ca-bundle.pem')
  key: fs.readFileSync('인증서경로/domain_xxxxx.key.pem')
  cert: fs.readFileSync('인증서경로/domain_xxxxx.crt.pem')
};
https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(443);

참 쉽죠?

참고 주소

Posted by lahuman

댓글을 달아 주세요

MongoDB backup & restore

간단하게 몽고 디비 백업과 복구를 해보겠다.

먼저 백업 명령은 다음과 같다

# 결과로 디렉터리가 생성 된다.
# 특정 collection 명이나 DB 명을 Backup 할 수 있다.
$> mongodump --collection words --db TEST --out ./

다음은 복원 하는 방법이다.

# 특정 컬렉션만 복원 할 수 있으며 --drop  옵션을 추가 하면 삭제하고 복원 한다.
$> mongorestore --host 172.30.10.1 --port 27017 --db TEST --collection words --username tester --password 'password'  ./TEST/words.bson --drop

가끔씩 쓸일이 생긴다.

Posted by lahuman
TAG mongodb

댓글을 달아 주세요

AWS LAMBDA 를 개발시 알면 좋은 팁

  1. Lambda를 API Gateway를 통해서 호출 하도록 설정 할때 매핑 템플릿 을 사용하면 IP 등의 정보를 얻을 수 있다.

  2. Lambda에서 RDS에 접근하기 위해서는 VPC를 설정해야 한다.
  3. VPC가 설정된 Lambda는 외부 인터넷에 접근 할 수 없다.
  4. VPC가 설정된 Lambda는 내부 private IP만 접근 할 수 있다.

다시 사용할 일이 올지는 모르겠지만, 재미있었다.

신기술은 늘 어렵다. 근데 써보고 나면 별거 없다.

참고 자료

Posted by lahuman

댓글을 달아 주세요

얼마전 Node에서 비동기 처리를 순서대로 처리해야 하는 일이 있었다.

구글을 검색하다 async.waterfall in a For Loop in Node.js을 찾았다.

var async = require("async")
var users = []; // Initialize user array or get it from DB

async.forEachLimit(users, 1, function(user, userCallback){

    async.waterfall([
        function(callback) {
            callback(null, 'one', 'two');
        },
        function(arg1, arg2, callback) {
            // arg1 now equals 'one' and arg2 now equals 'two'
            callback(null, 'three');
        },
        function(arg1, callback) {
            // arg1 now equals 'three'
            callback(null, 'done');
        }
    ], function (err, result) {
        // result now equals 'done'
        console.log('done')
        userCallback();
    });


}, function(err){
    console.log("User For Loop Completed");
});

asyncasync, await인줄 알았는데, 비동기 처리에 사용하는 모듈 이었다.

70 여 가지 모듈을 지원하며, 예제도 잘 나와 있다.

이중 제어 관련하여 다음의 매소드 등이 제공된다.

  1. XXXLimit : 한번에 처리 하는 Worker 갯수 지정
  2. XXXSeries : 한개씩 처리
  3. waterfall : 여러 비동기 처리를 순차적으로 처리
  4. parallel : 콜렉션을 병렬 처리
  5. apply : 인수 처리
  6. map : 새로운 컬렉션을 생성

이 외에도 많은 기능이 제공된다.

Async provides around 70 functions that include the usual 'functional' suspects (map, reduce, filter, each…) as well as some common patterns for asynchronous control flow (parallel, series, waterfall…). All these functions assume you follow the Node.js convention of providing a single callback as the last argument of your asynchronous function -- a callback which expects an Error as its first argument -- and calling the callback once.

비동기 처리를 할때 사용하면 상당히 유용하다.

참고 자료

Posted by lahuman
TAG async, nodejs

댓글을 달아 주세요