최원석
Committed by GitHub

Merge pull request #11 from goesnow/goesnow

Goesnow
......@@ -7,6 +7,9 @@ crawler/chromedriver
crawler/chromedriver.exe
**/*.exe
package-lock.json
__pycache__/
**/__pycache__/
*.pyc
**/build/
public
......
......@@ -2,12 +2,32 @@
Lookup ID, and Compare!
<span style="font-size:24px;">SPA</span> with <span style="font-size:16px;">Vanilla Typescript</span>
and <span style="font-size:24px;">Page Transitions</span> with <span style="font-size:16px;">Scss</span>
and <span style="font-size:24px;">Instagram Crawler</span> with <span style="font-size:16px;">Python</span>
---
### Using ...
- Typescript
- Webpack
- Scss
- Flask
## Execute server
listing for __*localhost:8080*__
```shell
python -m pipenv shell
python server.py
```
or
> just run server with **Pycharm**
## Execute only frontend
[link](https://github.com/1Seok2/check-your-instagram/tree/master/app)
......
No preview for this file type
......@@ -26,6 +26,8 @@
"file-loader": "^6.2.0",
"gts": "^3.1.0",
"html-webpack-plugin": "^5.3.0",
"node-sass": "^5.0.0",
"sass-loader": "^11.0.1",
"style-loader": "^2.0.0",
"ts-loader": "^8.0.17",
"typescript": "^4.0.3",
......
......@@ -6,19 +6,20 @@
* 컴포넌트 제작 후 반환
**/
import Header from "./views/header/Header";
import Body from "./views/body/Body";
import Footer from "./views/footer/Footer";
import Header from "./views/header";
import Body from "./views/body";
import Footer from "./views/footer";
import './assets/style/App.scss';
import './assets/style/PageTransition.scss';
const App = (pathname : string) : string => {
history.pushState('','', pathname);
return `
<div>
<div class="container">
${Header()}
${Body(pathname)}
${Footer()}
<a href="/wonseog" id="nav-button" data-link>wonseok!!</a>
</div>
`;
}
......
body{
background-color: beige;
}
\ No newline at end of file
body {
margin: 0;
padding: 0;
}
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 250px;
min-height: 500px;
width: 100%;
height: 100%;
}
\ No newline at end of file
.body {
border: 1px solid gray;
width: 100%;
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
\ No newline at end of file
.footer {
height: 50px;
background-color: #afafaf;
display: flex;
justify-content: center;
align-items: center;
font-size: .8rem;
width: 100%;
color: #fafafa;
}
\ No newline at end of file
.header {
height: 70px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.8rem;
width: 100%;
}
\ No newline at end of file
@keyframes page-initial-bottom {
0%{
opacity: 1;
background-color: white;
}
100%{
opacity: 0;
background-color: white;
}
}
@keyframes page-blink-bottom {
0%{
opacity: 0;
top: 50%;
left: 50%
}
40%{
opacity: 1;
left: 50%;
}
50%{
left: 50%;
}
100%{
opacity: 1;
left: -70%;
}
}
@keyframes page-top-left {
0%{
left: 50%;
top: 170%;
}
50%{
top: 50%;
left: 50%;
}
100%{
top: 50%;
left: -70%;
}
}
.page-transition {
width : 120%;
height: 120%;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
background-color: #353535;
z-index: 1;
display: none;
&.transition-0 {
animation: ease-in-out 1.2s page-initial-bottom;
}
&.transition-1 {
animation: ease-in-out 2.4s page-blink-bottom;
}
&.transition-2 {
animation: ease-in-out 2.4s page-top-left;
}
}
\ No newline at end of file
/**
* @author : wonseog
* @date : 2021/03/09
* @description : 페이지 이동 효과 주는 함수
**/
let $div : HTMLDivElement | null;
const pageTransitionClassList = [
"transition-0",
"transition-1",
"transition-2"
]
const getDivs = () : HTMLDivElement | null => document.querySelector('.page-transition');
const turnOnAndOff = (idx : number)=>{
$div && (()=>{
$div.classList.toggle(pageTransitionClassList[idx]);
$div.style.display = 'block';
setTimeout(()=>{
$div && (()=>{
$div.style.display = 'none';
$div.classList.toggle(pageTransitionClassList[idx]);
})()
},idx === 0 ? 1000 : 2400);
})()
}
export const initialTrantition = () => {
$div = $div || getDivs();
$div && turnOnAndOff(0);
}
export const randomTransition = () => {
$div = $div || getDivs();
const randomIndex = Math.floor(Math.random()*(pageTransitionClassList.length - 1) + 1);
$div && turnOnAndOff(randomIndex);
}
\ No newline at end of file
export const BASE_URL = 'http://localhost:5000/';
export const BASE_URL = 'http://localhost:8080/';
......
......@@ -4,6 +4,7 @@
<base href="/" />
<meta charset="UTF-8">
<title>home</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="App"></div>
......
......@@ -3,20 +3,47 @@
* @date : 2021/03/08
* @description : 현재 pathname을 파악 후 App으로 전달
**/
import App from './App';
import {BASE_URL} from './config/url';
import {initialTrantition, randomTransition} from "./components/pageTransition";
import {setState} from "./state/state";
window.addEventListener('DOMContentLoaded', () => {
/* add div for page transitions */
(()=> {
const $div = document.createElement('div');
$div.className = "page-transition";
document.body.appendChild($div);
initialTrantition();
})();
const $App = document.querySelector('#App');
const pathname = window.location.pathname.split('/')[1];
/* change url */
window.addEventListener('popstate', ()=>{
$App && ($App.innerHTML = App(pathname));
});
/* initial render */
$App && ($App.innerHTML = App(pathname));
document.body.addEventListener('click', async (e) => {
e.stopPropagation();
/* add navigation click event */
if((e.target as HTMLAnchorElement).matches("[data-link]")){
const href = (e.target as HTMLAnchorElement).href.split(BASE_URL)[1];
const href : string= (e.target as HTMLAnchorElement).href.split(BASE_URL)[1];
e.preventDefault();
setTimeout(()=>{
$App && ($App.innerHTML = App(href));
} else if((e.target as HTMLAnchorElement).id === 'update-button') {
},1200);
randomTransition();
}
/* add POST event for button */
else if((e.target as HTMLAnchorElement).id === 'update-button') {
let result: any= null;
const insta_id = (document.querySelector('#id-input') as HTMLInputElement).value;
......@@ -26,16 +53,15 @@ window.addEventListener('DOMContentLoaded', () => {
} catch (e){
console.log(e);
} finally {
console.log(result)
result && $App && ($App.innerHTML = App('main'))
console.log(result);
result && $App && (()=>{
$App.innerHTML = App('main');
setState({insta_id : insta_id});
})();
}
} else {
alert('아이디를 입력하세요');
}
}
});
window.addEventListener('popstate', ()=>{
$App && ($App.innerHTML = App(pathname))
});
$App && ($App.innerHTML = App(pathname));
})
\ No newline at end of file
......
export {default} from './state';
......@@ -11,7 +11,7 @@ export interface StateType{
following? : Array<string>
}
export const state: StateType ={
const state: StateType ={
insta_id : '',
followers : [''],
following : [''],
......@@ -21,3 +21,5 @@ export const setState = (newState: StateType): StateType =>({
...state,
...newState
});
export default state;
......
......@@ -4,21 +4,24 @@
* @description : 페이지 내용
**/
import Home from "./contents/Home";
import '../../assets/style/Body.scss';
const Body = (pathname: string) : string => {
let contentsContainer = '';
switch (pathname){
case 'compare':
/* 팔로워, 팔로잉 비교*/
break;
case 'main':
/* 아이디 조회 후 */
break;
default:
contentsContainer = Home();
}
return `
<div class="Body">
<div class="body">
${contentsContainer}
</div>
`;
......
......@@ -4,7 +4,7 @@
* @description id 입력하는 메인 화면
* 조회 / 업데이트
**/
import {state} from "../../../state/state";
import state from "../../../state";
import Title from "../../../components/title";
const Home = (): string =>{
......
export {default} from './Body'
\ No newline at end of file
......@@ -4,10 +4,12 @@
* @description : 페이지 푸터
**/
import '../../assets/style/Footer.scss'
const Footer = () : string => {
return `
<div class="Footer">Its my Footer</div>
<div class="footer">Its my Footer</div>
`;
}
......
export {default} from './Footer'
\ No newline at end of file
......@@ -5,6 +5,7 @@
**/
import Title from "../../components/title";
import '../../assets/style/Header.scss'
const Header = () : string => `
<div class="header">
......
export {default} from './Header'
\ No newline at end of file
......@@ -15,8 +15,8 @@ module.exports = {
exclude: /node_modules/,
},
{
test : /\.css$/,
use: ['style-loader', 'css-loader'],
test : /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|gif|jp2|webp)$/,
......
No preview for this file type
No preview for this file type
No preview for this file type
......@@ -17,12 +17,21 @@ firebase = pyrebase.initialize_app(config)
db = firebase.database()
def update_data(user_insta_id ,followers, followings):
insta_id = user_insta_id.replace('_','').replace('.','')
data = {
"followings" : followings,
"followers" : followers
}
def id_encrypt(user_insta_id):
return user_insta_id.replace('_', '1z1').replace('.', '2z2')
def update_data(user_insta_id, data):
insta_id = id_encrypt(user_insta_id)
db.child("insta").child(insta_id).update(data)
def get_data_by_id(user_insta_id):
insta_id = id_encrypt(user_insta_id)
data = db.child("insta").child(insta_id).get()
return data.val()
......
No preview for this file type
No preview for this file type
......@@ -3,7 +3,7 @@ from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from config.admin import ID, PW, LOCAL_PROJECT_PATH
from config.URLs import INSTAGRAM_URL
# from config.firebase import update_data
from config.firebase import update_data
def check_people(driver, type):
result = []
......@@ -43,7 +43,12 @@ def get_list(insta_id, driver):
following_list = check_people(driver, "following")
# update at firebase
# update_data(insta_id, followers_list, following_list)
data = {
"followers" : followers_list,
"followings" : following_list,
"insta_id" : insta_id
}
update_data(insta_id, data)
def crawler_instagram(insta_id):
......@@ -64,10 +69,9 @@ def crawler_instagram(insta_id):
isPrivate = ""
pass
# 비공개 계정인 경우
# account is private
if isPrivate:
print('private!!')
# 공개 계정인 경우
else:
get_list(insta_id, driver)
......
......@@ -5,16 +5,14 @@ googleapis-common-protos==1.52.0
httplib2==0.19.0
itsdangerous==1.1.0
Jinja2==2.11.3
jws==0.1.3
MarkupSafe==1.1.1
oauth2client==3.0.0
protobuf==3.15.2
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycryptodome==3.4.3
pyparsing==2.4.7
Pyrebase==3.0.27
python-jwt==2.0.1
Pyrebase4==4.4.3
requests==2.11.1
requests-toolbelt==0.7.0
rsa==4.7.2
......
import os
from flask import Flask, render_template, request, jsonify, send_from_directory
from crawler.crawler_instagram import crawler_instagram
from config.firebase import get_data_by_id
# my_path = '/Users/choewonseog/Documents/check-your-instagram/app/public'
# my_path = 'C:/Users/goesnow/Documents/study/check-your-instagram/app/public'
root_dir = os.path.dirname(os.getcwd())
my_path = os.path.join(root_dir, 'check-your-instagram', 'app', 'public')
......@@ -11,14 +10,29 @@ app = Flask(__name__, static_folder=os.path.abspath(my_path))
def update(insta_id):
result = 'ok'
try:
crawler_instagram(insta_id)
except Exception as e:
print(e)
result = 'fail'
data = {
"insta_id" : insta_id
"result" : result
}
return jsonify(data)
def search(insta_id):
result = {}
try:
result = get_data_by_id(insta_id)
except Exception as e:
print(e)
return jsonify(result)
@app.errorhandler(404)
def page_not_found():
return render_template('404.html')
......@@ -27,10 +41,12 @@ def page_not_found():
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def home(path):
if path == 'update':
insta_id = request.args.get('insta_id')
if path == 'update':
return update(insta_id)
elif path == 'search':
return search(insta_id)
else:
return send_from_directory(my_path, filename='index.html')
......@@ -39,4 +55,4 @@ if __name__ == "__main__":
print(" server is start")
print("-" * 60)
app.run(debug=True)
app.run(host="localhost", port=8080, debug=True)
......
<!DOCTYPE html>
<html>
<head>
<title>check insta</title>
</head>
<body>
<h1>메인 화면</h1>
<input id="insta_id" placeholder="id" type="text" name="insta_id"/>
<button id="submit_id">제출</button>
<script>
const button = document.querySelector('#submit_id')
const input = document.querySelector('#insta_id')
button.addEventListener('click',async () => {
let result = null;
try {
result = await (await fetch('http://localhost:5000/update?insta_id=' + input.value)).json()
} catch (e) {
console.log(e)
} finally {
if(result) {
console.log(result.insta_id)
}
}
})
</script>
</body>
</html>
\ No newline at end of file