먼저 facebook 크롤링을 진행을 위해 아이디를 가입했기때문에 인스타그램 또한 facebook아이디로 진행을 위해
facebook으로 로그인창을 받아서 클릭을 진행해준다.
document.querySelector(".KPnG0").click();
로그인 유지하기
userDataDir을 사용하면 로그인에 대한 정보를 기억 할 수 있다.
const browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"],
userDataDir: 'C:\Users\dhsdb\AppData\Local\Google\Chrome\User Data'
});
로그인 여부 판단하기
로그인이 되어있으면 내 아이디 주소를 기반으로 href="/bot135791/" 이 나와있다
게시글 가져오기
article로 구성이 되어있다.
document.querySelector("article:first-of-type")
작성자 ID 가져오기
document.querySelector("a.sqdOP")
게시글 ID 가져오기
a태그 식으로 되어있다.
document.qeurySelector(".c-Yi7")
이미지 가져오기
document.querySelector("article:first-of-type").querySelector(".KL4Bh img")
게시글 Content 가져오기
document.querySelector("article .QzzMF:first-of-type")
1차적으로 가져와보기
const puppeteer = require("puppeteer");
const dotenv = require("dotenv");
dotenv.config();
const crawler = async () => {
try {
const browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"],
userDataDir: "C:UsersdhsdbAppDataLocalGoogleChromeUser Data",
});
const page = await browser.newPage();
page.setViewport({
width: 1080,
height: 1080,
});
await page.goto("https://instagram.com");
// 로그인이 되었을때
if (await page.$('a[href="/bot135791/"]')) {
console.log("이미 로그인이 되어있습니다");
// 로그인이 안됬을때
} else {
// 페이스북으로 로그인 버튼
await page.waitForSelector(".KPnG0");
await page.click(".KPnG0");
await page.waitForNavigation(); //facebook 로그인으로 넘어가는것을 대기
await page.waitForSelector("#email");
await page.type("#email", process.env.EMAIL);
await page.waitFor(1000);
await page.type("#pass", process.env.PASSWORD);
await page.waitFor(1000);
await page.waitForSelector("#loginbutton");
await page.click("#loginbutton");
await page.waitForNavigation(); //instagram으로 넘어가는것을 대기
console.log("로그인을 완료 하였습니다 ");
}
await page.waitForSelector("article:first-of-type");
const newPost = await page.evaluate(() => {
// 더보기를 눌러서 진행해준다
if(document.querySelector("button.sXUSN")){
document.querySelector("button.sXUSN").click();
}
//게시글 가져오기
const article = document.querySelector("article:first-of-type");
console.log(article);
const postId =
document.querySelector(".c-Yi7") &&
document.querySelector(".c-Yi7").href;
console.log(postId);
const name =
article.querySelector("a.sqdOP") &&
article.querySelector("a.sqdOP").textContent;
const image =
article.querySelector(".KL4Bh img") &&
article.querySelector(".KL4Bh img").src;
console.log(image);
const content =
article.querySelector(".QzzMF:first-of-type") &&
article.querySelector(".QzzMF:first-of-type").textContent;
return {
postId,
name,
image,
content,
};
});
console.log(newPost);
} catch (err) {
console.log(err);
}
};
crawler();
인스타는 스크롤을 내리면 위에있는 article을 없애버리고 하단에 새 article을 추가하고 하는
react-virtualized 기술이 적용되어있다. (메모리를 아낀다)
그래서 aricle이 처음엔 8개까지 늘어나다가 그 이후로는 article이 추가및 삭제가 되서 8개씩 유지한다.
먼저 스크롤 부분들을 위해 해당 부분들을 제거해준다.
제거해주고 스크롤을 돌린 코드
const puppeteer = require("puppeteer");
const dotenv = require("dotenv");
dotenv.config();
const crawler = async () => {
try {
const browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"],
userDataDir: "C:UsersdhsdbAppDataLocalGoogleChromeUser Data",
});
const page = await browser.newPage();
page.setViewport({
width: 1080,
height: 1080,
});
await page.goto("https://instagram.com");
// 로그인이 되었을때
if (await page.$('a[href="/bot135791/"]')) {
console.log("이미 로그인이 되어있습니다");
// 로그인이 안됬을때
} else {
// 페이스북으로 로그인 버튼
await page.waitForSelector(".KPnG0");
await page.click(".KPnG0");
await page.waitForNavigation(); //facebook 로그인으로 넘어가는것을 대기
await page.waitForSelector("#email");
await page.type("#email", process.env.EMAIL);
await page.waitFor(1000);
await page.type("#pass", process.env.PASSWORD);
await page.waitFor(1000);
await page.waitForSelector("#loginbutton");
await page.click("#loginbutton");
await page.waitForNavigation(); //instagram으로 넘어가는것을 대기
console.log("로그인을 완료 하였습니다 ");
}
await page.waitForSelector("article:first-of-type");
//스토리 부분, 전화번호 추가, 프로필 사진추가 삭제하기
await page.evaluate(() => {
const story = document.querySelector(".zGtbP");
const start = document.querySelector("._2eEhX");
//삭제
if (story) {
story.parentNode.removeChild(story);
}
if (start) {
start.parentNode.removeChild(start);
}
const recommended = document.querySelector(".vboSt");
if (recommended) {
recommended.parentNode.removeChild(recommended);
}
});
await page.waitFor(1000);
let result = [];
let prevPostId = "";
while (result.length < 10) {
// 회원님을 위한 추천 삭제해주기
const newPost = await page.evaluate(() => {
// 더보기를 눌러서 진행해준다
if (document.querySelector("button.sXUSN")) {
document.querySelector("button.sXUSN").click();
}
//게시글 가져오기
const article = document.querySelector("article:first-of-type");
console.log(article);
const postId =
document.querySelector(".c-Yi7") &&
document.querySelector(".c-Yi7").href;
console.log(postId);
const name =
article.querySelector("a.sqdOP") &&
article.querySelector("a.sqdOP").textContent;
const image =
article.querySelector(".KL4Bh img") &&
article.querySelector(".KL4Bh img").src;
console.log(image);
const content =
article.querySelector(".QzzMF:first-of-type") &&
article.querySelector(".QzzMF:first-of-type").textContent;
return {
postId,
name,
image,
content,
};
});
// 새 게시글의 postId가 이전 postId와 같지 않으면
// 배열에 넣고 해당 포스트 아이디를 검증한다
// 중복으로 데이터가 들어가는것을 방지
if (newPost.postId !== prevPostId) {
if (!(result.find((v) => v.postId === newPost.postId))) {
result.push(newPost);
}
}
prevPostId = newPost.postId;
await page.evaluate(() => {
window.scrollBy(0, 900);
});
}
console.log(result);
} catch (err) {
console.log(err);
}
};
crawler();
게시글들을 가져오는데 성공하였다.
좋아요 구현하기
해당 코드를 통해 좋아요 기능까지 구현하였다.
await page.evaluate(() => {
// 좋아요 눌러주기
const fill = document.querySelector(".fr66n button svg");
if(fill.getAttribute("fill") === "#262626"){
document.querySelector(".fr66n button").click();
}
});
const puppeteer = require("puppeteer");
const dotenv = require("dotenv");
dotenv.config();
const crawler = async () => {
try {
const browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"],
userDataDir: "C:UsersdhsdbAppDataLocalGoogleChromeUser Data",
});
const page = await browser.newPage();
page.setViewport({
width: 1080,
height: 1080,
});
await page.goto("https://instagram.com");
// 로그인이 되었을때
if (await page.$('a[href="/bot135791/"]')) {
console.log("이미 로그인이 되어있습니다");
// 로그인이 안됬을때
} else {
// 페이스북으로 로그인 버튼
await page.waitForSelector(".KPnG0");
await page.click(".KPnG0");
await page.waitForNavigation(); //facebook 로그인으로 넘어가는것을 대기
await page.waitForSelector("#email");
await page.type("#email", process.env.EMAIL);
await page.waitFor(1000);
await page.type("#pass", process.env.PASSWORD);
await page.waitFor(1000);
await page.waitForSelector("#loginbutton");
await page.click("#loginbutton");
await page.waitForNavigation(); //instagram으로 넘어가는것을 대기
console.log("로그인을 완료 하였습니다 ");
}
await page.waitForSelector("article:first-of-type");
//스토리 부분, 전화번호 추가, 프로필 사진추가 삭제하기
await page.evaluate(() => {
const story = document.querySelector(".zGtbP");
const start = document.querySelector("._2eEhX");
//삭제
if (story) {
story.parentNode.removeChild(story);
}
if (start) {
start.parentNode.removeChild(start);
}
const recommended = document.querySelector(".vboSt");
if (recommended) {
recommended.parentNode.removeChild(recommended);
}
});
await page.waitFor(1000);
let result = [];
let prevPostId = "";
while (result.length < 10) {
// 회원님을 위한 추천 삭제해주기
const newPost = await page.evaluate(() => {
// 더보기를 눌러서 진행해준다
if (document.querySelector("button.sXUSN")) {
document.querySelector("button.sXUSN").click();
}
//게시글 가져오기
const article = document.querySelector("article:first-of-type");
console.log(article);
const postId =
document.querySelector(".c-Yi7") &&
document.querySelector(".c-Yi7").href;
console.log(postId);
const name =
article.querySelector("a.sqdOP") &&
article.querySelector("a.sqdOP").textContent;
const image =
article.querySelector(".KL4Bh img") &&
article.querySelector(".KL4Bh img").src;
console.log(image);
const content =
article.querySelector(".QzzMF:first-of-type") &&
article.querySelector(".QzzMF:first-of-type").textContent;
return {
postId,
name,
image,
content,
};
});
await page.evaluate(() => {
// 좋아요 눌러주기
const fill = document.querySelector(".fr66n button svg");
if(fill.getAttribute("fill") === "#262626"){
document.querySelector(".fr66n button").click();
}
});
await page.waitFor(1000);
// 새 게시글의 postId가 이전 postId와 같지 않으면
// 배열에 넣고 해당 포스트 아이디를 검증한다
// 중복으로 데이터가 들어가는것을 방지
if (newPost.postId !== prevPostId) {
if (!(result.find((v) => v.postId === newPost.postId))) {
result.push(newPost);
}
}
prevPostId = newPost.postId;
await page.evaluate(() => {
window.scrollBy(0, 900);
});
}
console.log(result);
} catch (err) {
console.log(err);
}
};
crawler();
본 글은 아래 인프런 강의를 듣고 작성된 내용입니다
https://www.inflearn.com/course/%ED%81%AC%EB%A1%A4%EB%A7%81
'Node.js > node crawling' 카테고리의 다른 글
노드 크롤링 - 페이스북 이미지 가져오기, 좋아요 구현하기, DB 저장 (0) | 2020.08.17 |
---|---|
노드 크롤링 - 페이스북 로그인, 로그아웃 하기 (0) | 2020.08.16 |
노드 크롤링 - 인피니티 스크롤 사이트(unsplash) 크롤링하기 (3) | 2020.08.16 |
노드 크롤링 - 브라우저 사이즈 조절 및 스크린샷 찍기 (0) | 2020.08.16 |
노드 크롤링 - axios를 활용해서 이미지를 다운로드 하기 (0) | 2020.08.16 |