728x90
반응형

이전 포스팅에서 웹 크롤링 인피니트 스크롤링무엇인가 알아보았으며,

인피니트 스크롤링이 적용된 페이지에 대해서

이미지를 다운하고 파일로 만드는 방법을 알아보았습니다

 

인스타그램, 페이스북 여러 웹사이트에서 인피니트 스크롤링을 적용하고 있으니

꼭 알아두어야 할 것 같습니다

 

그럼 더 자세히 알고 싶으시면 아래의 링크를 확인해주세요

 

 

2022.08.27 - [IT_Web/Nodejs] - 웹 크롤링 인피니트 스크롤링 조작하여 이미지 다운로드하고 파일 만들기

 

웹 크롤링 인피니트 스크롤링 조작하여 이미지 다운받고 파일만들기

이전 포스팅에서 웹 크롤링을 하여 스크린샷을 찍는 방법에 대해 풀 스크린과 어느 특정 영역, 또는 화면 전체 이렇게 3가지 방법으로 스크린샷 찍는 방법을 알아보았습니다 웹크롤링할 때 화면

tantangerine.tistory.com

 

 

본론에 앞서 웹 크롤링을 하실 때는

본인이 책임져야 한다는 것을 잊지 마세요

합법적이지 못한 방법은 언제나 

꼭 책임이 따른다는 것을 명심하시길 바랍니다

 

그러니 회사 업무의 효율성을 위해서만 사용하시고

올바르게 사용하시길 바랍니다

 

그리고

웹 크롤링이 벌써 7번째(?) 포스팅인 것 같습니다

그래서 환경설정과 여러 라이브러리 설치 방법은 생략하고 진행하겠습니다

보고 싶으신 분이 계시다면 이전 포스팅에서 확인하시길 바랍니다

메뉴에 Node 쪽을 확인해보시면 관련 포스팅을 찾을 수 있습니다 

 

그럼 이제 본론으로 넘어가 보겠습니다

 

웹 크롤링 로그인, 로그아웃 및 waitForResponse(응답 대기) 알아보기 

 

아래의 코드를 보시면

약간 코드를 수정해서 값을 할당하는 함수와 웹 크롤링하는 함수를 불리하여

함수의 재사용을 높일 수 있게 변경하였습니다

 

그럼 아래에서 더 상세 한 설명을 이어나가겠습니다

기초적인 브라우저 환경설정 등은 주석으로 설명을 대신하겠습니다

로그인 로그아웃에 초점을 맞추겠습니다

 

const puppeteer = require('puppeteer');
const dotenv = require('dotenv'); // npm i dotenv
//const userAgent = require('new-user-agent')
dotenv.config();

const setCrawler = async () => {
  const browser = await puppeteer.launch({ // 웹 사이트의 브라우저를 띄우는 함수이다
    headless: false, // 웹크롤링할 때 사이트 노출 여부를 결정하는 값(운영을 하게될때 노출은 필요없다)
    args:['--window-size=1920,1080'] // 브라우저의 size를 설정한다
  });
  const page = await browser.newPage(); // 브라우저를 노출하고 새 탭보기로 페이지를 오픈한다
  await page.setViewport({ // 오픈할 때 가로 세로 길이를 설정한다
    width: 1080,
    height:1080,
  })

  //userAgent의 값을 랜덤으로 셋팅해주는 함수입니다 하지만 
  // 하지만 버전이 너무 낮아 현제 웹페이지에는 맞는게 없네요
  //await page.setUserAgent(userAgent.test());
  //console.log('userAgent', userAgent.test());

  const inputValue = async (selector, value) => {
    await page.evaluate((selector, value) => {
      document.querySelector(selector).value = value
    }, selector, value)
    await setTime(selector)
  }
  const buttonClick = async (selector, nextSelector, type) => {
    await page.evaluate((selector) => {
      document.querySelector(selector).click();
    }, selector)
    if(type === 'login'){
      const res = await page.waitForResponse(res => {
        return res.url().includes('graphql')
      })
      const result = await res.json()
      console.log('login', result);
      if(await result.extensions.is_final){
        await setTime(type)
        await page.keyboard.press('Escape')
      }
    } else if(type === 'logOut'){
      await page.waitForNavigation()
    } else {
      if(nextSelector){
        // waitForRequest(요청 대기), waitForResponse(응답 대기)
        await page.waitForSelector(nextSelector)
      }
      await setTime(selector)
    }
  }
  const setTime = async (selector = 'normal') => {
    const setTime = await page.evaluate(async() => {
      const timeList = await [3975, 4547, 5231, 6397, 7894, 3394, 4206, 5147, 6932, 7430, 3561, 4896, 5877, 6407, 7133];
      const randomTime = await timeList[Math.floor(Math.random() * timeList.length)]
      await new Promise(r => setTimeout(r, randomTime))
      return randomTime
    })
    console.log(`waitTime[${selector}]: `, setTime)
    return setTime
  } 
  return { buttonClick, inputValue, setTime, page: page, browser: browser }
}

// keyboard.press(); 인자값 목록 https://github.com/puppeteer/puppeteer/blob/v1.12.2/lib/USKeyboardLayout.js
// $('.i8zpp7h3')
// $('.i1n1lj7b.mmwt03ec')
// 

const crawler = async () => {
  try {
    const { buttonClick, inputValue, setTime, page, browser } = await setCrawler();
    const url = 'https://facebook.com';
    await page.goto(url);

    const id = await process.env.EMAILL;
    const password = await process.env.PASSWORD;
    
    // 로그인
    await inputValue('#email', id);
    await inputValue('#pass', password);
    await buttonClick('[name="login"]', '', 'login');
   

    // 로그아웃
    await buttonClick('.i8zpp7h3', '.i1n1lj7b.mmwt03ec');
    await buttonClick('.i1n1lj7b.mmwt03ec > div:last-child > div', '', 'logOut')
    // await page.close();
    // await browser.close();
  } catch (e) {
    console.log(e);
  }
}

crawler()

 


 

로그인 input 태그 찾기 및 로그인 하기

 

아래의 이미지를 보시면

<input> 태그 id, name속성 값이 email로 지정되어있습니다

 

 

웹크롤링-태그찾기
웹크롤링 태그 찾기

 

 

위에서 찾은 태그 이름인 #email, #pass를 함수 호출의 매개변수 첫 번째 인자 값으로 설정합니다

그리고 두 번째에는 로그인할 id와 password를 지정합니다

 

다음으로 선언된 inputValue 함수에 page.evaluate()를 호출하여 document.querySelector()로 태그에 접근합니다

이때 첫 번째 매개변수인 selector 인자 값을  document.querySelector(selector) 할당하여 호출합니다

그럼 태그를 가져오게 되고 그때 .value값을 새로 지정하거나 click()를 호출하여 버튼을 클릭하여

로그인을 시도하게 됩니다

 

 

여기서 잠깐!!

page.evalueate() 함수 안에서 document객체에 접근할 수 있다는 것 기억하시죠??

그리고 evaluate()에서 두 번째 매개변수부터 값을 할당해서 호출하면 

evaluate() 내부에서 사용이 가능하다는 것을 잊지 마세요

 

 

 

 

 

 

웹크롤링-로그인
웹크롤링 로그인 함수

 

 

evaluate() 함수에서 document객체를 활용해서 id, password를 할당하는 것과

puppeteer를 활용해서 하는 방법 두 가지가 있습니다

 

아래의 코드에서 page.type(), page.hover(), page.click() 3개의 함수를 확인할 수 있습니다

간단해 보이는 이 함수들은 그 사용법과 활용법이 다르며

언제 이 함수들이 버전업으로 활용방법이 변경될지 모르는 일입니다

그러니 대도록이면 함수를 선언하여 위와 같이 호출하는 방식으로 사용하시길 바랍니다

 

 

const crawler = async () => {
  try {
    const { buttonClick, inputValue, setTime, page, browser } = await setCrawler();
    await page.goto('https://facebook.com');

    const id = await process.env.EMAILL;
    const password = await process.env.PASSWORD;

    await page.type('#email', id);
    //await inputValue('#email', id);

    await page.type('#pass', password);
    //await inputValue('#pass', password);

    await page.hover('[name="login"]'); // 마우스를 선택자에 올리기
    await Promise.all([
      page.click('[name="login"]'),
      page.waitForNavigation(),
    ]);
    //await buttonClick('[name="login"]');
    await setTime()
    await page.keyboard.press('Escape');
        console.log('Escape')
    // await page.close();
    // await browser.close();
  } catch (e) {
    console.log(e);
  }
}

crawler()

 


 

waitForResponse 응답 대기 활용방법

 

 

로그인을 성공하면 아래와 같이 권한 페이지 설정을 하기 위해 dim처리가 되어 있습니다

dim처리를 없애보도록 하겠습니다

 

 

 

 

로그인을 클릭하게 되면 서버 호출을 시도하게 됩니다

그래서 page.waitForResponse()를 호출해서

웹 페이지에서 서버를 호출한 res.url()과 우리가 알고 있는 url주소를 비교하여

같으면 true값을 return 합니다

그리고 res값을 json()를 사용하여 Object형태로 받아올 수 있으며,

아래와 같이 접근이 가능합니다

 

 

 

웹크롤링 waitForResponse 함수 결과값

 

 

 

 

result.extensions.is_final에 접근을 하여 true일 경우

로그인 호출 후 페이지 랜더링 시간을 예방하기 위해 setTime()를 호출합니다

그리고 keyboard.press() 함수를 사용해서 Escape 즉 우리가 알고 있는 esc를 누르는 효과로 

dim처리를 해제할 수 있습니다 

 

사이드 바 공식문서 카테고리에 키보드를 누를 수 있는 인자 값으로 뭐가 있는지

링크를 걸어두도록 하겠습니다

 

 


 

 

로그인 아웃 태그 찾기 및 로그아웃하기

 

 

아래와 같이 빨간색 테두리를 클릭하게 되면 

class명을 확인할 수 있습니다

그럼 앞서 로그인 하기와 같이 선언된 함수를 사용해서 프로필 서브 창을 활성화합니다

 

 

 

웹크롤링-태그찾기2
웹크롤링 로그아웃 태그 찾기

 

 

 

태그를 찾기 위해서는 창에 태그를 확인해야 합니다

아래와 같이 불확실할 경우에는 특정 지역을 찾을 수밖에 없습니다

어차피 웹크롤링은 웹사이트 하나에 대해서 대응할 수밖에 없으니

아래와 같이 지정해 봅시다

서브 창에서 div를 찾아 전체 div태그를 찾습니다

그리고 > div:last-child > div를 해서 최하위 div태그를 찾아서 로그인 버튼을 클릭하게 합니다

 

 

 

 

웹크롤링-태그찾기3
웹크롤링 서브창 태그 찾기

 

 

 

서브 창이 활성화될 때까지 기다려서 그다음 로그아웃 메뉴를 클릭해야 합니다

 

그것을 구현하기 위해 서브 창을 활성화할 태그 첫 번째 인자 값과

활성화될 때까지 기다릴 두 번째 인자 값을 할당하여 호출합니다

 

 

그래서 클릭한 다음 아래와 같이 함수를 호출하여 

다음 태그를 기다리고 그다음 함수를 실행하게 됩니다

 

 

웹크롤링 서브창 활성화 대기

 

 

 

이렇게 웹 크롤링해서 로그인과 로그아웃 그리고 서버 응답 대기,

그리고 현재 페이지 내에서 클릭 이벤트 등을 이용하여 페이지가 변화될 때

기다리는 함수를 알아보았습니다

 

웹크롤링은 개발할 때 한눈에 확보여서 재밌기도 합니다

이런 것을 배워서 제가 하고자 하는 것에 더 좋은 시스템을 만들어서 활용해보도록 하겠습니다

 

이렇게 이번 포스팅은 마치도록 하겠습니다

오늘도 너무너무 고생했지만 그래도 보람이 있는 하루인 것 같습니다

 

이렇게 보람찬 생활을 한다면 언젠가는 이 대모험도 끝나지 않을까? 합니다

 

그럼 끝날 수 있다고 믿으면 파이팅합시다

그럼 다음 포스팅에 뵙겠습니다

 

 

 

 

 

 

 

 

 

728x90
반응형

+ Recent posts

Powered by Tistory, Designed by wallel