728x90

 

 

서론


안녕하세요 앞으로 Flutter에 대해 공부하도록 하겠습니다.

 

Flutter는  앱 뿐만아니라 웹페이지,윈도우 데스크탑 프로그램도도 만들수있으며

배우기 쉽고, 개발언어가 구글에서 만든 Dart언어인데 앱개발시 Dart언어 단 하나만 배우면 된다는 장점이있습니다.

 

글을 읽기 전에 저는 컴공과에 재학중인 대학생입니다. 따라서 글에 틀린부분이 있을수 있다는점 양해 부탁드립니다.

 

 

 

설치


https://flutter-ko.dev/docs/get-started/install/windows#

 

윈도우에서 설치

 

flutter-ko.dev

 

이 사이트에 들어가서 Flutter SDK를 다운받아야되는데 저같은경우 다운로드 버튼이 Failed로 돼있어서 다운로드가 불가능하였습니다.

해결방법은 플러터 공식사이트https://flutter.dev/ 로 접속해서 다운받는 방식입니다...(간단)

 

그 후 환경변수에 들어가셔서  Path에 추가해주셔야 되는데

flutter에서 압축을 해제하여 flutter폴더에있는 bin폴더의 경로를 추가해주면됩니다.

 

그 후 안드로이드 스튜디오는 설치되어있다고 가정하고

 

안드로이드 스튜디오에서 flutter 플러그인 설치하시면 끝입니다.

 

설치과정을 영상으로 자세히 보고싶으신분은 코딩애플님의 영상을 추천드립니다.

 

https://www.youtube.com/watch?v=JS-Si5GO3iA 

 

실습


1. Hello World ! 

 

- Flutter에서는 화면을 그리는 모든 디자인 요소를 위젯(Widget)이라고 함

 

플러터는 lib/main.dart가 메인 화면입니다.

코딩의 시작 Hello World를 화면에 표시하고싶으시면

 

#appbar의 title은 Welcome to Flutter
#center의 text는 Hello World로 바꾼 코드 

Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

 

 

2. 외부 패키지 이용하기

 

플러터의 의존성은 pubspec.yaml파일이 담당합니다.

 

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  english_words: ^3.1.0

cupertino는 UI가 IOS스러운 앱을 만들때 사용하는 디자인

종속성을 추가해준다음 Pub get을 해줘야함

 

패키지를 가져올때 import 를 사용함.

lib/main.dart 파일에 다음과같이 패키지를 가져와준다

import 'package:english_words/english_words.dart';

 

 

"Hello World" 문자열출력대신 English words를 사용하여 텍스트를 생성해보도록 합시다.

 

@override
Widget build(BuildContext context) {
  final wordPair = WordPair.random();
  return MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text('Welcome to Flutter'),
      ),
      body: Center(
        child: Text(wordPair.asPascalCase),
      ),
    ),
  );
}

 

Stateful 위젯 추가하기

 

Stateless 위젯은 모두 변경불가능함. 즉 모든값이 final 이다.

 

Stateful 위젯은 위젯의 수명동안 변경될 수 있는 상태를 유지합니다. Stateful 위젯은 최소 두 개 이상 클래스가 필요합니다: 1) StatefulWidget 클래스가 2) State 클래스 의 인스턴스를 생성합니다. StatefulWidget 클래스 그자체는 변경불가능합니다. 하지만 State 클래스가 위젯의 수명동안 상태를 유지합니다.

 

앱의 수명동안 변경될수있는 위젯 RandomWords를 추가하고 그위젯에서 State클래스인 RandomWordsState를 생성할것이다. 그 후 RandomWords를 기존 Stateless위젯 MyApp 의 자식으로 사용될 것임

 

 

class RandomWordsState extends State<RandomWords> {
  // TODO Add build() method
}

 

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

 

Randomwordsstate 수정

class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}

 

 

전체코드

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_plugin2/flutter_plugin2.dart';
import 'package:english_words/english_words.dart';

void main() {
  runApp(const MyApp());
}



class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}



class _MyAppState extends State<MyApp> {


  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      platformVersion =
          await FlutterPlugin2.platformVersion ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Center(
          child: RandomWords(),
        ),
      ),
    );
  }
}

class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

 

 

이렇게 코드를 짜시면 앱이 실행될때마다 중앙화면에 영단어가 랜덤으로 출력됩니다.

 

리스트뷰를 이용한 랜덤 영단어 생성기

 

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_plugin2/flutter_plugin2.dart';
import 'package:english_words/english_words.dart';

void main() {
  runApp(const MyApp());
}



class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}



class _MyAppState extends State<MyApp> {


  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      platformVersion =
          await FlutterPlugin2.platformVersion ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My Project01'),

        ),
        body: RandomWords(),
      ),
    );
  }
}

class RandomWordsState extends State<RandomWords> {

  final _suggestions = <WordPair>[];
  final _biggerFont = const TextStyle(fontSize:18.0);

  Widget _buildSuggestions() {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: /*1*/ (context, i) {
          if (i.isOdd) return Divider(); /*2*/

          final index = i ~/ 2; /*3*/
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10)); /*4*/
          }
          return _buildRow(_suggestions[index]);
        });
  }

  Widget _buildRow(WordPair pair) {
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Scaffold(

      body: _buildSuggestions(),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

 

 

본글은 

https://flutter-ko.dev/docs/get-started/codelab  를 참고하여 작성함

728x90
728x90

실습은 리눅스 Ubuntu 가상환경에서 진행됩니다. 

 

 

SCAPY 란?


Scapy는 패킷 조작 프로그램으로 다양한 프로토콜의 패킷을 생성/전송/캡처 작업을 수행할수 있으며

hping,nmap의 85% arpspoof, arp-sk, tcpdump, tethereal, p0f등을 대체 할수있습니다.

 

 

Scapy 설치페이지


https://scapy.readthedocs.io/en/latest/

 

Welcome to Scapy’s documentation! — Scapy 2.4.5. documentation

© Copyright 2008-2021 Philippe Biondi and the Scapy community. Revision 7e161f1d.

scapy.readthedocs.io

 

실습을 위한 기본 개념 + Scapy 실습 환경 구축


스캔(Scan): 서버의 작동 여부와 서버가 제공하는 서비스를 확인

 

 

국내에서 스캐닝은 불법입니다. 절대로 공개되어 있는 IP/도메인에 대해 스캐닝하면 안됨

제48조(정보통신망 침해행위 등의금지) 

 

Scapy 실습 환경 구축(리눅스 환경 cmd)

> sudo apt-get update

> sudo apt-get upgrade

> sudo scapy

> sudo apt-get install scapy

> sudo apt-get upgrade scapy

 

#기본명령어

ls() # Layer 리스트 보여줌

ls(TCP)  #TCP header 구조

ls(IP) #IP header 구조

lsc() #scapy 명령어/함수리스트 

conf #환경설정

sniff() #패킷 스니핑

str() #문자열 정보보기

hexdump() #16진수 코드보기

traceroute("naver.com") #hop 추적

 

 

Scapy 실습(패킷 생성과 전송)


CMD에서 scapy 명령어를 통해 scapy실행

 

 

 

frame=Ether()/IP()/TCP()/Raw(load="heelo")

frame.show()

frame=Ether()/IP(ttl=20)/TCP()/Raw(load="hi")

frame.show()

str(frame) #16진수 문자열출력

hexdump(frame) #16진수 덤프

 

#SYN/ACK Packet 
> pkt =IP(dst="192.168.122.101")/TCP(dport=80,flags="SA)

#ICMP Packet
pkt = IP(dst=192.168.122.101")/ICMP(code=1,type=3)

#icmp packet , echo request packet
mypkt = IP(dst=192.168.122.101")/ICMP(code=0,type=8)

mypkt.summary()#패킷 한줄요약
mypkt.show()#패킷정보출력

#캡처한 패킷을 pcap 쓰기
wrpcap("file1.pcap", mypkt)
a = rdpcap("file1.pcap") #읽기
728x90
728x90

DoS(Denial of Service atack) : 혼자 쏘는 Dos공격

 

▶한 명 또는 그 이상의 사용자가 1개의 시스템의 리소스를 독점하거나 파괴함으로써

시스템 또는 서비스의 정상적인 운영을 할 수 없게 만드는 공격

 

▶시스템파괴, 시스템 자원 및 네트워크 자원 고갈

 

DDoS : 분산 Dos 공격

 

▶ Dos 공격의 일종 여러 대 공격자를 분산적으로 배치하여 동시에 DoS공격

▶ 여러 대의 컴퓨터를 일제히 동작하게 하여 특정사이트를 공격하는 방식

 

 

DoS공격 개념

 

▶ 자원 고갈형 

ex) SYN Flooding , Ping of Death , L7 Application공격(http get flooding)

 

▶ OS 또는 서버 프로그램, 네트워크 프로토콜의 취약점을 이용한 Dos

Land attack , Ping of Death Attack , Teradrop Attack

 

▶ Route 경로 조작

ICMP Router Discovery Attack

 

▶ Bandwidth 잠식형

Smurf Attack , UDP Diagnostic Port Denial service attack

 

SYN Flooding : 서버 자원의 리소스를 고갈시키는 공격

 

'SYN Received' 상태로 ACK 패킷을 기다리는것을 'BACKLOG에 빠졌다' 라고 말함

 

SYN FLOODING 과정

1. 공격자는 많은 숫자의 SYN패킷을 서버에 전송

2. 서버는 받은 SYN 패킷에 대한 SYN/ACK 패킷을 각 클라이언트로 보냄

3. 서버는 자신이 보낸 SYN/ACK 패킷에 대한 ACK패킷을 받지못함

4. 서버는 세션의 연결을 기다리게 되고 공격은 성공

 

SYN FLOODING 보안대책 -> 시스템 패치설치, 침입 차단,탐지 시스템 설치, IP주소 대역 차단, SYN_COOKIE 이용

 

 

Boink, Bonk, Teardrop : TCP 프로토콜의 오류제어를 이용한 공격

 

Bonk : 처음 패킷을 1번으로 보낸후 두번째와 세번째 패킷의 시퀀스 넘버를 모두 1번으로 조작해서 보냄

BOINK : 처음 패킷을 1번으로 보낸후 두번째 패킷은 101번, 세번째 패킷은 201번 으로 정상적으로 보내다가 중간에서 일정한 시퀀스 넘버를 보냄

Teardrop : 시퀀스 넘버를 일정하게 바꾸는 것을 넘어 중첩과 빈공간을 만들어 시퀀스 넘버가 좀더 복잡해지도록 섞음

 

▷ 전혀 맞지 않는 시퀀스 넘버때문에 피해 시스템이 패킷화된 데이터를 재조합하는데 혼란이 생겨 cpu에 과부하가 걸리게 됨

 

LAND 공격 : SYN Flooding 기법과 유사

 

송신지 IP주소를 스푸핑하여 SYN flooding 공격 이때 패킷을 전송할때 출발지ip주소와 목적지 ip주소의 값을 동일하게

 

수신 시스템은 송신지 주소가 자신의 주소와 동일하므로 응답패킷을 자신에게 송부하고 유휴시간까지 대기하게 되어 해당 시스템에 장애 발생

 

Land 공격법은 동시 사용자 수를 점유하여 cpu부하까지 올림

 

 

Smurf공격 

 

웹 Dos공격

 

Http 유형 http get flooding , 동적 http requests flooding , http cc attack , http slowloris , rudy

dns 유형 dns query flooding , dns application ddos

메일 유형  mail bomb

728x90
728x90

https://www.bxieinfinity.com/airdrop?r=bolbtc 

 

액시인피니티에서 포크되어 나온 백시인피니티라고 합니다.

메타마스크 or 트러스트월렛를 BSC메인넷에 연결하고 이메일만 입력해주시면

백시코인 100개 + 랜덤박스( 귀여운 캐릭터 + 토지 + 아이템) 등 받을 수 있어요!

저는 5~20$ 가치의 귀여운 백시펫이 나왔네요 ㅎㅎ 

백시인피니티 P2E게임은 12월28일날 출시한다고해요 ! 

 

 

사전예약방법은  우선 메타마스크를 설치하시고 BSC를 추가해주셔야 되는데 아래 링크가 정리가 잘되있더라구요!

https://skuld2000.tistory.com/175

 

바이낸스 스마트 체인(BSC) 메타마스크 월렛 셋팅 방법

바이낸스 스마트 체인(Binace Smart Chain) 작년, 바이낸스에서 BSC(바이낸스 스마트 체인) 을 런칭 한 후 이를 기반으로 여러가지 디파이(Defi) 서비스 들이 출시되었습니다. BSC 기반의 디파이 서비스

skuld2000.tistory.com

 

 

 

메타마스크 설치 + BSC환경 셋팅이 되셨다면  https://www.bxieinfinity.com/airdrop?r=bolbtc  백시인피니티에 가셔서 

BSC주소와 이메일주소만 입력하면 100백시코인과 랜덤보상이 주어집니다

 

현재 백시코인은 5000백시 = 0.1BNB 이며 

현재 기준1백시당 약 10원정도 하는거같네요!

 

728x90
728x90

모듈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
import FinanceDataReader as fdr
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import tensorflow as tf
 
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, Conv1D, Lambda
from tensorflow.keras.losses import Huber
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
cs
 

 

데이터수집 

데이터수집은 FinanceDataReader 모듈을 통해 가져왔으며 추후 개발할 웹사이트와 상호작용하기 위해 외부db와 연결할 예정이다. 

1
samsung = fdr.DataReader('005930',start='1990')
cs

데이터 전처리

 

주가 데이터에 대하여 딥러닝 모델이 잘 학습하기위해 정규화(Normalization)을 해줘야한다.

 

표준화(Standardization)

표준화는 데이터의 평균을 0 분산 및 표준편차를 1로 만들어 주는 과정

표준화를 하는이유는

서로다른 통계 데이터들을 비교하기 쉽기 때문.

표준화를 하면 평균은 0 , 분산과 표준편차는 1로 만들어 데이터의 분포를 단순화시키고 비교를 용이하게 해준다.

 

ex) (6 10 2 4 8) 의 데이터셋이 있을경우 이를 표준화한다면 

데이터의 평균 = (6+10+2+4+8) = 6

분산 = (4^2 + 4^2 + 2^2 + 2^2) / (5-1 )  = 10 

표준편차는  10의 제곱근이 된다

 

                                                                     표준화공식

표준화 코드 

X_ = (X - X.mean() )  / X.std()

 

 

16
17
18
19
scaler = MinMaxScaler()
scale_cols = ['Open''High''Low''Close''Volume']
scaled = scaler.fit_transform(samsung[scale_cols])
scaled #표준화 확인 
 
cs

 

1
df = pd.DataFrame(scaled, columns=scale_cols) #표준화 한 데이터셋을 통해 데이터프레임 생성
cs

 

Train / test 분할 

Train

모델을 학습하기 위한 dataset이다. 한 가지 계속 명심해야할 중요한 사실은

"모델을 학습하는데에는 오직 유일하게 Train dataset만 이용한다"

 

Test

test set 학습과 검증이 완료된 모델의 성능을 평가하기위한 dataset이다.

보통 Train : Test 데이터를 8 : 2로 나눈다 . 

 

 

20
21
22
23
x_train, x_test, y_train, y_test = train_test_split(df.drop('Close'1), df['Close'], test_size=0.2, random_state=0, shuffle=False)
x_train.shape, y_train.shape #데이터확인 
x_test.shape, y_test.shape #데이터 확인 
x_train #데이터확인 
 
cs

train은 4800개의 데이터로 test는 1200개의 데이터 학습할 데이터와  성능을 평가하기 위한 데이터들을  

8:2 로 나눠주었다.

 

TensroFlow Dataset을 활용한 시퀀스 데이터셋 구성

 

1
2
3
4
5
6
7
8
9
10
def windowed_dataset(series,window_size,batch_size,shuffle):
    series = tf.expand_dims(series,axis=-1)
    ds = tf.data.Dataset.from_tensor_slices(series)
    ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
    ds = ds.flat_map(lambda w: w.batch(window_size + 1))
    
    if shuffle:
        ds = ds.shuffle(1000)
    ds = ds.map(lambda w: (w[:-1], w[-1]))
    return ds.batch(batch_size).prefetch(1)
cs

#Series : 시리즈 클래스는 1차원 배열의 값(values)에 각 값에 대응되는 인덱스(index)를 부여할 수 있는 구조를 갖고 있음 우선은 하나의feature(종가)를 기준으로 LSTM모델을 돌릴거

 

tf.expand_dims()는 배열의 차원을 늘려줍니다.
input에는 늘려질 배열을 넣습니다.
axis는 몇 번째 차원의 크기를 늘릴 건지 숫자를 넣습니다.

 

axis = -1은 가장 안쪽차원을 추가한다. 

ex) shape => ([10,10,3]) 일때  tf.expande_dims( axis= -1)일경우 shape => [10, 10, 3, 1]

 

tf.data.Dataset.from_tensor_slices 함수는 tf.data.Dataset 를 생성하는 함수로 입력된 텐서로부터 slices를 생성합니다. 예를 들어 학습데이터로 (60000, 28, 28)가 입력되면, 60000개의 slices로 만들고 각각의 slice는 28×28의 구조의 데이터를 갖게 됩니다. 위코드는 1차원구조의 데이터셋을 생성함

 

dataset.window는 3개의 인자를 전달받는데 window_size와 shift, drop_remainder

window는 요소를 shift만큼 묶어서 서브 dataset을 생성한다. 

 

window_size가 데이터셋의 크기를 초과하는경우가 존재하는데

이를 방지하기 위해 drop_remainder = True 인자를 넣어주면된다.

 

1
2
#하이퍼파라미터 정의
WINDOW_SIZE=20
BATCH_SIZE=32
cs

 

 

1
2
train_data = windowed_dataset(y_train, WINDOW_SIZE, BATCH_SIZE, True)
test_data = windowed_dataset(y_test, WINDOW_SIZE, BATCH_SIZE, False)
#train_data는 학습용데이터, test_data는 train_data를 통한 학습결과를 검증하기 위한 데이터셋
cs

 

1
2
3
4
5
# X: (batch_size, window_size, feature)
# Y: (batch_size, feature)
for data in train_data.take(1):
    print(f'데이터셋(X) 구성(batch_size, window_size, feature갯수): {data[0].shape}')
    print(f'데이터셋(Y) 구성(batch_size, window_size, feature갯수): {data[1].shape}')
cs

 

 

모델 미구현

728x90
728x90

필요 모듈 

1
2
3
import FinanceDataReader as fdr
import pymysql
import csv
cs

 

FinanceDataReader은 FinanceData.KR 에서 만든 오픈소스 금융 데이터 수집 라이브러리 이다.

 

 

  • 한국거래소(KRX)에 상장된 주식종목 리스트와 코넥스(비상장)에 있는 주식종목 리스트: 'KRX', 'KOSPI', 'KODAQ', 'KONEX'
  • 글로벌 주식종목 리스트: 'NASDAQ', 'NYSE', 'AMEX' and 'S&P500', 'SSE'(상해), 'SZSE'(심천), 'HKEX'(홍콩), 'TSE'(도쿄)
  • 개별 종목은 물론 금,원유 같은 원자재 지수도 지원한다. 

설치

pip install finance-datareader
pip install pymysql
pip install csv


참고 PyMySQL는 낮은 수준의 API를 지원하지 않습니다 

요구사항 

  • 파이썬 – 다음 중 하나:
  • MySQL 서버 – 다음 중 하나:

 

소스코드



1

2
3

 
conn = pymysql.connect(host="uws7-176.cafe24.com",user="아이디"
,password="패스워드",db="soll0803",charset="utf8")
curs=conn.cursor()
conn.commit()
cs

 

● pymysql.connect() 메소드를 이용하여 SQL에 연결 

host : 접속할 서버 주소

port : 접속할 서버 포트번호

user : sql id

password : sql password

db : 접속할 데이터베이스

charset : 인코딩

 

● line 1에서 접속이 성공하였다면 conn 객체로부터 cursor()메서드를 호출하여 cursor 객체를 가져옴

 

4
5
 
df = fdr.DataReader(symbol="005930",start='2000'#종목코드 005930 -> 삼성전자
df.to_csv('test.csv') #df를 csv파일로 저장
 
 
cs

#type(df) -> dataframe

 

6
7
= open('test.csv','r') #파일읽기모드
csvReader = csv.reader(f) #csvReader객체 생성
cs

 

 

1
2
3
4
5
6
7
8
9
10
11
for row in csvReader:
    Date1 = (row[0])
    Open1 = row[1]
    High1 = row[2]
    Low1 = row[3]
    Close1 = row[4]
    Volume1 = row[5]
    Change1 = row[6]
 
    sql = "INSERT INTO stock_data (Date,Open,High,Low,Close,Volume,Change2) values(%s,%s,%s,%s,%s,%s,%s)"
    curs.execute(sql,(Date1,Open1,High1,Low1,Close1,Volume1,Change1))

conn.commit()
f.close()
conn.close()

 
cs

curs.execute를통해 sql문 실행 

 

전체소스 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import FinanceDataReader as fdr
import pymysql
import csv
 
#삼성전자 주가데이터2020~오늘 데이터를 csv로 변환
#df = fdr.DataReader(symbol="005930",start='2020')
#df.to_csv('test.csv')
 
conn = pymysql.connect(host="uws7-176.cafe24.com",
user="아이디",password="패스워드",db="soll0803",charset="utf8")
curs=conn.cursor()
conn.commit()
 
df = fdr.DataReader(symbol="005930",start='2000'#종목코드 005930 -> 삼성전자
df.to_csv('test.csv')
 
= open('test.csv','r')
csvReader = csv.reader(f)
 
for row in csvReader:
    Date1 = (row[0])
    Open1 = row[1]
    High1 = row[2]
    Low1 = row[3]
    Close1 = row[4]
    Volume1 = row[5]
    Change1 = row[6]
 
    sql = "INSERT INTO stock_data (Date,Open,High,Low,Close,Volume,Change2) values(%s,%s,%s,%s,%s,%s,%s)"
    curs.execute(sql,(Date1,Open1,High1,Low1,Close1,Volume1,Change1))
conn.commit()
f.close()
conn.close()
cs

 

결과

728x90
728x90

개요

 

파이썬으로 request.get을 통해 웹을 크롤링하던 도중 원하는 데이터가 크롤링되지않아 처음엔 당황스러웠다.

하지만 크롤링이 되지않는 이유는 get방식으로 웹이 동작하는게 아니라 post방식을 통해 작동하기 때문이었다.

이를 확인하는 방법은 크롤링할 웹사이트로 이동할때 주소창이 변할경우 get방식으로 작동하고 

주소창이 바뀌지않을경우 post방식으로 작동한다는것을 알수있다.

 

 

특징

GET 방식은 다음과 같은 특징이 있습니다.

- 클라이언트가 입력한 값이 URL과 결합되어 스트링 형태로 서버에 전달됩니다
- 서버의 DB에 정보를 요청하는 것이 아니라 해당 웹페이지에서 보여지는 그대로를 가져오는 것입니다.
- 한번 요청시 데이터 양에 제한이 있습니다.

 

POST 방식은 다음과 같은 특징이 있습니다.

- 클라이언트와 서버 간에 스트링 형태로 그대로 서버에 전달되지 않고 인코딩이라는 과정을 거칩니다.
- 헤더를 통해 요청이 전송되는 방식입니다. 이 때문에 GET 방식과 같이 URL이 노출되지 않습니다.
- 요쳥시 GET 보다 더 많은 양의 정보를 교환할 수 있습니다.
- 페이지에서 날짜를 설정하고 조회하기 버튼을 눌렀을 때 서버는 DB에서 해당 기간에 해당되는 정보를 불러와 우리에게 보여줍니다.  이 때 사용하는 방식이 바로 POST 방식입니다. 조회하기 버튼을 눌렀을 때 URL 이 client 에게 노출이 되지 않으며, GET방식에 비해 더 많은 양의 정보를 받아올 수 있다는 장점이 있습니다. 

 

실습

 

 

>>> import requests

 

크롤링할 데이터는 바이낸스에서 상위트레이더의 포지션을 실시간으로 크롤링하는 프로그램을 짜보겠습니다.

https://www.binance.com/en/futures-activity/leaderboard?type=myProfile&tradeType=PERPETUAL&encryptedUid=CCF3E0CB0AAD54D9D6B4CEC5E3E741D2 

 

Binance Futures Leaderboard | ROI & PNL Rankings | Binance Futures

 

www.binance.com

 

위에 주소로 입력하게 될경우 TraderT라는 닉네임을 가진 트레이더의 포지션을 볼수있는데

이 데이터는 get방식으로 작동하는게 아닌 post방식을 통해 클라이언트가 서버(https://www.binance.com/bapi/futures/v1/public/future/leaderboard/getOtherPosition) 

이부분으로 request.post 요청을 하면 서버에서 응답을 해주는 방식으로 작동한다.

 

 

크롬f12를 눌러 개발자모드를 통해  network를 보면 post동식으로 동작하며

 

response로 원하는 데이터가 response오는걸 확인할수있다.

header쪽을 좀더보면 클라이언트가 서버로 post방식으로 request할때

request payload와 form data 두개의 방식으로 서버에게 전달하는데

 

 

Content-Type: application/json다음과 같은 요청이 있을 수 있습니다.

POST /some-path HTTP/1.1

Content-Type: application/json { "foo" : "bar", "name" : "John" }

AJAX별로 이것을 제출하면 브라우저는 단순히 페이로드 본문으로 제출하는 내용을 보여줍니다. 데이터가 어디에서 오는지 전혀 모르기 때문에 할 수 있는 모든 것입니다.

 

method="POST"and Content-Type: application/x-www-form-urlencoded/ 와 함께 HTML 양식을 제출하면 Content-Type: multipart/form-data요청은 다음과 같을 수 있습니다.

POST /some-path HTTP/1.1 Content-Type: application/x-www-form-urlencoded foo=bar&name=John

이 경우 form-data는 요청 페이로드입니다. 

여기에서 브라우저는 더 많이 알고 있습니다. bar가 제출된 양식의 입력 필드 foo 값이라는 것을 알고 있습니다. 그리고 그것이 당신에게 보여주고 있는 것입니다.

따라서 Content-Type데이터가 제출되는 방식은 다르지만 차이 가 있습니다. 두 경우 모두 데이터는 메시지 본문에 있습니다.

 

출처:https://stackoverflow.com/questions/23118249/whats-the-difference-between-request-payload-vs-form-data-as-seen-in-chrome

 

import requests
import websocket
import time
import json


url = 'https://www.binance.com/bapi/futures/v1/public/future/leaderboard/getOtherPosition'

payload = {
    'encryptedUid':'CCF3E0CB0AAD54D9D6B4CEC5E3E741D2',
    'tradeType':'PERPETUAL'
}
response1 = requests.post(url,json=payload)
#print(type(response1.text))
dict = json.loads(response1.text)
print(list.__len__(dict['data']['otherPositionRetList']))
print('심볼\t: 시작가격\t : 포지션수량\t : 포지션수량(usdt)')

for i in range(0,list.__len__(dict['data']['otherPositionRetList'])):
    print(dict['data']['otherPositionRetList'][i]['symbol'] +' : ' + str(dict['data']['otherPositionRetList'][i]['entryPrice'])+ ' : ' + str(dict['data']['otherPositionRetList'][i]['amount']),end='\t : ')
    usdt_amount = (int(dict['data']['otherPositionRetList'][i]['entryPrice'])*int(dict['data']['otherPositionRetList'][i]['amount']))
    print(usdt_amount)

 

출력결과

728x90
728x90

websocket을 설명하기에 앞서 HTTP에 대해 간략히 설명하겠습니다.

 

HTTP에 대한 간략한 설명

HTTP(Hyper Text Transfer Protocol)은 웹상에서 정보를 주고받을 수 있는 프로토콜인데

주로 html문서를 주고받을때 사용되며 HTTP는 클라이언트와 서버 사이에 이루어지는

요청(request)과 응답(response) 프로토콜입니다 

 

HTTP의 한계점 

HTTP의 특징중하나로 클라이언트가 서버에게 요청(request)를 보내고 서버가 답(response)을 주면

그대로 연결이 끊긴다.

서버와 다수의 클라이언트가 연결을 유지한다면 서버에 많은 리소스 낭비가 생기는데

HTTP프로토콜에는 이러지 않고 요청(request)에 응답(response)를 주면 연결이 끊기기 때문에

리소스 낭비가 적다.

 

하지만 이러한 http에는 여러 단점이 존재한다.

1. 요청(request)를 보낼 때 페이지가 리로딩 된다.

2. 동일한 요청에 중복된 헤더파일을 보낸다.

3. 실시간 상호작용성이 떨어진다.  

 

-Polling(폴링)

 

 

폴링기술은 클라이언트가 서버에게 계속해서 http requests를 날려 response(응답)을 받는 방식이다.

 

딱봐도 클라이언트는 서버에게 계속 요청(request)를 날리기 때문에 서버에 부담이온다.

 

또한 유저(클라이언트)가 아무것도 하지않아도 쓸데없이 서버의 리소스를 낭비하게된다.

 

또한 클라이언트에서 실시간정도의 빠른응답을 기대하기도 힘들다

 

-Long Polling

롱폴링은 클라이언트가 서버로 일단 http 요청을 날린다. 이 상태로 계속 기다리다가 서버에서 해당 클라이언트로 전달한 이벤트가 생기면 그순간 응답 메세지를 전달하면서 연결이 종료된다. 하지만 곧바로 클라이언트는 다시 요처을 날려 서버의 다음 이벤트를 기다리는 방식이다.

 

요약하자면

  1. 클라이언트가 웹서버로 HTTP 요청을보낸다
  2. 요청을 받은 웹서버는 데이터가 있을 때 까지(이벤트가 발생할 때 까지) 기다린다
  3. 데이터 혹은 이벤트가 발생하면 클라이언트로 HTTP응답을보낸다
  4. 응답을 받은 웹브라우저(클라이언트)는 데이터를 출력하고 HTTP연결을 끊는다
  5. 그리고 웹브라우저(클라이언트)는 다시 HTTP요청을 보낸다
  6. 기다린다
  7. 반복

Streaming

클라이언트가 서버에게 http request 를 보내고 서버는 응답을 끊임없이 흘려보낸다.(trickles out)

 

각 기술들의 문제점을 요약하자면

HTTP 통신규약 : 서버에게 요청보내고 응답 받으면 연결이 끊긴다. 서버-클라이언트 실시간 상호작용이 안된다.

 

그래서 실시간 상호작용할 수 있게 효과만 내본 기술들

Polling 기술 : 서버로 계속해서 요청보내기(근데 서버에 이벤트 없어도 계속 요청보냄>서버,클라이언트 무리)

 

Long polling기술 : 서버에 요청보내고 이벤트가 생겨 응답 받을 때 까지 연결안끊기. 응답받으면 끊고 다시 새요청보냄(근데 새 이벤트 생기면 모든 사용자가 연결 끊고 동시에 새요청보내게됨>서버무리)

 

Streaming 기술 : 서버에 요청보내고 끊기지 않은 연결상태에서 끊임없이 데이터받기(근데 클라이언트가 서버로 요청을 보내기 좀 힘듬. 스트리밍에서는 하나의 포트써서 읽고 쓰기 동시에 안됨)

 

 

이러한 기술들의 문제점인 실시간네트워킹이 가능한것이 바로 WebSocket이다

 

websocket(웹소켓)은 http를 기반으로 하면서 http의 문제점해결을 목표로 나온 기술이다.

이전의 통신과 달리 이중통신(full-duplex통신) 즉 수신과 송신을 동시에 처리가 가능하다.

socket connection을 유지하기 때문에 양방향 통신, 실시간통신, 데이터 전송이 가능하고

html5에 포함되어 프로토콜로 제정되어있다.

 

기존의 TCP SOCKET과 차이점은 웹소켓은 최초 접속이 일반 http요청을 이용한

handshaking으로 이루어진다. 또한 TCP Socket에서는 바이트 스트림을 사용하지만

웹소켓을 통해  전달되는 텍스트는 UTF-8형식을 가진다.

 

웹소켓길술은 real-time web application(서버 또는 클라이언트 쪽 데이터가 실시간으로 업데이트 되는 웹 어플리케이션)에서 많이 사용한다.

 

웹소켓 작동원리

 

서버와 클라이언트간 웹소켓 연결(connect)은 http프로토콜을 통해 이루어진다

HANDSHAKE과정이 성공적으로 끝나면 HTTP를 웹소켓프로토콜로 바꾸는 Protocol switching과정이 진행된다.

그러면 웹소켓을 위한 위한 새로운 소켓이 만들어지고 이소켓을 이용해 통신을한다!(ws나 wss)

데이터의 구조는 텍스트와 바이너리 모두 양방향 통신이 가능하며 텍스트의 경우 시작 바이트가 0x00, 끝 바이트가 0xFF로 끝나며 UTF-8데이터를 포함.

 

웹소켓 주소는 ws나 wss로 시작하는데 ws는 일반 웹소켓이고 wss는 SSL이적용된 웹소켓이다(Https)

 

이슈

  • stateful한 만큼 서버와 클라이언트 연결을 계속 유지해야하고, 비정상적 연결이 끊어졌을때를 대응해야함.
  • 서버와 클라이언트간의 socket 연결을 하는 것 자체가 비용이 많이 든다(트래픽이 많은 서버 같은 경우 CPU부담이 될 수 있다)

 

파이썬 웹소켓 크롤링 예제(비트맥스에서 1분 OHLCV 가져오기)

모듈 설치

pip install websocket-client

 

코드

import websocket
def on_message(ws, message):
    print("메시지: " + message)
def on_error(ws, error):
    print("에러 : " +error)
    ws.on_close(ws)
def on_close(ws):
    print("### closed ###")
    ws.close()
def on_open(ws):
    print("### open ###")
def run(endpoint):
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp(endpoint,
                                on_open = on_open,
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close)
    ws.run_forever()
if __name__ == "__main__":
    command = 'subscribe=tradeBin1m:XBTUSD'
    endpoint = 'wss://www.bitmex.com/realtime?'+command   
    run(endpoint)

 

728x90
728x90

https://ititit1.tistory.com/99

 

안드로이드 앱 외부 데이터베이스 연동(Android<-> PHP <-> Maria DB) 1. 기본 설치

안드로이드 어플리케이션은 외부 DB에 바로 접근해서 데이터를 불러오지 ㅗㅅ합니다. 보안상의 이유때문에 '외부' 데이터베이스에 바로 접근은 하지못합니다. 따라서 위와같은 방식으로 애플리

ititit1.tistory.com

 

위 글에서 이어지는 내용 입니다.

 

Apache, MariaDB, PHP가 제대로 동작한다고 가정하고 진행하겠습니다.

 

우선 Apache 를 Start눌러 서버를 시작합니다.

 

그후 DB 테이블을 만들어야되는데

 

1. test 데이터베이스 접속하기

관리자 권한으로 cmd를 실행한 후 mysql test -u root -p 를 입력하여 접속합니다.

 

2. table 만들기 

create table member_test(

   userid varchar(30),

   userpassword varchar(30),

   username varchar(30)

);

 

 

2-1 테이블 구조 출력하기 

desc member_test;

 

+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| userid       | varchar(30) | YES  |     | NULL    |       |
| usdrpassword | varchar(30) | YES  |     | NULL    |       |
| username     | varchar(30) | YES  |     | NULL    |       |
+--------------+-------------+------+-----+---------+-------+

 

3. 테이블에 필드(데이터)값 넣기

insert into member_test(userid,userpassword,username)
                      values('soll0803','dlwlsthf1','leejinsol');

 

3-1 필드 출력

select * from member_test;

 

+----------+--------------+-----------+
| userid   | userpassword | username  |
+----------+--------------+-----------+
| soll0803 | dlwlsthf1    | leejinsol |
+----------+--------------+-----------+

 

userid 열만 출력하기

MariaDB [test]> select userid from member_test;
+----------+
| userid   |
+----------+
| soll0803 |

+----------+

 

 

connect.php 파일 만들기 

 

C:\xampp\htdocs 경로에 connect.php 파일을 생성해줍니다.

 

코드는 다음과 같이 작성합니다.(저는 member_test 테이블에 값들을 4개 넣어줬습니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<html>
<head>
    <title> :::DB TEST::</title>
    <meta charset="utf-8"/>
</head>
 
<body>
    
<?php
//1. DBMS 접속
$connect = mysqli_connect("localhost","root","비밀번호","test");
 
//2. 쿼리 실행
$query = "select * from member_test";
$result = mysqli_query($connect,$query);
$num = mysqli_num_rows($result); //행의 개수 
 
echo "rows count : ",$num;
 
 
//3. 데이터 가져오기
echo "      /     ";
 
$row = mysqli_fetch_array($result); //연관배열 형태로 들어옴
echo $row['userid'] . " " . $row['userpassword'] . " " . $row['username'];
//echo $query; 
 
echo ' / ';
$row = mysqli_fetch_array($result); //연관배열 형태로 들어옴
echo $row['userid'] . " " . $row['userpassword'] . " " . $row['username'];
 
echo ' / ';
$row = mysqli_fetch_array($result); //연관배열 형태로 들어옴
echo $row['userid'] . " " . $row['userpassword'] . " " . $row['username'];
 
echo ' / ';
$row = mysqli_fetch_array($result); //연관배열 형태로 들어옴
echo $row['userid'] . " " . $row['userpassword'] . " " . $row['username'];
 
 
 
//원래는 while문으로 돌리는게 일반적임
?>
 
</body>
</html>
cs

 

저장후 localhost/connect.php에 접속하여 확인합니다.

rows 값과

테이블의 필드값들이 성공적으로 웹에서 출력이 됩니다.

 

 

필드값들을 JSON 형태로 출력하기 

<test.php>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
    $con=mysqli_connect("localhost","root","비밀번호","test");
    mysqli_set_charset($con,"utf8");
 
    $res = mysqli_query($con,"select * from member_test");
    $result = array();
    
    while($row = mysqli_fetch_array($res)) {
        array_push($result,
            array('userid'=>$row[0],'userpassword'=>$row[1],'username'=>$row[2]));
    }
    echo json_encode(array("Tree"=>$result), JSON_UNESCAPED_UNICODE);
    mysqli_close($con);
?>
 
cs

 

위 내용들을 json viewer사이트에서 보게되면 

 

https://jsonformatter.org/json-viewer

 

Best JSON Viewer Online

Secure JSON Viewer is online JSON Viewer tool to Visualize JSON data in Tree View.

jsonformatter.org

사진대로 JSON형태로 출력이 됩니다.

728x90
728x90

안드로이드 어플리케이션은 외부 DB에 바로 접근해서 데이터를 불러오지 못합니다.

보안상의 이유때문에 '외부' 데이터베이스에 바로 접근은 하지못합니다.

 

 

따라서 위와같은 방식으로

애플리케이션 < -> PHP+아파치서버 <-> db에 통신하여 db를 가져오게된다.

즉, PHP에서 Mysql의 데이터에 접근해 echo 로 웹페이지에 mysql의 내용을 띄워 주면, 그 내용을 안드로이드에서 읽어오는 것이다. 간단히 그림으로 설명하자면 다음과 같다

 

안드로이드에서 http 요청을 통해 아파치 웹서버의 php파일이 출력하고 있는 내용을 읽어오는 것이다. 즉, 위 사진에서 

Seq : 1 Author : Yong...... 등의 내용을 가져온다. 위 웹페이지에서 띄워진 내용들은 모두 echo로(JSON 형태 ) 띄운 것이다.

 

 

먼저 실습을위해 

 

Maria DB , 아파치 , PHP 를 설치해야되는데

1. Maria DB 설치

Maria DB를 설치를 위해서 https://downloads.mariadb.org/mariadb/10.3.17/

 

MariaDB 10.3.17 Stable - MariaDB

 

downloads.mariadb.org

 

본인의 운영체제에 맞게 설치해주시면 되고 

Maria DB가 설치가 완료 되면

시작메뉴를 열어서 Heider SQL을 실행해줍니다

 

신규를 눌러서 새로운 세션을 만들어주고

세션을 우클릭하여 이름을 변경해주신후 암호를 입력하고 열기를 누르면

test1의 DB가 열리게 됩니다

 

 

 

2. XAMPP 설치

아파치와 PHP는 XAMPP 를 통해 설치해준다. 

XAMPP는 Apache, MariaDB, PHP, Perl의 약자로 설치하려는 소프트웨어를 포함하여 여러가지 기능을 제공하고 있습니다.

 

 

XAMPP를 설치하기 위해서 먼저 https://www.apachefriends.org/index.html 링크로 들어갑니다.

 

들어가셔서 본인의 운영체제에 맞게 설치해주시면 됩니다.

 

설치가 완료되면 Apache 를 Start 해줍니다.

 

 

3. 설치,동작 확인 

 

 

C:\xampp\htdocs 폴더로 가셔서 info.php 파일을 만들어주시고

 

코드를 다음과같이 작성합니다.

 

 

 

1
2
3
4
5
<?php
    $con=mysqli_connect("localhost","root","비밀번호") or die("MariaDB 접속 실패");
    phpinfo();
    mysqli_close($con);
?>
cs

이제

 

localohost/info.php 에 접속하시고

 

이런 화면이 나온다면  Apache, MariaDB, PHP가 제대로 동작된다고 보시면 됩니다.

 

참고:https://1d1cblog.tistory.com/

 

728x90

+ Recent posts