728x90
반응형

이전 글에서는 웹크롤링에서 간단하게 DB 연동하기에 대해서

 

DB 연동으로 웹크롤링을 보다 효율적으로 사용하는 방법을 알아보았습니다

DB 연동으로 정보를 저장해서 데이터 관리는 물론 중복된 데이터까지

관리가 가능하니 웹 크롤링을 보다 능률적으로 실행할 수 있을 것입니다

 

더 자세히 알고 싶으시다면 아래의 링크를 클릭해주세요

 

 

2022.09.03 - [IT_Web/Nodejs] - 웹 크롤링 puppeteer로 mysql 및 sequelize 활용하여 DB 연동하기

 

웹 크롤링 puppeteer로 mysql 및 sequelize 활용하여 DB연동하기

이전 글에서 간략하게 프록시가 무엇이며 프록시를 활용해서 IP를 변경하는 방법을 알아보았습니다 더 자세한 정보를 알고 싶으시다면 아래의 링크를 클릭하시길 바랍니다. 2022.09.02 - [IT_Web/Nodej

tantangerine.tistory.com

 

 

로그인 유지 및 파일 업로드 알아보기

 

 

오늘은 puppeteer를 활용해서 파일 업로드

로그인 정보를 유지하는 방법을 알아보려고 합니다

 

 

 

그럼 우선 전체 코드를 보시겠습니다

아래의 코드를 보시면 진행이 많이 되었습니다

이전 포스팅을 하나씩 참고하시면 완성하실 수 있으니 관심 있으시다면 확인해보세요

 

 

 

const puppeteer = require('puppeteer');
const writekeyboardList = require('./writekeyboardList');
const callElement = require('./mouseHandleHtml');
const dotenv = require('dotenv'); // npm i dotenv
const db = require('./models');
const fs = require('fs')

dotenv.config();

const setCrawler = async (production, isMouse = false) => {
  await db.sequelize.sync();
  let browser = await puppeteer.launch({
    headless: false,
    args:['--window-size=1920,1080'],
    userDataDir: 'C:\Users\kimsangjin\AppData\Local\Google\Chrome\User Data'
  });
  let page = await browser.newPage();
  await page.setViewport({
    width: 1080,
    height:1080,
  })

  if (!production && isMouse) {
    await callElement(page)
  }

  await page.on('dialog', async (dialog) => { 
    console.log(`dialog`, dialog) 
    console.log(`type: ${dialog.type()} / message: ${dialog.message()}`) 
    if(dialog.type() === 'prompt') {
      await dialog.accept('https://www.tistory.com/')
    }
    if(dialog.type() === 'alert'){
      await dialog.dismiss(); 
    }
    if(dialog.type() === 'confirm'){
      await dialog.accept();
    }
  })

  const setNewProxy = async(crawlerUrl) => {
    const newProxies = await page.evaluate(async() => {
      const ips = Array.from(document.querySelectorAll('tr > td:first-of-type > .spy14')).map((v) => v.innerText)
      const types = Array.from(document.querySelectorAll('tr > td:nth-of-type(2)')).map((v) => v.innerText)
      const anonymity = Array.from(document.querySelectorAll('tr > td:nth-of-type(3)')).map((v) => v.innerText)
      const latencies = Array.from(document.querySelectorAll('tr > td:nth-of-type(6) > .spy1')).map((v) => v.innerText)
      return ips.map((v, i) => {
        return {
          ip: v,
          type: types[i],
          latency: latencies[i],
          anonymity: anonymity[i].toString()
        }
      });
    });
    const fristProxies =  newProxies.filter((v) => v.type.startsWith('HTTP')).sort((p, c) => p.latency - c.latency)
    console.log('fristProxies', fristProxies)
    await Promise.all(fristProxies.map(async (v) => {
      return await db.Proxy.create({
        ip: v.ip,
        type: v.type,
        latency: v.latency,
        anonymity: anonymity.toString()
      });
    }))
    await page.close();
    await browser.close();
    browser = await puppeteer.launch({
      headless: false,
      args:['--window-size=1920,1080', '--disable-notifications', `--proxy-server=${fristProxies[0].ip}`]
    });
    page = await browser.newPage();
    await page.goto(crawlerUrl);
    await page.waitForSelector('.tf_keyword')
    await inputValue('.tf_keyword', '내아이피'),
    await Promise.all([
      buttonClick(['.ico_pctop.btn_search', 'ico_ksearch.btn_ksearch']),
      page.waitForNavigation(),
    ]);
    await setTime(4000)
    await page.close();
    await browser.close();
    await db.sequelize.close()
  }

  const handleWriteKeyboard = async (selector, id) => {
    const writeList = writekeyboardList()
    const idOfList = [...id]
    if(selector){
      await page.click(selector);
      console.log(`idOfList`, idOfList)
      for (const id of idOfList) {
        const inputValue = await writeList.filter(element => element.ShiftLeft === id || element.key === id )
        if (inputValue.length > 0) {
          const code = inputValue[0].code
          const ShiftLeft = inputValue[0].ShiftLeft === id ? 'ShiftLeft' : ''
          if (ShiftLeft) {
            await setTime(selector, 0, 'key')
            await page.keyboard.down(ShiftLeft);
            await setTime(selector, 0, 'key')
            await page.keyboard.press(code);
            await setTime(selector,0, 'key')
            await page.keyboard.up(ShiftLeft);
          } else {
            await page.keyboard.press(code);
          }
          await setTime(selector,0, 'key')
        }
      }
    } else {
      await page.keyboard.press(id);
    }
  }

  const getSelectEl = async(selector) => {
    const selectedEl = await page.evaluate((selector) => {
      console.log('selector', selector)
      const temEl = document.querySelector(selector)
      console.log('selector', temEl)
      return temEl
    }, selector)
        console.log('selector', selectedEl)
    return selectedEl
  }

  const fileUpload = async() => {
    const pathFile = 'C:\Users\kimsangjin\Desktop'
    const fileExitst = await fs.existsSync(`${pathFile}/travis_1.png`)
    if(fileExitst){
      const input = await page.$("#m_attach_file");
      await input.uploadFile(`${pathFile}/freelanceDeveloper.png`)
      return true
    }
    return false
  }

  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) => {
      if (document.querySelector(selector[0])) {
        document.querySelector(selector[0]).click();
      } else {
        document.querySelector(selector[1]).click();
      }
    }, selector)
    if(type === 'login'){
      // waitForRequest(요청 대기), waitForResponse(응답 대기)
      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, 2000)
        await page.keyboard.press('Escape')
      }
    } else if(type === 'logOut'){
      await page.waitForNavigation()
    } else {
      if(nextSelector){
        await page.waitForSelector(nextSelector)
      }
      if(type === 'wait') await setTime(selector)
    }
  }

  const setTime = async (selector = 'normal', waitTime = 0, type= '') => {
    const setTime = await page.evaluate(async(waitTime, type) => {
      let timeList =[]
      if(type === 'key'){
         timeList = await [569, 311, 257, 175, 306, 123, 428, 497, 298, 211, 379, 108, 512, 139, 249];
      } else {
        timeList = await [3975, 4547, 5231, 6397, 7894, 3394, 4206, 5147, 6932, 7430, 3561, 4896, 5877, 6407, 7133];
      }
      let randomTime = await timeList[Math.floor(Math.random() * timeList.length)]
      if (waitTime > 0) randomTime = waitTime
      await new Promise(r => setTimeout(r, randomTime))
      return randomTime
    }, waitTime, type)
    console.log(`waitTime[${selector}]: `, setTime)
    return setTime
  } 


  return { fileUpload, getSelectEl, buttonClick, inputValue, handleWriteKeyboard, setTime, setNewProxy, page, browser }
}


const crawler = async () => {
  try {
    const { getSelectEl, buttonClick, inputValue, handleWriteKeyboard, setTime, setNewProxy, page, browser } = await setCrawler(JSON.parse(process.env.PRODUCTION));
    const id = await process.env.EMAIL;
    const password = await process.env.PASSWORD;
    await page.goto('https://office.hiworks.com/polarium.co.kr/home#loginUrl=mail/webmail/m_list/b0');
    await setTime()
    const isLogin = await getSelectEl('.menu.office')
    if(isLogin){
      console.log('이미 로그인이 되어있습니다.')
      await buttonClick(['.menu.office'], '.main-btn');
    } else {
      await page.waitForSelector('#office_id');
      await setTime()
      await handleWriteKeyboard('#office_id', id)
      await setTime()
      await handleWriteKeyboard('#office_passwd', password)
      await setTime()
      await buttonClick(['.int_jogin'], '.main-btn');
    }
      await page.waitForSelector('.main-btn')
      await buttonClick(['.main-btn'], '#to_addr');
      await page.waitForSelector('#to_addr')
      await inputValue('#to_addr', '김상진');
      await setTime('', 500)
      await page.keyboard.press('Enter');
      await page.waitForSelector('#m_attach_file')
      await fileUpload()
      await setTime('', 500)
      await buttonClick(['.detail_select > a']);
  } catch (e) {
    console.log(e);
  }
}

crawler()

 

로그인 유지 알아보기

먼저 로그인 유지 방법을 알아보도록 하겠습니다

 

 

아래의 userDateDir를 추가하면 간단하게 로그인 유지가 됩니다

하지만 크롬만 가능하니 크롬을 설치하고 아래의 경로대로 설정하시면 간단히 됩니다

 

puppeteer-로그인유지
로그인 유지 코드

 

아래처럼 로그인 유지가 된다면

로그인에만 있는 태그를 선택해서 있으면 로그인이 되었다는 의미로

분기를 하여 코드 작성할 수 있습니다

 

 

 

puppeteer-로그인분기
로그인 코드 분기

 

 

 

 

puppeteer 활용하여 파일 업로드 하기

 

이제는 어느 정도 하실 수 있다고 가정하겠습니다

그래서 여러 함수를 세팅해서 사용하고 있으니 참고하시길 바랍니다

 

로그인 후

fileUpload함수를 아래와 같이 실행합니다

 

 

puppeteer-파일업로드함수호출
파일업로드 실행

 

 

우선 파일 위치가 필요합니다

그 위치에 현재 올리려는 파일이 있는지 존재 여부를 확인하여

있을 때만 파일 업로드를 실행합니다

 

이때 이름은 db에 저장된 파일을 올리도록 하는 것이 좋을 듯합니다

다음에 기회 되면 적용하도록 하고

지금은 특정 파일만 올리도록 하겠습니다

 

 

puppeteer-파일업로드선언문
파일업로드 선언문

 

 

 

 

아래의 이미지를 보면 파일 첨부라는 글이 보이지만

그 밑에 input type='file'로 정의된 것을 확인할 수 있습니다

그것을 위에 처럼 input을 가져와서 .uploadFile()와 경로를 지정해서 호출하면

 

파일이 업로드되는 것을 확인할 수 있습니다

이때 꼭 page.$()활용해서 해야 한다는 점 확인하세요

 

 

 

태그 현재 상황
태그 현재 상황입니다

 

 

 

이렇게 로그인 유지와 파일 업로드를 알아보았습니다

node.js에서 메일 보낼 수 있는 라이브러리가 존재합니다

그러니 그것도 활용하는 것이 좋을 듯합니다

크롤링보다는 라이브러리를 사용하는 것이 간편하겠지요

 

그럼 오늘도 한걸음 나아가셨길 바라며

IT대모험을 즐기며 다음 포스팅에서 찾아뵙겠습니다

그럼 파이팅 하세요!

728x90
반응형

+ Recent posts

Powered by Tistory, Designed by wallel