[nodejs] 프로그래밍을 통한 단어장 만들기 #2 - Medium 파싱
서문
안녕하세요 @wonsama 입니다. 이전 글에 이어 이번 시간에는 medium 사이트 주소만 입력 받으면 해당 컨텐츠를 가져오는 방식으로 동작하도록 구현해 봤습니다.
동작방식
- medium 사이트 주소 입력 받기
- 해당 주소의 정보 scraping
- scraping 된 정보에서 script 부분에 포함된 data parsing
- UI에 해당 정보 display
DONE
- 파일에서 읽기
- 문장에서 단어 추출
- 이미 알고 있는 단어는 추출 제외
ING
- url 정보 입력을 통해 문서 읽기 ( 웹사이트마다 별도 파서가 필요예상 )
- express로 ui 구성하기 ( 모르는 단어 선택을 쉽게 하기 위함 + 웹에서도 동작하도록 )
TODO LIST
- google translate 연동으로 모르는 단어 자동 번역
단어 맞추기 게임 ( 외운 날짜 기준으로 날짜 범위 설정 가능)electron으로 desktop app 형태 만들기
( 생각 날때마다 좀 더 추가예정)
result
결과물을 보면 알 수 있듯이 medium 사이트에서 읽는 것보단 편하게 글만 읽을 수 있게 되었네요 ^^
읽기모드와 유사
source
일단 핵심이 되는 소스만 공개해보면 아래와 같습니다.
[index.js]
let express = require('express');
let router = express.Router();
let request = require('request');
let cheerio = require('cheerio');
/* POST home page. */
router.get('/', function(req, res, next) {
res.render('index', { isLoad : false });
});
/* GET home page. */
router.post('/', function(req, res, next) {
// let url = 'https://medium.com/starts-with-a-bang/we-still-dont-understand-why-time-only-flows-forward-1187a8367d74';
console.log("req.body.inpUrl : ", req.body.inpUrl)
request( req.body.inpUrl, function (error, response, html) {
if (!error && response.statusCode == 200) {
let $ = cheerio.load(html);
let contents = $('script').contents()[7].data;
// console.log( contents );
// [replace] JSON 파싱에서 오류가 발생하여 미리 변경 처리 한다.(유니코드 파싱오류) \x3c <
contents = contents.replace(/\\x3c/g, '<');
let txtStart = 'window["obvInit"]({';
let txtEnd = '"}}}}';
let idxStart = contents.indexOf(txtStart);
let idxEnd = contents.indexOf(txtEnd);
let cutStart = idxStart + txtStart.length -1;
let cutEnd = idxEnd - cutStart + txtEnd.length;
let json = JSON.parse(contents.substr(cutStart, cutEnd));
//- let title = json.value.title;
//- let createdAt = json.value.createdAt;
//- let subTitle = json.value.content.subtitle;
//-
//- let p1 = json.value.content.bodyModel.paragraphs[0]; // type, text, markup
//- type : 1 => 일반글
//- type : 3 => 제목
//- type : 7 => 인용
//- type : 8 => 프로그램 소스
//- type : 9 => 목록
//- type : 4 => 그림 주석
//- type : 11 => 소스 주석
//- type : 13 => 강조글
//- markups
//- type : 1 => 강조
//- type : 2 => 이탤릭
let items = [];
let item = {};
let idx = 1;
for(let para of json.value.content.bodyModel.paragraphs){
if( para.type==3 || para.type==13 ){
if(item.title!=undefined){
items.push(item);
}
item = {};
item.title = para.text;
item.idx = idx;
item.type = para.type;
item.paragraphs = [];
idx++;
}
if( para.type == 1 || para.type == 7 || para.type == 8 || para.type == 9){
item.paragraphs.push({text:para.text, type:para.type});
}
}
items.push(item);
for(let s of json.value.content.bodyModel.paragraphs){
console.log(s);
console.log();
console.log();
}
console.log();
res.render('index', { items : items, isLoad : true });
}
});
});
module.exports = router;
[index.pug]
extends layout
block navtop
a.navbar-brand(href="#") Medium 단어장 v0.1
//- div.collapse.navbar-collapse
div
ul.navbar-nav.mr-auto
li.nav-item.active
a.nav-link(href='#') HOME
span.sr-only (current)
li.nav-item
a.nav-link.disabled(href='#') 학습일지
li.nav-item
a.nav-link.disabled(href='#', data-content='개발예정', data-toggle="popover") 단어목록
form.form-inline(method='post')
div.input-group
div.input-group-prepend
span.input-group-text @url
input.form-control(id="inpUrl", type='text', name='inpUrl' placeholder="medium url")
button.btn.btn-outline-success.my-2.my-sm-0(type='submit') 조회
block container
//- medium 정보를 읽어들였는지 여부
if isLoad
div
each item in items
if item.type == 3
h3(id=`list-item-${item.idx}`)= item.title
else
h5(id=`list-item-${item.idx}`)= item.title
each para in item.paragraphs
if para.type == 7
i "#{para.text}"
br
br
else if para.type == 8
pre= para.text
else if para.type == 9
li= para.text
else
p= para.text
br
button.btn.btn-default.btn-sm(onclick="javascript:$(window).scrollTop(0);")
i.fas.fa-angle-double-up
p TOP
//- medium 정보를 읽어들였는지 여부
else
div @url에 medium 주소 정보를 입력 후 [조회] 버튼을 눌러 주시기 바랍니다.
//- 추가 : 자바스크립트 정의
block append javascript
script(src='/javascripts/index.js')
맺음말
일단 대충 쓸만하게 만드는 것이 목표라 UI나 기능 등이 많이 부족하네요
궁금하시거나 개선사항은 댓글로 피드백 부탁 드립니다.
행복한 하루 보내세요 ~
다음 시간에는 ...
medium 사이트에서 추출 된 컨텐츠 내에서 단어 추출을 연동해 보겠습니다. (아래 참조)
본문 | 추출단어 목록