[Puppeteer] evaluate() 함수에 변수 전달하기[Puppeteer] evaluate() 함수에 변수 전달하기

Posted at 2019. 9. 30. 19:49 | Posted in Node.js/Puppeteer
반응형




참고 : https://code-examples.net/ko/q/2bf409f






■ evaluate( ) 함수에 변수 전달하기




이전 [Puppeteer] 퍼펫티어를 이용한 CRAWLING 작업 포스팅에서


티스토리 로그인을 하는 예제를 조금 수정하여 작업을 진행한다.


해당 포스팅에서는 자바스크립트의 코드를 사용 할 수 있게 해주는


evaluate( ) 함수가 존재하고,


해당 evaluate( ) 함수에 변수값을 사용하는데 있어 아래와 같이 사용 한 경우 에러가 발생하였다.



 puppeteer_evaluate.js

const puppeteer = require("puppeteer");

// 사용시 인위적인 딜레이를 주기위한 함수
function delay( timeout ) {
return new Promise(( resolve ) => {
setTimeout( resolve, timeout );
});
}

puppeteer.launch( { headless : true } ).then(async browser => {

const page = await browser.newPage();
await page.goto( "http://magic.wickedmiso.com/manage/", { waitUntil : "networkidle2" } );

let magicId = "tistoryId";      // 티스토리 아이디
let magicPw = "tistoryPw";    // 티스토리 패스워드

await page.evaluate(() => {
        document.getElementById( "loginId" ).value = magicId;
        document.getElementById( "loginPw" ).value = magicPw;
});

await delay(3000);


        // 로그인 SUBMIT 기능

const elementHandle = await page.waitFor( "input" );

await elementHandle.press( "Enter" );

await delay(5000);

        /* 로그인이후 방문 기록 데이터를 콘솔에 띄워본다. */

const emToDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(1) > dd" );

        const txtToDay = await page.evaluate( emToDay => emToDay.textContent, emToDay );

        console.log("-. 오늘 방문자 수", txtToDay);

    

const emYesterDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(2) > dd" );

        const txtYesterDay = await page.evaluate( emYesterDay => emYesterDay.textContent, emYesterDay );

        console.log("-. 어제 방문자 수", txtYesterDay);


const emCumulativ = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(3) > dd" );

        const txtCumulativ = await page.evaluateemCumulativ => emCumulativ.textContentemCumulativ );

        console.log("-. 누적 방문자 수", txtCumulativ);


});



# 에러 출력





evaluate( ) 함수 이기 때문에 해당 함수내에 값을 전달할려면


다른 함수들과 마찬가지로 전달할 값을 오버라이딩 해서 매개변수값을 전달해 주어야 한다.



 puppeteer_evaluate.js

const puppeteer = require("puppeteer");

// 사용시 인위적인 딜레이를 주기위한 함수
function delay( timeout ) {
return new Promise(( resolve ) => {
setTimeout( resolve, timeout );
});
}

puppeteer.launch( { headless : false } ).then(async browser => {

const page = await browser.newPage();
await page.goto( "http://magic.wickedmiso.com/manage/", { waitUntil : "networkidle2" } );

let magicId = "tistoryId";      // 티스토리 아이디
let magicPw = "tistoryPw";    // 티스토리 패스워드
       

        // 함수내에 매개변수를 지정해준다.

     await page.evaluate(( { magicId, magicPw } ) => {
        document.getElementById( "loginId" ).value = magicId;
        document.getElementById( "loginPw" ).value = magicPw;
// document.getElementsByClassName( "btn_login" ).disabled = false;
}, { magicId, magicPw } );


await delay(3000);


        // 로그인 SUBMIT 기능

const elementHandle = await page.waitFor( "input" );

await elementHandle.press( "Enter" );

await delay(5000);

        /* 로그인이후 방문 기록 데이터를 콘솔에 띄워본다. */

const emToDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(1) > dd" );

        const txtToDay = await page.evaluate( emToDay => emToDay.textContent, emToDay );

        console.log("-. 오늘 방문자 수", txtToDay);

    

const emYesterDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(2) > dd" );

        const txtYesterDay = await page.evaluate( emYesterDay => emYesterDay.textContent, emYesterDay );

        console.log("-. 어제 방문자 수", txtYesterDay);


const emCumulativ = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(3) > dd" );

        const txtCumulativ = await page.evaluateemCumulativ => emCumulativ.textContentemCumulativ );

        console.log("-. 누적 방문자 수", txtCumulativ);


});



위 코드를 실행시켜보면.


이제 위와 같은 에러가 나타나지 않는것을 확인 할 수 있다.


출력결과는 아래와 같다.




# 실행 결과



다시한번 evaluate( )는 함수임을 기억하자.










# 참고




티스토리의 아이디, 패스워드 입력창의 경우


키보드 입력으로 판단되지 않았기 때문에.


로그인 버튼이 활성화 되지 않은 것을 확인 되었다.


이때는 Puppeteer의 키보드 입력과 같은 이벤트를 발생시켜서 처리할 수 있게끔 작업을 진행해 주어야 한다.






반응형
//

[Puppeteer] Cheerio 모듈을 활용한 데이터 스크랩핑[Puppeteer] Cheerio 모듈을 활용한 데이터 스크랩핑

Posted at 2019. 6. 20. 21:10 | Posted in Node.js/Puppeteer
반응형




■ 퍼펫티어를 이용한 유튜브 채널 스크랩핑




유튜브 API가 제대로 동작하지 않게 되었다.


cheerio-httpcli 모듈로 YouTube 페이지의 데이터를 스크래핑 하려 해보았지만.


유튜브의 경우 cheerio-httpcli를 통한 단순한 데이터 스크랩핑을 해보니


많은 수의 json형태의 데이터를 가져오기에


포기하던 차에 puppeteer를 활용해 보기로 했고


결과는 어느정도 만족할 수 있는 수준이었다.






위와 같이 유튜브 특정 채널의 업로드 영상을 가져와 보려고 한다.




# 소스코드

 puppeteer_ra_om_musiq.js

const puppeteer = require( "puppeteer" );

const cheerio = require( "cheerio" );


puppeteer.launch( { headless : true } ).then(async browser => {


const page = await browser.newPage();

await page.goto( "https://www.youtube.com/user/RaOmMusiq/videos/", { waitUntil : "networkidle2" } );

        // YouTube 페이지의 <ytd-grid-renderer> 태그 안의 내용을 가져온다.

const html = await page.$eval( "ytd-grid-renderer", e => e.outerHTML );


        // console.log(html);


const datacheerio.loadhtml );

data( "a.ytd-grid-video-renderer" ).each( function( key, val ) {


               // substring을 사용하여 불필요한 값을 잘라낸다. 

var videoId = data( val ).attr( "href" ).substring( 9, 20 );

var videoTitle = data( val ).text();

console.log( "VIDEO ID = ", videoId );

console.log( "VIDEO TITLE = ", videoTitle );

});

});





# 출력결과




위와같이 필요로 하는 YouTube 영상의 아이디 값 타이틀 제목을 얻어오는 모습을 확인 할 수 있다.






반응형
//

[Node.js] Serial Port를 이용한 Arduino 이벤트 실행[Node.js] Serial Port를 이용한 Arduino 이벤트 실행

Posted at 2019. 6. 13. 18:54 | Posted in Node.js
반응형




참고 : https://kocoafab.cc/tutorial/view/501

참고 : https://kocoafab.cc/tutorial/view/504






■ 직렬 포트(Serial Port)란?




직렬포트란 한번에 한 비트씩 수신하는 방식의 포트를 말한다.

질렬 포트는 PC에서 직렬 방식으로 주변 장치와 연결할때 사용하는 포트이다.

마우스나 키보드, 모뎀등이 시리얼 포트로 연결해서 사용한다.

직렬 포트는 구조가 단순하여 사용하기 편리한 장점이 있다.

단점으로는 한 선로에 1비트씩 보내기 때문에 전송속도가 낮고 1개의 포트로 주변 기기 1개만 연결된다는 단점이 있다.









■ Node.js 에서 아두이노 연결하기



먼저 테스트에 앞서 아두이노 장비를 준비하고 컴퓨터에 연결하자.




컴퓨터 장치관리자에 들어가면 위와같이 아두이노 장비가 추가된 것을 확인 할 수 있다.






# 모듈설치

 npm install serialport




# 소스코드

 serialport_check.js

const serialPort = require("serialport");


serialPort.list(function(err, ports) {

ports.forEach(function(port) {


console.log("###################################################");

console.log("comName : ", port.comName);

console.log("---------------------------------------------------");

console.log("pnpId : ", port.pnpId);

console.log("---------------------------------------------------");

console.log("manufacturer : ", port.manufacturer);

console.log("###################################################");

});

});




# 출력결과

C:\> node serialport_check.js



그럼 위와같은 화면이 나온다면 윈도우즈에서 node.js 의 설치가 마무리 되었다.










■ 아두이노에 입력값 전달하여, 자동 키보드 입력 하기




# 아두이노 소스코드

 physical_key_input.ino

#include <Keyboard.h>


void setup() {

  Serial.begin(9600);

}


void loop() {

   

if(Serial.available() > 0) {

   

Keyboard.begin();

/* 받을 문자열의 길이를 100으로 지정한다 */

char temp[100];

/* 문자열을 잘라 넣는다. */

byte leng = Serial.readBytes(temp, 20);

 

digitalWrite(13, HIGH);      /* 받은 문자값을 출력할 동안 불을 켜둔다. */

delay(1000);                   /* 값이 입력되기 전까지 딜레이를 10초 준다. */


/* 자른 문자열의 갯수만큼 반복문을돌려 키보드로 입력 신호를 전달한다. */

for(int num = 0; num < leng; num++) {

Keyboard.print(temp[num]);

delay(200);

}

           

digitalWrite(13, LOW);      /* 문자값이 출력도리 동안 켜둔 불을 끈다 */

Keyboard.end();

Serial.end();

}

}




# 노드.js 소스코드

 serialport_arduino.js

const SerialPort = require("serialport");

const sp = new SerialPort("COM9", { baudRate:9600, autoOpen:false });


function timeDelay(timeout) {

return new Promise((resolve) => {

setTimeout(resolve, timeout);

});

}


sp.open(function() {

timeDelay(5000);

sp.on("error", function(error) {

console.log("Error : ", error.message);

});


sp.write("Hello SAAK", function(error) {

if(error) {

return console.log("Error on write : ", error.message);

} else {

console.log("메세지가 정상적으로 입력되었습니다.");

}

});

});




# 출력결과











반응형
//

[Node.js] Google Spread Sheet 수정 및 삭제하기[Node.js] Google Spread Sheet 수정 및 삭제하기

Posted at 2019. 6. 11. 19:27 | Posted in Node.js/Google Spread Sheet
반응형





※ 해당 포스팅 google-spreadsheet 2.0.7 버전을 기준으로 작성되었습니다.

    google-spreadsheet 3 버전 이후버전부터는 실행에 앞서 에러가 발생합니다.

    추후 수정 예정이오니 해당 포스팅을 참고하시는 분은 이점을 꼭 기억해 주시기 바랍니다.

    ( google-spreadsheet 2.0.7 버전의 경우 2020-05-15일 기준으로 사용에 문제는 없습니다. )





■ 구글 스프레드 시트의 데이터 수정하기




그동안의 데이터에서 내용을 읽어오거나, 입력하는것을 해보았다면


이제 마무리 단계로 수정을 진행해 보려고 한다.


아래와 같이 스프레드 시트를 만들고 그 데이터를 변경해 보자.




# 스프레드 시트





위 스프레드 시트에서는 D2, D4의 영역에 DASONI 라고 적힌 부분이 있다.


이 부분을 한글 DASONI로 변경하려 한다.



# 소스 코드

 

const googleSpreadsheet = require("google-spreadsheet");

const creds = require("./서비스 계정 키.json");

const doc = new googleSpreadsheet("구글 스프레드 시트 ID");


doc.useServiceAccountAuth(creds, function(err) {

doc.getCells(

  1

, {

  "max-row" : 6 // Cell의 최대 열(row)의 갯수( 필수 )

, "max-col" : 5      // Cell의 최대 행(column)의 갯수( 필수 )

, "return-empty" : true

}

, function(err, cells) {

                        // 해당 셀(Cell)을 지정한뒤, 변경사항을 수정하고 저장한다.

                        // 셀(Cell)을 수정하면 바로 저장을 해주어야 한다.


cells[8].value = "다소니";          // 해당 셀(Cell)의 값을 변경한다.

cells[8].save();                        // 해당 셀(Cell)의 변경사항을 저장한다.

cells[18].value = "다소니";         // 해당 셀(Cell)의 값을 변경한다.

cells[18].save();                       // 해당 셀(Cell)의 변경사항을 저장한다.

}

);

});




수정할 clees[8], clees[18]은 전체 셀(Cell)에서 몇번째 셀인지를 나타낸다.


꼭 값을 넣고 save( )를 해주어야 한다.



# 출력 결과




위와같이 영문명 DASONI에서 한글명 다소니로 변경된 것을 확인 할 수 있다.







■ 데이터 한번에 수정하기




이번에는 수정할 영역을 찾아서 검색하는 것을 만들려고 한다.




# 스프레드 시트





# 소스 코드

 

const googleSpreadsheet = require("google-spreadsheet");

const creds = require("./서비스 계정 키.json");

const doc = new googleSpreadsheet("구글 스프레드 시트 ID");


doc.useServiceAccountAuth(creds, function(err) {


doc.getCells(

  1

, {

  "max-row" : 8

, "max-col" : 4

, "return-empty" : true


}

, function(err, cells) {

let black = new Array("김재경", "고우리", "오승아", "조현영");

for(var num = 0; cells.length > num; num++) {

if(black.indexOf(cells[num].value) >= 0) {

var unit = num + 3;      // 해당 셀에서 3칸 옆의 셀을 선택

cells[unit].value = "★";

cells[unit].save();

}

}

}

);

});




# 출력 결과









■ 구글 스프레드 시트의 데이터 삭제하기





# 스프레드 시




# 소스 코

 

const googleSpreadsheet = require("google-spreadsheet");

const creds = require("./서비스 계정 키.json");

const doc = new googleSpreadsheet("구글 스프레드 시트 ID");


doc.useServiceAccountAuth(creds, function(err) {


doc.getCells(

  1

, {

  "min-row" : 2     // min-row를 2로 지정하여 필터 키값부분은 제외한 셀값을 가져온다.

, "max-row" : 11

, "max-col" : 1

, "return-empty" : true


}

, function(err, cells) {

let computer = new Array("APPLE", "LG", "HUAWEI", "HEWLETT PACKARD");

for(var num = 0; cells.length > num; num++) {

if(computer.indexOf(cells[num].value) >= 0) {

// console.log(cells[num].value);

cells[num].del();

}

}

}

);

});





# 출력 결과










※ 참고 - getRow( )를 이용하여 수정 및 삭제를 하려 한경우




필자는 아래 코드처럼 getCell이 아닌 getRow를 이용한 방법이 되지 않을까 싶어 테스트 해보았지만


결과는 에러만 날뿐이었다.


아무래도 getRow를 이용한 방법은 되지 않는것 같으니 참고 바란다.



 

const googleSpreadsheet = require("google-spreadsheet");

const creds = require("./서비스 계정 키.json");

const doc = new googleSpreadsheet("구글 스프레드 시트 ID");


doc.useServiceAccountAuth(creds, function(err) {

doc.getRows(

  1

, {

  "offset" : 1

, "limit" : 7

}

, function(err, rows) {

// console.log(rows);

let black = new Array("김재경", "고우리", "오승아", "조현영");

for(var num = 0; rows.length > num; num++) {

if(black.indexOf(rows[num].이름) >= 0) {

console.log(rows[num].이름);

rows[num].블랙 = "★";

rows[num].블랙.save();

}

}

}

);

});










반응형
//