사이트를 통째로 다운로드
통째로 다운로드하면 뭐가 좋음?
- 사이트가 다운되거나, 인터넷에 연결되지 않은 상태에서도 사이트를 볼 수 있다.
- 로컬에 HTML을 다운로드 해두면 수비게 검색을 수행할 수 있다.
- 사이트 전체를 Database에 저장해 놓고 여러가지 분석을 수행해 볼 수 있다.
링크 따라다니며 다운로드하기
통째로 다운로드 하려면, 톱 페이지의 링크 정보를 바탕으로 HTML을 순회하며 한 페이지씩 내려받아야 한다.
프로그램을 만들어보자
3단계까지 링크 타고 들어가서 HTML 파일을 다운로드 파는 프로그램을 만들어보자
//0203_01_getall.js
// 모듈 로드
var client = require('cheerio-httpcli');
var request = require('request');
var fs = require('fs');
var urlType = require('url');
var path = require('path');
//-----공통 설정---
//링크 탐색 단계 지정
var LINK_LEVEL = 3;
//기준 URL 페이지
var TARGET_URL = "https://nodejs.org/api/";
var list ={};
console.log('start');
// 메인 처리
downloadRec(TARGET_URL, 0);
//지정 URL을 최대 level단계까지 다운로드
function downloadRec(url, level){
//최대 Level 확인
if(level >= LINK_LEVEL) return ;
//이미 다운받은 사이트는 무시
if(list[url]) return;
list[url] = true;
//외부 페이지는 무시
var us = TARGET_URL.split("/");
us.pop();
var base = us.join("/");
console.log(base);
if (url.indexOf(base) < 0) return;
//HTML을 취득
client.fetch(url, {}, function(err, $, res ){
//링크된 페이지를 획득
$("a").each(function(idx){
//<a> 태그의 링크를 획득
var href = $(this).attr('href');
if(!href) return;
// 상대 경로를 절대 경로로 변환
href = urlType.resolve(url, href);
// '#' 이후를 무시(a.html#aa와 a.html#bb는 같다)
href = href.replace(/\$.+$/,""); //말미의 #을 제거
downloadRec(href, level +1);
});
//페이지 저장(파일명 지정)
if(url.substr(url.length-1,1)=='/'){
url += "index.html"; //인덱스 자동 추가
}
var savepath = url.split("/").slice(2).join("/");
checkSaveDir(savepath);
console.log(savepath);
fs.writeFileSync(savepath, $.html());
});
}
//저장할 디렉토리 존재 유무 확인
function checkSaveDir(fname){
//디렉토리 부분만 검출
var dir = path.dirname(fname);
//디렉토리를 재귀적으로 생성
var dirlist = dir.split("/");
var p = "";
for (var i in dirlist){
p += dirlist[i] + "/";
if(!fs.existsSync(p)){
fs.mkdirSync(p);
}
}
}
Node.js의 동기 함수와 비동기 함수
Node.js의 네트워크나 파일 처리 등의 함수는 비동기로 구현되어 있다.
비동기 함수를 호출하면 함수의 처리가 완료된 시점에서 콜백 함수가 호출된다
// 비동기 함수 mkdir
var fs = require('fs');
console.log("mkdir 실행");
fs.mkdir("test", function(){
console.log("폴더 생성 완료");
});
console.log("mkdir 실행 완료. 결과 대기");
동기 함수
// 동기 함수
var fs = require('fs');
//디렉토리를 동기적으로 생성
console.log("mkdir 실행");
if(!fs.existsSync("test3")){
fs.mkdirSync("test3");
console.log("test3 생성완료");
}else{
console.log("test3이 이미 있으므로 생성 안 함");
|
console.log("mkdir 완료");