백만년만의 2탄
이제 NODE코드를 짜는 일만 남았다.
대충만 생각해도 axios로 크롤링 해와서 cheerio로 필요한 부분만 입맛에 맞춰 저장해주면 끝날 일이니깐
우선 egloos의 태그 부터 분석해봤다.
우선 최신글 기준으로 작업을 하면서 레이아웃은 버리고 제목부터 시작되는 본문을 가져오면 되겠거니 싶었다
다만 이때 간과했던게 스킨의 존재
내 이글루 기준으로만 구상을 하니 스킨에 따라 태그가 미세하게 다를거란 생각은 하질 못했었다...
일단 추후엔 그 모든걸 if 처리해서 어떻게든 했다...
개발자 툴로 대충 훑으니 id가 section_content인 div안에 본문 관련 태그가 다 들어있는걸 발견했고
GPT에몽~
사실 쌩 노드로 코드를 짜본 적이 없...진 않지만 DB까지 포함된 작업을 해본 적은 없어서 chat gpt가 있어서 시간이 엄청 절약 됐다 정말 시간은 금인 이 시대의 구세주라 할 수 있겠다
대충 초안을 짜줘서 테스트 하며 코드를 고쳐보고 다시 물어보고 (그런 와중에 mysql 라이브러리는 mysql2로 진화했다)
그렇게 완성을 시켰다
이하 gpt가 짜주신 초안
const axios = require('axios');
const cheerio = require('cheerio');
const mysql = require('mysql');
// MySQL DB 접속 정보
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'my_database'
});
// DB 연결
connection.connect();
// 크롤링할 페이지 URL
const url = 'http://guramori.egloos.com/2673827';
// 페이지 HTML을 가져와서 Cheerio로 파싱
axios.get(url).then((response) => {
const $ = cheerio.load(response.data);
// 포스트 정보 파싱
const postAuthor = $('span.post_info_author').text();
const postTitleCategory = $('h2.post_title_category').text().split('::');
const postTitle = $('h2.post_title a').text();
const postContent = $('div.hentry').html();
const postDate = $('span.post_info_date').text();
const postCommentCount = $('span.post_info_cmtcount').text();
const postTagList = $('div.post_taglist a').map(function() {
return $(this).text();
}).get();
// DB에 데이터 삽입
const category = {
writer: postAuthor,
title: postTitleCategory[1].trim()
};
connection.query('INSERT INTO category SET ?', category, (error, results, fields) => {
if (error) throw error;
const post = {
category_id: results.insertId,
writer: postAuthor,
title: postTitle,
content: postContent,
reply_count: postCommentCount,
reg_date: postDate
};
connection.query('INSERT INTO posts SET ?', post, (error, results, fields) => {
if (error) throw error;
for (const tag of postTagList) {
const tagData = {
title: tag
};
connection.query('INSERT IGNORE INTO tag SET ?', tagData, (error, results, fields) => {
if (error) throw error;
const postAndTag = {
posts_post_id: results.insertId,
tag_tag_id: results.insertId
};
connection.query('INSERT INTO post_and_tag SET ?', postAndTag, (error, results, fields) => {
if (error) throw error;
});
});
}
});
});
}).catch((error) => {
console.log(error);
});
// DB 연결 종료
connection.end();
이 초안이 문제없이 실행이 되던가는 기억이 안난다...아마 바로 아래에 댓글까지 저장하는 소스로 다시 짜달라 한 걸 보면 사용은 안했던 거 같긴하다...
일단 이것만으론 원하는 형태가 나오질 않아서 이 시점에서 다시 프로세스를 정리해봤다.
db에 본문 데이터를 저장하면서 img태그의 이미지가 이글루스에 업로드한 이미지라면 그 이미지를 다운받고 경로를 로컬경로로 바꿔 저장을 해줘야 하고 포스트 하나 작업이 끝나면 다음 포스트로 넘어가서 또 반복해주고...
대충 이글루 하나 백업하는데 필요한 과정은 이정도면 충분할듯
가장 중요한 이미지 저장쪽을 우선 제작해야했다
이미지 다운로드 소스는 전에 쓰던게 있어서 그걸 사용하면 됐지만 이글루스는 본문에 있는 이미지를 썸네일 버전으로 다운시킨 이미지로 보여줘서 그 부분을 우선 해결해야했다.
다행히 썸네일주소에 원본 주소가 고대로, 진짜 고대~로 들어있었다.
GPT에몽 더러운 정규식을 짜줘!
라는 소리다
우리 gpt 선생님은 아쉽게도 완전히 이해하지는 못해서 좀 더 구체적으로 말해줘서 답을 받아냈다
두번 정도 물어서 대충 대답을 받아낸듯
그리고 img태그를 반복시켜서 폴더에 저장해주고 본문의 img의 src 경로를 수정해주는 작업을 부탁했다.
뭐 이렇게 대충 물어물어 귀찮은 작업은 다 맡기고 대충 손대서 내 초안을 완성시켰다
const start = async (postNumber) => {
// Create MySQL Connection
const connection = await mysql.createConnection({
host: 'localhost',
user: '',
password: '',
database: 'egloos',
charset: 'utf8mb4'
});
try {
const url = `http://guramori.egloos.com/${postNumber}`;
const response = await axios.get(url).then(res => res.data).catch(er => er.response.data);
const html = response;
const $ = cheerio.load(html);
// Find the post content
const postTitle = $('.entry-title > a').text().trim();
const postContent = $('div.post_content .hentry');
// Find the post info
const postInfoAuthor = $(".post_info_author").text().replace("by", "").trim();
const postInfoDate = $('.post_info_date').text().trim();
const postInfoCmtCount = $('.post_info_cmtcount').text().trim().replace(/\D/g, '');
const postCategory = $('.post_title_category a').text().trim();
// Insert into category table
const imgs = $('div.post_content .hentry img')
if (!fs.existsSync('./img')) {
fs.mkdirSync('./img');
}
for (const img of imgs) {
const oldSrc = $(img).attr('src');
if (oldSrc.includes('http://pds')) {
const newSrc = 'http://pds' + oldSrc.split('http://pds')[1];
const slashSplit = newSrc.split("/");
const fileName = slashSplit[slashSplit.length - 1]
const imgPath = path.join(__dirname, 'img', fileName);
$(img).attr('src', imgPath);
await downloadImage(newSrc, imgPath);
}
}
const [categoryRe] = await connection.query(
`INSERT INTO category (writer, title) VALUES (?, ?) ON DUPLICATE KEY UPDATE category_id=LAST_INSERT_ID(category_id)`,
[postInfoAuthor, postCategory.length >= 1 ? postCategory : "미분류"]
);
// Get the category ID
const categoryId = categoryRe.insertId
// Insert into posts table
const [postRe] = await connection.query(
`INSERT INTO posts (category_id, writer, title, content, reply_count, reg_date) VALUES (?, ?, ?, ?, ?, ?)`,
[categoryId, postInfoAuthor, postTitle, postContent.html(), postInfoCmtCount, postInfoDate]
);
// Get the post ID
const postId = postRe.insertId;
// Find the post tags
const postTagList = $('div.post_taglist');
const tagLinks = postTagList.find('a');
connection.end()
const atag = $(".post_navi .next > a")
if (atag.text()) {
start($(".post_navi .next > a").attr("href"));
} else {
return;
}
} catch (er) {
console.log(er)
}
}
길어서 부분부분 잘랐다( 이미지 다운, 댓글,태그 저장 )
95%는 챗gpt의 소스다 많은 도움이 된다...
카테고리가 미분류인 포스팅의 경우는 카테고리명이 아예 표시가 안되기도 하는데 그럴땐 카테고리를 미분류로 넣어주게 했다.
파싱해오면 우선 이미지부터 저장&경로 변경을 해준다.
근데 저대로 돌리면 상대경로가 아닌 절대경로로 저장이 돼서 추후에 소스는 조금 수정해줬다(무식한 방법으로)
다음은 카테고리를 저장하는데 카테고리명과 해당 글의 작성자명으로 유니크값을 정해서 중복은 저장이 안되게 했고 던져주는 결과값에서 id를 빼와서 포스트 저장할때 사용했다.
다만 실수였던게 닉네임이 바뀔 수 있단걸 생각을 못해서 같은 이글루임에도 중복되는 카테고리가 여럿 들어가게 됐다
다행히 내 이글루가 실험체1호인 덕에 큰 문제는 없이 고칠 수 있었다
...애초에 닉을 바꿔댄건 나뿐이더라
그 후 해당 카테고리 아이디를 가지고 포스트를 저장, 저장시 reg_date는 실제 저장된 시간을 하고 포스트 작성 시간을 따로 저장해줄지, 포스트 작성 시간만 박아줄지 고민하다가 굳이 실제 저장 시간이 있을 이유가 없어서 포스트 작성 시간을 넣어줬다.
다만 태그인지 리플인지는 그걸 따로 저장해 버렸다
실수인지 실험인지...
대충 문제없이 저장되면 다음( 최신 포스트 기준이니 실제로는 이전 ) 포스트를 가르키는 a태그를 찾아 재귀한다
이렇게 초안이 완성됐다
이걸로 우선 내 이글루는 대충 db에 박아넣는 건 성공했다
그 후 다른 이글루를 저장하는 과정에서 상기한 스킨 문제에 직면하고 이래저래 코드를 만져서 어떻게든 헤쳐나갔다...
그 후 html파일로 저장, 해당 스킨의 css, js 다운 등의 기능을 추가하여 몇몇 분들에게 제공하였다
3탄은 그에 대해 써보자
'개발관련' 카테고리의 다른 글
북클럽 스킨 수정 - 현재 페이지의 카테고리 구별 표시 (0) | 2023.06.23 |
---|---|
이글루스 백업 코드 제작기 - 3 (5) | 2023.06.22 |
곧장 기부 사이트 크롬 확장 프로그램 개발 (3) | 2023.06.21 |
이글루스 - 티스토리 이전 관련 한 문제점 (0) | 2023.06.21 |
이글루스 백업 코드 제작기 - 1 (1) | 2023.06.21 |
댓글