자바스크립트/puppeteer, cheerio

* facebook 자동 로그인 + 좋아요 + 구독자 수 ( only puppeteer )

큰세상2000 2020. 11. 17. 00:19
반응형


참조 동영상 : https://www.youtube.com/watch?v=jw4exv4qv2E


분석은 로그인 한채로 진행하면 페이지 접근이 2-3 시간 정도 차단되므로 로그인 안한채로 하는것을 추천


index.js

const facebook = require("./facebook/index.js");

const facebook_id = '';
const facebook_pass = '';

(async () => {
	
	//  facebook 초기화
	await facebook.initialize();

	//	로그인
	await facebook.login(facebook_id, facebook_pass);

	//	페이스북 좋아요 카운트 가져오기
	await facebook.like_follow_Count();

	//  스크래핑 브라우저 종료
	await facebook.close();
})();

 


facebook.js

const puppeteer = require('puppeteer');
const clickTag = require('../_inc/clickTag.js');
const fs = require('fs');

const BASE_URL = 'https://www.facebook.com/';

module.exports = {
	browser: null,
	page: null,

	//  초기화
	initialize: async () => {
		// browser = await puppeteer.launch({ headless: false });
		browser = await puppeteer.launch();
		page = await browser.newPage();

		//	브라우저 타임아웃 오류 제거, 대기 시간이 길어짐
		await page.setDefaultNavigationTimeout(0);
	},

	//  로그인
	login: async (username, password) => {
		console.log('login start');

		try {
			await page.goto(BASE_URL, { waitUntil: 'networkidle2' });

			/*
			css : <a href="/accounts/login/?source=auth_switcher" tabindex="0">로그인</a>
			셀렉터 : #react-root > section > main > div > div > div:nth-child(2) > p > a
			*/

			// await facebook.page.$eval('#edit-button', el => el.click());

			//	로그인 페이지로 넘어가는 버튼 누르기
			// let loginButton = await facebook.page.$x('a[contains(text(), "로그인")]');
			// let loginButton = await facebook.page.$x('a[contains(., "로그인")]');

			// await delay(3000);

			console.log('id & pass input');

			//	아이디와 비빌번호 입력
			await page.type('input[name="email"]', username, { delay: 50 });
			await page.type('input[name="pass"]', password, { delay: 50 });

			//	로그인 페이지로 넘어가는 버튼 누르기
			/*
			css : <button class="sqdOP  L3NKy   y3zKF     " type="submit">
			<div class="Igw0E IwRSH eGOV_ _4EzTm">로그인</div></button>
			*/

			console.log('login button click');

			await clickTag.clickByText(page, '로그인', 'button');
			await clickTag.delay(2000);
		} catch (e) {
			console.debug(e);
		}
	},

	//	좋아요, 구독자 갯수 가져오기
	//	사이트 주소는 문서에서 가져온다
	//	./rank.txt
	// Big Hit Entertainment, fb.com/ibighit
	// 방탄소년단, fb.com/bangtan.official

	//	./rank_like_follower.txt
	//	페이지명, 사이트명, 좋아요갯수, 구독자수  형식
	like_follow_Count: async () => {
		try {
			var array = fs.readFileSync('./rank.txt').toString().split('\n');
			var arr = [];

			const fw = (data) => {
				fs.appendFile('./rank_like_follower.txt', data, function (err) {
					if (err) throw err;
					console.log(data);
				});
			};

			var arr = [];

			for (i in array) {
				arr = array[i].toString().split(', ');

				if (arr.length > 2) {
					arr[0] = arr[0] + ',' + arr[1];
					arr[1] = arr[2];
				}

				if (arr.length > 3) {
					arr[0] = arr[0] + ',' + arr[1] + ',' + arr[2];
					arr[1] = arr[3];
				}

				let likeNumber = 0;
				let followerNumber = 0;

				//	사이트 주소가 지정이 안된경우가 아니라면 로딩 시작
				if (arr[1] != 'fb.com/' && arr[1] != '') {
					await page.goto('http://' + arr[1], {
						//	networkidle2 는 페이지 못 받고 죽는 경우가 생김
						waitUntil: 'load',

						//	타임아웃 제거
						timeout: 0,
					});

					//	페이지 열릴때까지 대기 시간
					await clickTag.delay(1500);

					likeNumber = await page.evaluate(() => {
						var aaa = 0;

						// div 태그 중에서 '명이 좋아합니다' 라는 텍스트를 가진것을 찾아서 숫자만 뽑는다
						for (const a of document.querySelectorAll('div')) {
							if (a.textContent.includes('명이 좋아합니다')) {
								aaa = a.textContent.replace(/[^0-9]/g, '');
							}
						}

						//	추출 데이타가 없거나 0 이 아니라면 추출한 값을 리턴
						//	그렇지 않다면 다시 한번 분석 시도
						if (aaa != undefined && aaa != 0) {
							return aaa;
						}

						for (const a of document.querySelectorAll('div')) {
							if (a.textContent.includes('명이 좋아합니다')) {
								aaa = a.textContent.replace(/[^0-9]/g, '');
							}
						}

						return aaa;
					});

					// div 태그 중에서 '명이 팔로우합니다' 라는 텍스트를 가진것을 찾아서 숫자만 뽑는다
					followerNumber = await page.evaluate(() => {
						var aaa = 0;
						for (const a of document.querySelectorAll('div')) {
							if (a.textContent.includes('명이 팔로우합니다')) {
								aaa = a.textContent.replace(/[^0-9]/g, '');
							}
						}

						//	추출 데이타가 없거나 0 이 아니라면 추출한 값을 리턴
						//	그렇지 않다면 다시 한번 분석 시도
						if (aaa != undefined && aaa != 0) {
							return aaa;
						}

						for (const a of document.querySelectorAll('div')) {
							if (a.textContent.includes('명이 팔로우합니다')) {
								return a.textContent.replace(/[^0-9]/g, '');
							}
						}

						return aaa;
					});
				}

				//	2번 분석시도를 했는데도 값이 안나오면 그냥 0으로 지정한다
				if (likeNumber == undefined && followerNumber == undefined) {
					likeNumber = 0;
					followerNumber = 0;
				}

				//	파일에 분석해온 좋아요와 구독자수를 저장한다
				fw(arr[0] + ',' + arr[1] + ',' + likeNumber + ',' + followerNumber + '\n');
			}
		} catch (e) {
			console.debug(e);
		}

		await clickTag.delay(1000);
	},

	//	스크래핑 중단
	close: async () => {
		console.log('browser close');

		await browser.close();
	},
};

 

 

반응형