우리가 할 것은 만든 포켓몬 도감 사이트에서 정보를 가져올 것이라서 스크래핑에 더 가까움!
npm init -y
// 크롤링을 도와주는 모듈
npm i puppeteer
// 크롤링하기위한 puppeteer 모듈 불러오기
const puppeteer = require("puppeteer");
// 데이터를 저장하기위해 fs 모듈 불러오기
const fs = require("fs");
async function scrape() {
try {
// 크로미움으로 브라우저를 연다.
const browser = await puppeteer.launch();
// 페이지 열기
const page = await browser.newPage();
// 링크 이동
await page.goto("http://127.0.0.1:5555");
// .card 엘리먼트중에 값이 #100인 .card--id 엘리먼트가 생길때까지 기다림
await page.waitForFunction(
() =>
document.querySelector(".card:last-child .card--id").textContent ===
"#100",
{ timeout: 5000 }
);
// cards 에 모든 카드정보 배열로 저장
const cards = await page.$$(".card");
// 100개의 카드가 잘 저장되었는지 확인.
console.log(cards.length);
const data = [];
// cards 돌면서 필요한 데이터 수집
// data 배열에 수집한 데이터 등록
for (const card of cards) {
const id = await card.$eval(".card--id", (el) => el.textContent);
const image = await card.$eval(".card--image", (el) =>
el.getAttribute("src")
);
const name = await card.$eval(".card--name", (el) => el.textContent);
const details = await card.$eval(
".card--details",
(el) => el.textContent
);
data.push({ id, image, name, details });
}
// 페이지와 브라우저 종료
await page.close();
await browser.close();
// data 리턴 => 리턴한 데이터를 받아서 파일로 쓰기 위함.
return data;
} catch (error) {
console.log(error);
}
}
scrape()
.then((data) => {
fs.writeFile("pokemon.json", JSON.stringify(data), "utf8", (error) => {
if (error) {
console.log("파일 생성 중 에러 발생.");
return console.log(error);
}
console.log("파일 생성 완료!");
});
})
.catch((error) => console.log(error));
//추가
type: "module"
{
// include : 컴파일할 파일 경로를 설정합니다. [ src폴더 하위의 모든 .ts 확장자를 가진 파일 ]
"include": ["src/**/*.ts"],
"compilerOptions": {
"lib": ["ES2021", "DOM"],
// esModuleInterop 속성이 위의 코드 처럼 true로 설정될 경우, ES6 모듈 사양을 준수하여 CommonJS 모듈을 가져올 수 있게 됩니다.
// e.g. typescript-test.ts => import express from "express"
"esModuleInterop": true,
// 타입스크립트가 모듈을 찾는방법을 지정(import puppeteer때문에)
"moduleResolution": "NodeNext",
"target": "ES2021",
// rootDir : 컴파일될 타입스크립트 코드들의 위치를 명시합니다.
// "rootDir": "src",
// outDir : 컴파일 후 생성되는 js파일이 생성될 폴더명
"outDir": "dist",
// strictNullChecks
"strictNullChecks": true,
// 암시적 any 타입을 허용하지 않는다
"noImplicitAny": true
}
}
만든 app.js 바탕으로 app.ts를 만들어 볼 것임!
// require => import 로 변경
// 크롤링하기위한 puppeteer 모듈 불러오기
import puppeteer from "puppeteer";
// 데이터를 저장하기위해 fs 모듈 불러오기
import fs from "fs";
interface IPokemon {
id: string;
name: string;
image: string;
type: string;
}
//성공했을때와 실패했을때 모두 return이 있어야 오류가 안남
async function scrape(): Promise<IPokemon[]> {
try {
// 크로미움으로 브라우저를 연다.
const browser = await puppeteer.launch();
// 페이지 열기
const page = await browser.newPage();
// 링크 이동
await page.goto("http://127.0.0.1:5500");
// .card 엘리먼트중에 값이 #100인 .card--id 엘리먼트가 생길때까지 기다림(모든 카드가 로드될때까지 기다림)
await page.waitForFunction(
() => {
const cardId = document.querySelector(".card:last-child .card--id");
return cardId && cardId.textContent === "#100";
},
{ timeout: 10000 }
);
// cards 에 모든 카드정보 배열로 저장
const cards = await page.$$(".card");
// 100개의 카드가 잘 저장되었는지 확인.
console.log(cards.length);
const data: Array<IPokemon> = [];
// const data: IPokemon[] = [];
// cards 돌면서 필요한 데이터 수집
for (const card of cards) {
const id = await card.$eval(".card--id", (el: Element) => el.textContent);
const image = await card.$eval(".card--image", (el: Element) =>
el.getAttribute("src")
);
const name = await card.$eval(
".card--name",
(el: Element) => el.textContent
);
const type = await card.$eval(
".card--details",
(el: Element) => el.textContent
);
// data 배열에 수집한 데이터 등록
if (id && image && name && type) {
data.push({ id, image, name, type });
} else {
console.log("빈 형식이 들어왔습니다!");
return [];
}
}
// 페이지와 브라우저 종료
await page.close();
await browser.close();
// data 리턴 => 리턴한 데이터를 받아서 파일로 쓰기 위함.
return data;
} catch (error) {
console.log(error);
return [];
}
}
scrape()
.then((data) => {
fs.writeFile(
"pokemon.json",
JSON.stringify(data),
"utf8",
(error: Error) => {
if (error) {
console.log("파일 생성 중 에러 발생.");
return console.log(error);
}
console.log("파일 생성 완료!");
}
);
})
.catch((error) => console.log(error));
1. require => import 로 변경
import puppeteer from "puppeteer";
import fs from "fs";
2. interface IPokemon생성
interface IPokemon { id: string; name: string; image: string; type: string; }
3. type지정
async function scrape(): Promise<IPokemon[]>
data: Array<IPokemon>
el: Element
: 안해도 됨.4. null값 방지
const cardId = document.querySelector(".card:last-child .card--id");
return cardId && cardId.textContent === "#100";
if (id && image && name && type)