Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT: 4주차 develop 브랜치 main 브랜치로 병합 #58

Merged
merged 73 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
7cb431b
✨feat: 연관어 크롤링 및 프론트 API 연결 구현
colde99 Jun 21, 2024
66bdd74
Merge branch 'develop' into feat/keyword-crawling
colde99 Jun 22, 2024
eb37b52
Merge pull request #26 from CheatSOL/feat/keyword-crawling
colde99 Jun 22, 2024
05fdf6e
♻️refactor: files-주석 제거
gariguri Jun 22, 2024
8214d04
fix: 영어 검색어일 때 소문자로 변환 후 크롤링 요청
colde99 Jun 22, 2024
0f0e2a8
✨feat: 연관키워드 기준 날짜 fix 및 관련뉴스 api 구현
colde99 Jun 22, 2024
72aa93f
✨feat: PeriodPrice-한투 기간별 주식시세 api 추가
gariguri Jun 22, 2024
3e0ad8f
✨feat: index.js - 한투 기간별 api 라우터 추가
gariguri Jun 22, 2024
89d7d93
✨feat: main.yml - EC2 OS 변경으로 인한 CICD 로직 수정
ShinHeeEul Jun 23, 2024
734925d
✨feat: word2vec_model.model - word2vec_model 강화
ShinHeeEul Jun 23, 2024
00e0d2e
🔧chore: requirements.txt - pip install 버전 변경 및 psycopg2-binary만 사용하도록 변경
ShinHeeEul Jun 23, 2024
441bdd1
♻️refactor: index.js - 불필요한 console 로그 제거
ShinHeeEul Jun 23, 2024
a5742e1
🔧chore: requirements.txt - 불필요한 라이브러리 제거
ShinHeeEul Jun 23, 2024
a7903d7
Merge pull request #29 from CheatSOL/feat/enhanceModel
ShinHeeEul Jun 23, 2024
dc055d9
fix: 연관키워드 페이지 오류 수정
colde99 Jun 24, 2024
e196e00
Merge branch 'develop' into feat/related-keyword-news-api
colde99 Jun 24, 2024
1644511
Merge pull request #31 from CheatSOL/feat/related-keyword-news-api
colde99 Jun 24, 2024
29c0d56
Merge branch 'develop' into feat/stockchart-api
gariguri Jun 24, 2024
14b5e2d
Merge pull request #30 from CheatSOL/feat/stockchart-api
gariguri Jun 24, 2024
b08977f
🐛fix: WSPrice-approvalKeycache코드 추가
gariguri Jun 24, 2024
0b68367
Merge pull request #33 from CheatSOL/fix/ws-data
gariguri Jun 24, 2024
e10615e
feat: instagram 정보 크롤링 및 api 설정
donginLee Jun 24, 2024
f155b19
✨ feat: app.js에 googleNewsRouter 추가 완료
JaeIn1 Jun 24, 2024
1ab1256
✨ feat: 구글 뉴스 크롤링을 위해 rss-parser 설치
JaeIn1 Jun 24, 2024
5ecdd1e
✨ feat: 구글 뉴스 라우터 기능 구현 완료
JaeIn1 Jun 24, 2024
c1df23b
♻️ refactor: 구글 트랜드 api 기능 수정 완료
JaeIn1 Jun 24, 2024
d0a8edf
Merge pull request #36 from CheatSOL/feat/social-google-api
ShinHeeEul Jun 24, 2024
83e91d1
✨ feat: 소셜 페이지 차트 socialChartRouter로 변경 및 youTubeNewsRouter 라우터 추가
JaeIn1 Jun 25, 2024
8a7e257
✨ feat: youtube-node 설치 완료
JaeIn1 Jun 25, 2024
ab91453
✨ feat: google.js 파일 삭제 및 socialChart 파일에 구글 및 유튜브 api 구현 완료
JaeIn1 Jun 25, 2024
e9dccac
✨ feat: 소셜 페이지 유튜브 컴포넌트 검색어에 따른 데이터 api 구현 완료
JaeIn1 Jun 25, 2024
5244029
♻️ refactor: youtube api key값 env파일에 저장
JaeIn1 Jun 25, 2024
3fd9861
Merge pull request #39 from CheatSOL/feat/social-youtube-api
ShinHeeEul Jun 25, 2024
9c482b0
✨feat: app.js - 유튜브 api 라우터 추가
gariguri Jun 25, 2024
0093a0d
✨feat: pakage.json-youtube-node설치
gariguri Jun 25, 2024
e6b38c2
✨feat: Youtube.js-유튜브 api 로직 구현
gariguri Jun 25, 2024
85f541e
Merge branch 'develop' into feat/graphs
donginLee Jun 25, 2024
fd1d102
Merge pull request #41 from CheatSOL/feat/graphs
gariguri Jun 25, 2024
48efd4f
Merge branch 'develop' of https://github.com/CheatSOL/CheatSOL-BE int…
gariguri Jun 25, 2024
5978097
🐛fix: 에러 해결
gariguri Jun 25, 2024
dfc6567
Merge pull request #42 from CheatSOL/feat/total-sns
colde99 Jun 25, 2024
4e61f60
✨ feat: naverNewsRouter 추가 완료
JaeIn1 Jun 26, 2024
4436625
✨ feat: 네이버 뉴스 api 구현 완료
JaeIn1 Jun 26, 2024
2fe997f
✨ feat: 소셜 페이지 네이버 차트 api 구현 완료
JaeIn1 Jun 26, 2024
5a0c3ee
♻️ refactor: 유튜브 키 값 변경 완료
JaeIn1 Jun 26, 2024
2c314e8
Merge branch 'develop' into feat/social-naver-api
JaeIn1 Jun 26, 2024
057eae1
Merge pull request #44 from CheatSOL/feat/social-naver-api
JaeIn1 Jun 26, 2024
3c87ba9
✨feat: youtube-유튜브 크롤링 구현
gariguri Jun 26, 2024
9fa6ceb
Merge pull request #45 from CheatSOL/feat/youtube-crawling
ShinHeeEul Jun 26, 2024
c802d97
✨ feat: 인스타그램 token , uid env파일에 저장
JaeIn1 Jun 26, 2024
b15baf0
Merge pull request #46 from CheatSOL/feat/social-instagram-api
gariguri Jun 26, 2024
af50a9d
✨feat: youtube-크롤링 되돌리기
gariguri Jun 26, 2024
273179f
Merge pull request #47 from CheatSOL/fix/youtube-crawling
ShinHeeEul Jun 26, 2024
720a409
✨feat: 인스타그램 포스트 api 구현
donginLee Jun 27, 2024
8af79e3
Merge pull request #48 from CheatSOL/feat/instagram-news
gariguri Jun 27, 2024
1afceb0
✨feat: files - 캐싱 적용
ShinHeeEul Jun 27, 2024
349ba15
Merge pull request #49 from CheatSOL/feat/cache
gariguri Jun 27, 2024
ac8e475
fix: bin/www - 이거 지우지 마세요!!
ShinHeeEul Jun 27, 2024
b71c47d
Merge pull request #50 from CheatSOL/fix/deletebin
gariguri Jun 27, 2024
23199ff
🐛fix: 중복 유튜브 api 삭제
gariguri Jun 27, 2024
cb75baf
Merge pull request #52 from CheatSOL/fix/youtube.js
ShinHeeEul Jun 27, 2024
ce27cfd
🐛fix: app.js - error youtuberouter 안지워진거 수정
ShinHeeEul Jun 27, 2024
e9e68ec
Merge pull request #53 from CheatSOL/fix/errorfix
gariguri Jun 27, 2024
1542882
✨feat: files - instagram 캐싱 적용
ShinHeeEul Jun 27, 2024
af32d54
Merge pull request #54 from CheatSOL/fix/errorfix
colde99 Jun 27, 2024
3654090
🐛fix: app.js - instaNews 안나오는 현상 수정
ShinHeeEul Jun 27, 2024
caac03a
Merge pull request #55 from CheatSOL/fix/errorfix
colde99 Jun 27, 2024
7f9fae1
♻️ refactor: 네이버 데이터랩 키 값 env파일로 저장
JaeIn1 Jun 27, 2024
a03ca8e
Merge pull request #56 from CheatSOL/feat/naver-key
ShinHeeEul Jun 27, 2024
44d2c30
✨feat: get_similar_words.py - similarity 하드코딩
ShinHeeEul Jun 27, 2024
d87e5ba
♻️refactor: instagram-news - 불필요한 콘솔 제거
ShinHeeEul Jun 27, 2024
eb6c54b
✨feat: main.yml -CICD 파일 수정
ShinHeeEul Jun 27, 2024
5097308
Merge pull request #57 from CheatSOL/fix/lastFix
JaeIn1 Jun 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ jobs:
echo "KIS_APP_KEY=${{ secrets.KIS_APP_KEY}}" >> .env
echo "KIS_SECRECT_KEY=${{ secrets.KIS_SECRECT_KEY }}" >> .env
echo "PORT=${{ secrets.PORT }}" >> .env
echo "INSTA_UID_KEY=${{ secrets.INSTA_UID_KEY }}" >> .env
echo "INSTA_KEY=${{ secrets.INSTA_KEY }}" >> .env
echo "NAVER_ID=${{ secrets.NAVER_ID }}" >> .env
echo "NAVER_SECRET=${{ secrets.NAVER_SECRET }}" >> .env
echo "YOUTUBE_KEY=${{ secrets.YOUTUBE_KEY }}" >> .env
echo "INSTA_IP=${{ secrets.INSTA_IP }}" >> .env

# Build step removed since there is no build script

Expand All @@ -54,7 +60,7 @@ jobs:
key: ${{ secrets.EC2_KEY }}
port: 22
source: "."
target: "/home/ec2-user/CheatSOL-BE"
target: "/home/ubuntu/CheatSOL-BE"

- name: Execute remote commands via SSH
uses: appleboy/ssh-action@master
Expand All @@ -66,18 +72,14 @@ jobs:
script: |
# Install Node.js and pm2 on Amazon Linux
curl -sL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo yum install -y nodejs
sudo npm install -g pm2
sudo apt-get update -y
sudo apt-get install -y nodejs
sudo apt-get install -g pm2
# Navigate to the application directory
cd /home/ec2-user/CheatSOL-BE

# Install Python and pip
sudo yum install -y python3
sudo alternatives --set python /usr/bin/python3
sudo yum install -y python3-pip
cd /home/ubuntu/CheatSOL-BE

# Install project dependencies
npm install --production
npm install
pip install -r requirements.txt
# Restart or start the application with pm2
pm2 stop all
Expand Down
50 changes: 34 additions & 16 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,52 @@ var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
const {wsdata}=require("./src/utils/WSPrice");
const axios = require("axios");
const cheerio = require("cheerio");

// 라우터 추가

const { wsdata } = require("./src/utils/WSPrice");
var indexRouter = require("./src/routes/index");
var companyRouter = require("./src/routes/company");
var googleRouter = require("./src/routes/google");
var stockInfoRouter = require("./src/routes/stock.info.detail");
var socialRouter = require("./src/routes/social");
const db = require("./src/models/DB");
const http=require('http');
var keywordRouter = require("./src/routes/keyword"); //연관검색어 router
var socialChartRouter = require("./src/routes/socialChart");
var stockInfoRouter = require("./src/routes/stock.info.detail");
var googleNewsRouter = require("./src/routes/google-news");
var youTubeNewsRouter = require("./src/routes/youtube-news");
var naverNewsRouter = require("./src/routes/naver-news");
var instaNewsRouter = require("./src/routes/instagram-news");
const http = require("http");
var app = express();
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
const server = http.createServer(app);
const WebSocket = require('ws');
const WebSocket = require("ws");
const wss = new WebSocket.Server({ server });
wss.on('connection', async function connection(ws) {
console.log('새로운 WebSocket 클라이언트가 연결되었습니다.');
wss.on("connection", async function connection(ws) {
console.log("새로운 WebSocket 클라이언트가 연결되었습니다.");
let id;
ws.on('message', (message) => {
ws.on("message", (message) => {
const data = JSON.parse(message);
console.log('Received data:', data);
console.log("Received data:", data);
id = data.id;
if (id) {
wsdata(ws, id); // id가 설정된 후에 wsdata 호출
wsdata(ws, id); // id가 설정된 후에 wsdata 호출
} else {
console.error('ID is undefined');
console.error("ID is undefined");
}
});
});

ws.on('close', function close() {
console.log('WebSocket 연결이 종료되었습니다.');
ws.on("close", function close() {
console.log("WebSocket 연결이 종료되었습니다.");
});
});
server.listen(3002, () => {
console.log('서버가 3002번 포트에서 실행 중입니다.');
console.log("서버가 3002번 포트에서 실행 중입니다.");
});

db.sequelize
Expand All @@ -55,10 +66,17 @@ db.sequelize
console.error("Unable to connect to the database:", err);
});

// 라우터 url 설정
app.use("/api", indexRouter);
app.use("/api/company", companyRouter);
app.use("/api/trends", googleRouter);
app.use("/api/social", socialRouter);
app.use("/api/keyword", keywordRouter);
app.use("/api/trends", socialChartRouter);
app.use("/api/stockInfo", stockInfoRouter);
app.use("/api/news/google", googleNewsRouter);
app.use("/api/news/youtube", youTubeNewsRouter);
app.use("/api/news/naver", naverNewsRouter);
app.use("/api/news/instagram", instaNewsRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
Expand Down
2 changes: 1 addition & 1 deletion bin/www
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,4 @@ function onListening() {
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
"http-errors": "~1.6.3",
"https": "^1.0.0",
"morgan": "~1.9.1",
"nodemon": "^3.1.3",
"nodemon": "^3.1.4",
"pg": "^8.12.0",
"pg-hstore": "^2.3.4",
"python-shell": "^5.0.0",
"rss-parser": "^3.13.0",
"sequelize": "^6.37.3",
"ws": "^8.17.1"
"ws": "^8.17.1",
"youtube-node": "^1.3.3"
}
}
5 changes: 2 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
psycopg2-binary==2.9.9
gensim==4.3.2
pandas==2.2.2
psycopg2==2.9.9
psycopg2-binary==2.9.9
python-dotenv==1.0.1
scipy==1.10.0
scipy==1.12.0
57 changes: 57 additions & 0 deletions src/controllers/CacheController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const db = require("../models/DB");

async function getCache(keyword, social, period) {
try {
const cacheData = await db.Cache.findOne({
where: {
keyword: keyword,
social: social,
period: period,
},
order: [["updatedAt", "DESC"]],
});

return cacheData;
} catch (error) {
console.log("cacheError", error);
return null;
}
}

async function setCache(keyword, social, period, data) {
await db.Cache.create({
keyword: keyword,
social: social,
period: period,
data: data,
});
}

async function updateCache(keyword, social, period, data) {
await db.Cache.update(
{
data: data,
updatedAt: Date.now(),
},
{
where: {
keyword: keyword,
social: social,
period: period,
},
}
);
}

function isExpired(cache) {
if (cache === null || cache === undefined) return true;
const givenDate = new Date(cache.updatedAt);

const expirationDate = new Date(givenDate.getTime() + 24 * 60 * 60 * 1000);

const currentDate = new Date();

return expirationDate < currentDate;
}

module.exports = { getCache, setCache, updateCache, isExpired };
11 changes: 5 additions & 6 deletions src/controllers/NewsCrawling.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const axios=require('axios');
const cheerio=require('cheerio');
const { Model, Op } = require('sequelize');
const { CompanyNews, Company } = require('../models/DB');
const fetchNews = require('../utils/NaverStockNews');
const axios = require("axios");
const cheerio = require("cheerio");
const { Model, Op } = require("sequelize");
const { CompanyNews, Company } = require("../models/DB");
const fetchNews = require("../utils/NaverStockNews");

async function fetchNewsContent(link) {
try {
Expand Down Expand Up @@ -32,7 +32,6 @@ function delay(ms) {
async function saveNewsToDatabase(id, newsItems) {
const newsData = [];

//console.log("newsItems", newsItems);
for (let items of newsItems) {
for (let item of items) {
const link = `https://n.news.naver.com/article/${item.officeId}/${item.articleId}`;
Expand Down
Empty file.
140 changes: 140 additions & 0 deletions src/controllers/social/instagram.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const axios = require("axios");
const cheerio = require("cheerio");

function formatInstagramStyle(input) {
let num = input[0];
let percentage = input[1] * 100;

// 숫자를 적절한 단위로 축약
function formatNumber(number) {
if (number >= 1e6) {
return (number / 1e6).toFixed(1) + "M";
} else if (number >= 1e3) {
return (number / 1e3).toFixed(1) + "K";
} else {
return number.toString();
}
}

// 백분율로 변환
let formattedNum = formatNumber(num);
let formattedPercentage = percentage.toFixed(0) + "%";

return [formattedNum, formattedPercentage];
}

const formatDate = function formatDate(originalDate) {
let year = parseInt(originalDate.slice(2, 4));
let month = parseInt(originalDate.slice(5, 7));
month++;
let ans;
if (month > 12) {
month = 1;
year++;
}
if (month < 10) {
ans = year + ".0" + month;
} else {
ans = year + "." + month;
}

return ans;
};
const getTagId = async function convertWordToTagId(word) {
try {
const { data } = await axios.get(
`
https://moana.mediance.co.kr/v1/instagram-tags/find?keyword=${encodeURI(
word
)}&uid=${process.env.INSTA_UID_KEY}&ip=${process.env.INSTA_IP}`,
{
headers: {
Authorization: process.env.INSTA_KEY,
},
}
);
console.log("Daa:", data);
return data.id;
} catch (error) {
console.error("Error fetching tag ID:", error);
}
};

const getTags = async function getHotHashTags(word) {
try {
const { data } = await axios.get(
`https://moana.mediance.co.kr/v1/instagram-tags/find?keyword=${encodeURI(
word
)}&ip=${process.env.INSTA_IP}&uid=${process.env.INSTA_UID_KEY}`,
{
headers: {
Authorization: process.env.INSTA_KEY,
},
}
);
// console.log("xdata);/
return data.instagramTag.instagramTagTree.engagementTags;
} catch (error) {
console.error("Error fetching hotTags data:", error);
}
};
const getTrend = async function getTrendWithTagId(id) {
try {
const { data } = await axios.get(
`https://moana.mediance.co.kr/v1/instagram-tags/${id}/series-summary`,
{
headers: {
Authorization: process.env.INSTA_KEY,
},
}
);

const trend = data.data.map((item) => {
return { date: formatDate(item.statOn), posts: item.postCount };
});

return trend;
} catch (error) {
console.error("Error fetching trend data:", error);
}
};

const getTagInfo = async function getTagInfo(id) {
try {
const { data } = await axios.get(
`https://moana.mediance.co.kr/v1/instagram-tags/${id}/summary?ip=${process.env.INSTA_IP}}`,
{
headers: {
Authorization: process.env.INSTA_KEY,
},
}
);

return formatInstagramStyle([
data.postCount,
data.instagramTag.instagramTagStat.engagementAvg /
data.instagramTag.instagramTagStat.occupyTimeAvg,
]);
} catch (error) {
console.error("Error fetching or parsing data:", error);
return null;
}
};
const getInstagramInfo = async function scrapingInstagramSocialInfo(word) {
try {
const id = await getTagId(word);
if (id) {
const trendData = await getTrend(id);
const topTags = (await getTags(word)).slice(0, 3);
const tagInfo = await getTagInfo(id);

return { id, trendData, topTags, tagInfo };
} else {
console.log("No ID found for the given word.");
}
} catch (error) {
console.error("Error in instagramInfo function:", error);
}
};

module.exports = { getInstagramInfo };
Empty file added src/controllers/social/naver.js
Empty file.
Loading