📱인프런 모바일 App 😆
Node.js로 웹 크롤링하기

Node.js로 웹 크롤링하기

(1개의 수강평)

67명의 수강생

55,000원

평생
초급, 중급
수료증
75개 수업, 총 12시간 59분
위시리스트 추가
황재만 프로필

함수 패러미터 안에 들어올 타입에 대한 가이드가 에디터상에 노출되고있는거 같은데 어떤 확장툴을 설치하신건가요? 황재만 1달 전

sheet_to_json(ws, opts: { header: 'A' });

 

3분 3초경에 나오는 위의 opts: 와 같은 표기들이요 ㅎ

실제 코드는 아니고 함수 내부의 타입을 알아서 가이드해주는거 같은데 유용해보여서요.

1
김호균 프로필

10강 페이지네이션과 아이프레임 강의가 7개 아니었나요? 김호균 1달 전

10-6강 트위터 태그 분석하기

10-7강 트위터 아이프레임 컨텐츠 가져오기

 

이거 두개 강의가 지금은 안보여요

1
이재형 프로필

반복 크롤링이 2개까지만 되고 시행이 되지 않습니다. 이재형 3달 전

강의 중 내용과 다른것은 다음처럼 친구 추천이 뜨는데 혹시 이문제로 작동이 되지 않는 걸까요? 친구 추천 다음 게시글부터 크롤링 되지 않습니다.

중간에 다음과 같이 회원님을 위한 추천이 뜨고,

 

크롤링 콘솔창에는 이런 오류가 뜨는데요.

Error: Evaluation failed: TypeError: Cannot read property 'querySelector' of null

    at __puppeteer_evaluation_script__:4:19 입니다.

코드는 다음과 같습니다.

const puppeteer = require("puppeteer");
const dotenv = require("dotenv");

const db = require("./models");
dotenv.config();

const crawler = async () => {
try {
await db.sequelize.sync();
const browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"],
userDataDir: "/Users/fullyalive/Project/userData"
});
const page = await browser.newPage();
await page.setViewport({
width: 1920,
height: 1080
});
await page.goto("https://instagram.com");
if (await page.$(`a[href="/${process.env.IN_ID}/"]`)) {
console.log("✅ 이미 로그인 되어 있습니다.");
} else {
await page.waitForSelector("button.L3NKy"); // instagram 내 페이스북 로그인버튼
await page.click("button.L3NKy");
await page.waitForNavigation(); // facebook 로그인 창 리다이렉트를 기다린다.
await page.waitForSelector("#email"); // 해당 태그의 존재 여부를 확인
await page.type("#email", process.env.FB_ID);
await page.type("#pass", process.env.FB_PW);
await page.waitForSelector("#loginbutton");
await page.click("#loginbutton");
console.log("🙆🏻‍ 로그인 완료");
}
let result = [];
let prevPostId = "";
while (result.length < 10) {
const moreButton = await page.$("button.sXUSN"); // 더보기 버튼 클릭
if (moreButton) {
await page.evaluate(btn => btn.click(), moreButton);
}
const newPost = await page.evaluate(() => {
const article = document.querySelector("article:first-child");
const postId =
article.querySelector(".c-Yi7") &&
article.querySelector(".c-Yi7").href;
const name = article.querySelector("h2").textContent;
const img =
article.querySelector(".KL4Bh img") &&
article.querySelector(".KL4Bh img").src;
const content =
article.querySelector(".C4VMK > span") &&
article.querySelector(".C4VMK > span").textContent;
return {
postId,
name,
img,
content
};
});
if (newPost.postId !== prevPostId) {
console.log(newPost);
if (!result.find(v => v.postId === newPost.postId)) {
result.push(newPost);
}
}
prevPostId = newPost.postId;
await page.waitFor(1000);
await page.evaluate(() => {
window.scrollBy(0, 800);
});
}

await page.waitFor(3000);
await page.close();
await browser.close();
} catch (e) {
console.error(e);
}
};

crawler();

1
이재형 프로필

[에러발생]Cannot read property 'findOne' of undefined 이재형 3달 전

안녕하세요!

let result=[]; 밑으로 코드는 전부 붙여넣었는데,

TypeError: Cannot read property 'findOne' of undefined  at crawler (/Users/fullyalive/Project/project_nodeJsCrawler/lecture/index.js:68:44)

    at process._tickCallback (internal/process/next_tick.js:68:7)가 뜨는데 해결방법을 모르겠습니다 ㅠㅠ

코드는 다음 코드입니다.

const puppeteer = require("puppeteer");
const dotenv = require("dotenv");

const db = require("./models");
dotenv.config();

const crawler = async () => {
try {
await db.sequelize.sync();
const browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"],
userDataDir: "/Users/fullyalive/Project/userData"
});
const page = await browser.newPage();
await page.setViewport({
width: 1920,
height: 1080
});
await page.goto("https://instagram.com");
if (await page.$(`a[href="/${process.env.IN_ID}/"]`)) {
console.log("✅ 이미 로그인 되어 있습니다.");
} else {
await page.waitForSelector("button.L3NKy"); // instagram 내 페이스북 로그인버튼
await page.click("button.L3NKy");
await page.waitForNavigation(); // facebook 로그인 창 리다이렉트를 기다린다.
await page.waitForSelector("#email"); // 해당 태그의 존재 여부를 확인
await page.type("#email", process.env.FB_ID);
await page.type("#pass", process.env.FB_PW);
await page.waitForSelector("#loginbutton");
await page.click("#loginbutton");
console.log("🙆🏻‍ 로그인 완료");
}
let result = [];
let prevPostId = "";
while (result.length < 10) {
const moreButton = await page.$("button.sXUSN"); // 더보기 버튼 클릭
if (moreButton) {
await page.evaluate(btn => btn.click(), moreButton);
}
const newPost = await page.evaluate(() => {
const article = document.querySelector("article:first-child");
const postId =
article.querySelector(".c-Yi7") &&
article
.querySelector(".c-Yi7")
.href.split("/")
.slice(-2, -1)[0];
const name =
article.querySelector("h2") &&
article.querySelector("h2").textContent;
const img =
article.querySelector(".KL4Bh img") &&
article.querySelector(".KL4Bh img").src;
const content =
article.querySelector(".C4VMK > span") &&
article.querySelector(".C4VMK > span").textContent;
return {
postId,
name,
img,
content
};
});
if (newPost.postId !== prevPostId) {
console.log(newPost);
if (!result.find(v => v.postId === newPost.postId)) {
const exist = await db.Instagram.findOne({
where: { postId: newPost.postId }
});
if (!exist) {
result.push(newPost);
}
}
}
await page.waitFor(1000);
await page.evaluate(() => {
const article = document.querySelector("article:first-child");
const heartBtn = article.querySelector(".coreSpriteHeartOpen span");
if (heartBtn.className.includes("outline")) {
heartBtn.click();
}
});
prevPostId = newPost.postId;
await page.waitFor(1000);
await page.evaluate(() => {
window.scrollBy(0, 800);
});
}
await Promise.all(
result.map(r => {
return db.Instagram.create({
postId: r.postId,
media: r.img,
writer: r.name,
content: r.content
});
})
);

console.log(result.length);
await page.close();
await browser.close();
} catch (e) {
console.error(e);
}
};

crawler();

1
이재형 프로필

sponsered(광고) 게시글 탐색을 위한 문자열 입력 이재형 3달 전

document.querySelector('[id^=hyperfeed_story_id]:nth-child(5)').textContent 를 하면 강의에서 나온 sponsor 구분 코드가 뜨지 않습니다.

저는 다음처럼 실행되는데, 어떻게 스폰서를 제외할 수 있을까요??

2
이재형 프로필

npm start 후 error 이재형 3달 전

 UnhandledPromiseRejectionWarning: SequelizeConnectionError: Client does not support authentication protocol requested by server; consider upgrading MySQL client

이런 오류가 생기는데, 어떤게 문제인지 모르겠습니다.

원래 강의대로라면 crawler schema에 table이 생겨야하는데, 위 오류가 발생합니다.

mysql 설치시 validation을 설치했는데 그거 때문에 생긴 문제일까요?

코드는 다음 코드에서 돌렸습니다.

const puppeteer = require("puppeteer");
const dotenv = require("dotenv");

const db = require("./models");
dotenv.config();

const crawler = async () => {
await db.sequelize.sync();
try {
let browser = await puppeteer.launch({
headless: false,
args: ["--window-size=1920,1080", "--disable-notifications"]
});
let page = await browser.newPage();
await page.setViewport({
width: 1080,
height: 1080
});
await page.goto("http://spys.one/free-proxy-list/KR/");
const proxies = await page.evaluate(() => {
const ips = Array.from(
document.querySelectorAll("tr > td:first-of-type > .spy14")
).map(v => v.textContent.replace(/document\.write\(.+\)/, ""));
const types = Array.from(
document.querySelectorAll("tr > td:nth-of-type(2)")
)
.slice(5)
.map(v => v.textContent);
const latencies = Array.from(
document.querySelectorAll("tr > td:nth-of-type(6) .spy1")
).map(v => v.textContent);
return ips.map((v, i) => {
return {
ip: v,
type: types[i],
latency: latencies[i]
};
});
});
const filtered = proxies
.filter(v => v.type.startsWith("HTTP"))
.sort((p, c) => p.latency - c.latency);
await Promise.all(
filtered.map(async v => {
return db.Proxy.upsert({
ip: v.ip,
type: v.type,
latency: v.latency
});
})
);
await page.close();
await browser.close();
const fastestProxies = await db.Proxy.findAll({
order: [["latency", "ASC"]]
});
browser = await puppeteer.launch({
headless: false,
args: [
"--window-size=1920,1080",
"--disable-notifications",
`--proxy-server=${fastestProxies[0].ip}`
]
});
const browser2 = await puppeteer.launch({
headless: false,
args: [
"--window-size=1920,1080",
"--disable-notifications",
`--proxy-server=${fastestProxies[1].ip}`
]
});
const browser3 = await puppeteer.launch({
headless: false,
args: [
"--window-size=1920,1080",
"--disable-notifications",
`--proxy-server=${fastestProxies[2].ip}`
]
});
// const context = await browser.createIncognitoBrowserContext();
// const context2 = await browser.createIncognitoBrowserContext();
// const context3 = await browser.createIncognitoBrowserContext();
// console.log(await browser.browserContexts());
const page1 = await browser.newPage();
const page2 = await browser2.newPage();
const page3 = await browser3.newPage();
await page1.goto(
"https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query=%EB%82%B4+%EC%95%84%EC%9D%B4%ED%94%BC"
);
await page2.goto(
"https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query=%EB%82%B4+%EC%95%84%EC%9D%B4%ED%94%BC"
);
await page3.goto(
"https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query=%EB%82%B4+%EC%95%84%EC%9D%B4%ED%94%BC"
);
// page = await browser.newPage();
// await page.goto('https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query=%EB%82%B4+%EC%95%84%EC%9D%B4%ED%94%BC');
// await page.waitFor(10000);
// await page.close();
// await browser.close();
await db.sequelize.close();
} catch (e) {
console.error(e);
}
};

crawler();

2
이재형 프로필

mysql MAC OS 설치관련 이재형 3달 전

mysql workbench를 설치했는데

셋팅에 관한 내용이 없고

제 초기 셋팅이 강사님과 달라서 따라가기가 힘듭니다.

관련 자료나 새로운 영상 제공이 가능한가요?

3