ํ๋ก๊ทธ๋๋จธ์ค ์ฝ๋ฉํ
์คํธ๋ ๋ฌธ์ ์ ๋ฒํธ๊ฐ ์๋ค.
๊ทธ๋์ ๋ด๊ฐ ์ด๋๊น์ง ํ์๋์ง, ์ค๋์ ์ด๋์๋ถํฐ ์ด๋๊น์ง ํ์ง ๊ณํ ์ธ์ฐ๋ ๊ฒ ์ฝ์ง ์์๋ค.
๋งค์ผ ๋ฑ 30๋ถ๋ง ํฌ์ํด์ ๋ฌธ์ ๋ฅผ ํ๊ณ ์ถ์๋ฐโฆ
์ผ๋จ ์ฝ๋ฉ ๊ธฐ์ด ํธ๋ ์ด๋์ ์ด 124๋ฌธ์ ๋ฟ์ด๋๊น
์ฒ์์ ๊ทธ๋ฅ ํ๋์ฉ ๋ฐ์์ฐ๊ธฐํด์ ๋ชฉ๋ก ๋ง๋ค๊น ํ์๋ค.
๊ทผ๋ฐ ๋ฌธ๋ ์๊ฐ๋ฌ๋ค.
โ์น์คํฌ๋กค๋ง์ผ๋ก ๊ธ์ด์ค๋ฉด ๋์์?โ
์ฌ์ค ์น์คํฌ๋กค๋ง์ ๋ํด์๋
โ๋ญ๊ฐ๋ฅผ ๊ธ์ด์ค๋ ๊ฑฐ?โ ์ ๋๋ง ์๊ณ ์์๋ค.
๊ทผ๋ฐ ์ฑGPT๋ ๊ฐ์ด ์๊ธฐํ๋ฉฐ ์ฝ๋ ์ง๋ดค๋๋
๊ธ๋ฐฉ ์ํ๋ ๊ฒฐ๊ณผ๋ฌผ์ด ๋์๋ค.
์ด๊ฒ ๋ฐ๋กโฆ ๋ฐ์ด๋ธ์ฝ๋ฉ์ธ๊ฐ? ๐
const puppeteer = require("puppeteer");
const fs = require("fs");
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
const allTitles = [];
const totalPages = 7;
for (let currentPage = 1; currentPage <= totalPages; currentPage++) {
const url = `https://school.programmers.co.kr/learn/challenges/training?order=acceptance_desc&languages=javascript&page=${currentPage}`;
console.log(`๐ ํ์ด์ง ${currentPage} ๋ก๋ฉ ์ค...`);
await page.goto(url, {
waitUntil: "networkidle2",
timeout: 120000,
});
await new Promise((resolve) => setTimeout(resolve, 2000));
const titles = await page.$$eval("td.title a", (elements) =>
elements.map((el) => ({
title: el.innerText.trim(),
link: el.href,
}))
);
console.log(`โ
ํ์ด์ง ${currentPage}์์ ${titles.length}๊ฐ ์์ง`);
allTitles.push(...titles);
}
console.log(`\n๐ฆ ๋ชจ๋ ๋ฌธ์ ์ ๋ชฉ (์ด ${allTitles.length}๊ฐ):`);
allTitles.forEach((title, index) => {
console.log(`${index + 1}. ${title.title}`);
});
await browser.close();
const csvHeader = "๋ฒํธ,์ ๋ชฉ,๋งํฌ\n";
const csvContent = allTitles
.map((p, i) => `${i + 1},"${p.title}","${p.link}"`)
.join("\n");
fs.writeFileSync("programmers_problems.csv", csvHeader + csvContent, "utf-8");
console.log(`๐พ CSV ์ ์ฅ ์๋ฃ: programmers_problems.csv`);
})();
์ฒ์ npm init -y ํ๋๋ ์ด๋ฌ๋๋ผ.
npm ERR! Invalid name: "์ฝ๋ฉ202507"
ํ๊ธ ํด๋๋ช
๋๋ฌธ์ npm์ด ์์งโฆ
๋ฐ๋ก ํด๋๋ช
์ coding-2507์ผ๋ก ๋ฐ๊ฟ์ ํด๊ฒฐํ๋ค.
์ฒซ ์คํ ๋ ์ด ์๋ฌ๊ฐ ๋ด๋ค.
TimeoutError: Navigation timeout of 60000 ms exceeded
Puppeteer๊ฐ ํ์ด์ง์ ๋ชจ๋ ์์ฒญ์ด ๋๋๊ธธ ๊ธฐ๋ค๋ฆฌ๋๋ผ ํ์์์ ๊ฑธ๋ฆผ.
ํด๊ฒฐ๋ฒ์ ๊ฐ๋จํ๋ค.
waitUntil: "networkidle0" โ "networkidle2"timeout: 120000์ผ๋ก ๋๋ฆผheadless: false๋ก ์ค์ ๋ธ๋ผ์ฐ์ ์ผ์ ๋์ ํ์ธ์๋ฌด๋ฆฌ ๋๋ ค๋ 1ํ์ด์ง 20๋ฌธ์ ๋ง ๊ธํ.
URL์ page=1์ด ๋ฐํ์๋ ๊ฑธ ๋ฐ๊ฒฌํ๊ณ for๋ฌธ์ผ๋ก 1~7ํ์ด์ง ์ํํ๋๋ก ์์ ํ๋ค.
for (let currentPage = 1; currentPage <= totalPages; currentPage++) {
const url = `...page=${currentPage}`;
await page.goto(url, ...);
}
์ด๋ฒ์ CSV ๊ฒฐ๊ณผ๊ฐ ์ด ๋ชจ์:
"๋ฌธ์ ์ ๋ชฉ","function link() { [native code] }"
์์ธ์ ๋ ๊ฐ์ง์๋ค.
el.textContent๊ฐ ๋์ ์ ํจ โ ๋์ ํ์ด์ง๋ผ์el.getAttribute("href") ๋์ ํจ์ ์ฐธ์กฐ๊ฐ ์ฐํ๊ณ ์น ๋ฐฉ๋ฒ:
title: el.innerText.trim(),
link: el.href,
๋ฐ๊ฟจ๋๋ ๊น๋ํ๊ฒ ์ ๋ชฉ+๋งํฌ ์ถ๋ ฅ๋จ.
๋ง์ง๋ง์ผ๋ก fs.writeFileSync() ์ผ๋๋:
ReferenceError: fs is not defined
fs ๋ชจ๋์ import ์ ํด์ ์๊ธด ์ค์์๋ค. ์๋จ์ ์ถ๊ฐ๋ก ํด๊ฒฐ.
const fs = require("fs");
์ต์ข
์ ์ผ๋ก ๋์จ programmers_problems.csv
| ๋ฒํธ | ์ ๋ชฉ | ๋งํฌ |
|---|---|---|
| 1 | ๋ฌธ์ ๋ฆฌ์คํธ๋ฅผ ๋ฌธ์์ด๋ก ๋ณํํ๊ธฐ | https://school.programmers.co.kr/learn/courses/30/lessons/181941 |
| 2 | ํ์ง์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ ๋ฐํํ๊ธฐ | https://school.programmers.co.kr/learn/courses/30/lessons/181944 |
์์ ๋ก ์ด๋ฉด ๋ฐ๋ก ๋งํฌ ํด๋ฆญ ๊ฐ๋ฅ ๐
innerText, href๋ก ์ ๊ทผํด์ผ ์์ networkidle2 + setTimeout ์กฐํฉ์ผ๋ก ๋ก๋ฉ ์์ ํ
