반응형

Keras로 조지는 편은 다음에 이어서 올리겠습니다.

 

TensorFolw와 CNN 모델로 Mnist데이터 학습시키기

 

0. 시작전에

- TensorFlow 설치와 Keras설치에 관한것은 여기서 다루지 않습니다.

- CNN에 대한 부분은 이전 게시글을 참고해주세요.

- Keras만 갖고놀다가 TensorFlow를 잡으니 Python하다가 C언어하는 느낌이네요.

- CNN으로 조지기라고 적어두고, 내가 조져진 게시물...

 

 

1. 데이터 다운로드

일단 시작은 기본 라이브러리 호출과 데이터 다운로드부터 시작하겠습니다.

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./data/", one_hot=True)

TensorFlow는 tf라는 이름으로 불러와주었습니다.

그리고 위와같은 방법으로 데이터를 다운로드해서 mnist라는 변수에 담아주었습니다.

 

<주의>

위와 같이 코드를 실행하면 현재 파이썬파일과 함께있는 data라는 폴더에 mnist파일이 저장됩니다. data라는 폴더가 없을 경우 애러가 발생할 수 있습니다.

 

파이썬 파일과 폴더는 한 폴더에

위와같이 해당 코드를 실행하면 4개의 파일이 data의 폴더에 저장됩니다.

 

2. 데이터 확인하기

mnist 데이터를 보게되면 아래와 같이 "test", "train", "validation"이라는 3개의 데이터셋이 존재하는 것을 볼 수 있습니다.

  • TRAIN DATA : 학습을 시키는 용도의 데이터
  • VALIDATION DATA : 학습시킨 모델을 검증하는 데이터
  • TEST DATA : 최종적으로 학습시킨 모델이 판단할 데이터

Validation은 최종적으로 Test데이터를 통해서 결과를 도출하기전에 최종적으로 확인하는 용도라고 생각해주시기 바랍니다.

 

그럼 mnist.train 이하에는 어떤 데이터가 있는지 확인해보겠습니다.

mnist 데이터

위와깉이 몇개의 데이터가 보이는데 중요한건 "images"와 "labels"라고 할 수 있습니다.

 

실제 학습시킬 데이터와 그 정답이니까요.

 

한번 출력해서 확인해보겠습니다.

 

먼저 labels 부분의 5번째 데이터를 보게되면 9번째 자리에 1이 표시되어있는 것을 볼 수 있습니다.

 

이러한 형태를 One-Hot이라고해서 오로지 특정 위치 하나에만 1이 존재함으로 그 자리의 값을 특정하는 것을 말합니다.

 

위의 경우 맨 앞이 0, 마지막이 9가 되는 형태고 9번째 자리가 1인것을보면 Label은 8을 의미하고 보이시는 것 처럼 이미지도 8을 띄우고 있습니다.

 

다음으로 데이터의 크기를 확인해보겠습니다.

 

데이터의 크기 확인하기

label은 0~9까지 10개의 자리를 차지하기 때문에 10으로 나눠준 값이 총 이미지의 갯수라고 볼 수 있습니다.

 

  • train : 55000개
  • validation : 5000개
  • test : 10000개

3. 모델 구축하기

tf.set_random_seed(777)
learning_rate = 0.001
training_epochs = 10
batch_size = 100

X = tf.placeholder(tf.float32, [None, 784])
X_img = tf.reshape(X, [-1, 28,28, 1])
Y = tf.placeholder(tf.float32, [None, 10])

일단 위와같이 초기상태를 만들어주었습니다.

 

placeholder는 사용자와 모델간의 데이터 이동이 가능한 변수(?)같은 녀식입니다.

 

X 는 이미지데이터가 들어갈 공간입니다. mnist데이터는 2차원 이미지가 1차원 형태로 되어있습니다. (...;;)

 

그래서 784크기의 이미지가 X에 들어간 후 reshape를 통해서 28x28의 형태로 변형시키는 과정이 필요합니다.

 

또한 최종적으로 출력되는 Y는 One-Hot출력되기 때문에 10개의 공간을 설정해주었습니다.

 

W1 = tf.Variable(tf.random_normal([3, 3, 1, 32], stddev=0.01))
L1 = tf.nn.conv2d(X_img, W1, strides=[1, 1, 1, 1], padding="SAME")
L1 = tf.nn.elu(L1)
L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
# 14 x 14

W2 = tf.Variable(tf.random_normal([3, 3, 32, 64], stddev=0.01))
L2 = tf.nn.conv2d(L1, W2, strides=[1, 1, 1, 1], padding="SAME")
L2 = tf.nn.elu(L2)
L2 = tf.nn.max_pool(L2, ksize=[1, 1, 1, 1], strides=[1, 1, 1, 1], padding="SAME")
# 14 * 14

W3 = tf.Variable(tf.random_normal([3, 3, 64, 128], stddev=0.01))
L3 = tf.nn.conv2d(L2, W3, strides=[1, 1, 1, 1], padding="SAME")
L3 = tf.nn.elu(L3)
L3 = tf.nn.max_pool(L3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
# 7 * 7

L4_flat = tf.reshape(L3, [-1, 7*7*128])

 

그리고 대충 Convolution과 Max_pooling을 반복하는 구조를 대충 만들었습니다.

 

W(Weight)의 stddev는 랜덤한 값의 설정할 때의 표준편차입니다.

conv2d는 2차원 이미지에대한 Convolution을 의미합니다.

Padding = "SAME"은 입출력 이미지의 크기가 동일하다는 것을 말합니다.

Activation Function은 elu로 설정해주었습니다.

 

그냥 별생각없이 대충 만들어봤습니다. mnist데이터 자체가 간단한 데이터라 아마 잘 될꺼라는 믿음...으로 만들었습니다.

(gpu환경이 아니시고 컴퓨터의 사양에 자신이 없으시다면 절절하게 조정이 필요합니다.)

 

최종적으로 3개의 Conv와 Pooling 후 Flatten 과정을 수행하게됩니다.

 

이제 일반 DNN형태를 만들겠습니다.

 

hidden1 = tf.layers.dense(L4_flat, 300, name="hidden1",activation=tf.nn.elu)

hidden2 = tf.layers.dense(hidden1, 100, name="hidden2",activation=tf.nn.elu)

logits = tf.layers.dense(hidden2, 10, name="outputs")

이것도 뭐... 간단하게 만들어봤습니다.

 

아마 잘 될꺼라는 믿음으로...

 

중간 숫자 300, 100, 10은 출력의 갯수를 말합니다.

 

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

for epoch in range(training_epochs):
    avg_cost=0
    total_batch = int(mnist.train.num_examples / batch_size)
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        feed_dict = {X:batch_xs, Y:batch_ys}
        c, _ = sess.run([cost,optimizer], feed_dict=feed_dict)
        avg_cost += c / total_batch
    
    print("Epoch : ", "%04d" % (epoch + 1), 'cost = ', '{:.9f}'.format(avg_cost))
    
print("Learning Finished!")

마지막으로 학습과정입니다.

 

저 코드를 직접 짠 기억은 없는데, 저장된 자료들중에 mnist 관련자료에 있어서 갖고왔습니다...

(아마 sung Kim님의 코드가아닐까합니다... 존경합니다.)

 

scoftmax cross entropy에 Ver2가 생겨서 적용해봤습니다.

 

Cost Function은 reduce mean을 사용했습니다.

 

optimizer는 가장 배신을 덜하는 Adam을 사용했습니다.

 

 

4. 학습

10Epoch에 cost가 0.01정도까지 떯어지네요. 일단 흠...

 

좋습니다. 테스트해서 어느정도 결과가 나오는지 확인해보겠습니다.

 

corrent_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(corrent_prediction, tf.float32))
print("Accuracy: ", sess.run(accuracy, feed_dict={X : mnist.test.images, Y : mnist.test.labels}))

실행결과 99%확률로 맞추네요~

 

잘맞추네요...;;

 

sess.close()
tf.reset_default_graph()

끝나면 위의 코드를 실행해서 초기화시켜주세요.

 

역시 Keras가 쉽습니다...;;

반응형
반응형

CNN 기초정리

원래는 mnist 데이터를 다루려고 했는데, 그래도 CNN 기초정리는 해야겠어서 잠깐 살짝 다루고 넘어가겠습니다.

 

0. 시작 전에

CNN에 대해서 깊게 설명하려면 일단 기존 DNN의 개념부터 시작해야 해서 아주~ 가볍게 설명하고 넘어가겠습니다.

혹시 추가 질문이나 문제 있는 부분은 글 남겨주세요~

 

1. CNN이란?

Convolutional Neural Network의 약자로 일반 Deep Neural Network에서 이미지나 영상과 같은 데이터를 처리할 때 발생하는 문제점들을 보완한 방법입니다.

 

어떤 문제가 있었나?

DNN은 기본적으로 1차원 형태의 데이터를 사용합니다. 쉽게 생각하면 iris데이터를 생각해보시면 됩니다.(다뤄보지 않았다면... 크흠...)

 

iris데이터를 보게 되면 Columns으로 꽃받침과 꽃잎의 길이 등이 데이터로 오게 되는데 아래와 같습니다.

 

Index 꽃받침길이 꽃받침너비 꽃잎길이 꽃잎너비 꽃의종류(Target)
1 5.1 3.5 1.4 0.2 setosa

이러한 형태의 데이터가 많이 존재하는데, 여기서 꽃받침과 꽃잎의 정보를 input데이터(=X)로하고, 꽃의 종류를 output데이터(=Y)로 설정하여 학습을 하게 됩니다

 

그리고 학습된 모델에게 꽃받침과 꽃잎에 대한 정보를 넣음으로 꽃의 종류를 맞추게 하는 모델이 되게 됩니다.

 

Iris 데이터에 대한 설명은 여기까지이고, 이러한 데이터를 1차원 데이터라고 부르는 이유는 데이터가 하나의 row로 표현되기 때문입니다.

 

하지만, 이미지는 어떤가요? 480x480 같은 형태로 표현되는 이미지는 하나의 row로 표현되지 않습니다. 물론 한 줄로 표현할 수는 있겠죠. 다만, 이미지 데이터를 하나의 row로 변환하게 되는 순간, 데이터는 큰 손실을 갖게 됩니다.

 

예를 들어 아래와 같은 강아지 사진이 있다고 봅시다.

 

귀엽...;;

이런 사진 데이터를 한 줄로 표현한다면...?

 

아래와 같은 한 줄이 됩니다... 위에서부터 1px씩 잘라서 우측에 붙이는 형태죠.

 

한줄된 강아지...ㅠㅠ

 

실제로는 더 작은 숫자들의 집합으로 이루어진 한 줄 데이터가 되겠지만, 의미적으로 봐주세요.

 

저 한 줄로 표현된 이미지와 기존의 이미지를 비교해보면 DNN으로 이미지를 학습시킬 때의 문제를 알 수 있습니다.

 

이미지 데이터는 한 점을 기준으로 그 주변 점들이 모여 하나의 객체(?)가 됩니다.

 

위 이미지에서 보면 이미지의 특정 픽셀(이미지 데이터에서 매우 작은 한 점)들이 모여 강아지라는 객체를 만들게 되는데, 한 줄로 된 row데이터에서는 이러한 연간 관계가 제거된다는 문제가 있습니다.

 

말료표현하기 어렵네요...

 

그럼 CNN에서는 어떻게 극복했을까?

 

제가 설명하기 좋은 자료를 찾기가 힘들어서... 대충 그렸습니다... ㅋㅋ

 

위와 같은 이미지가 있다고 생각해봅시다. 다음에 작업할 데이터도 숫자 이미지니 까요.

 

이 이미지는 더 자세하게 보면 아래와 같은 상태로 볼 수 있습니다.

위의 이미지의 빨간색 네모칸 하나를 1픽셀로 생각해주시고, 한 픽셀에는 흰색 또는 회색이 들어있다고 생각해주세요.

(네모칸에 회색 또는 흰색 중 많이 차지하는 녀석이 들어있다고 가정해주세요.)

위와 같은 이미지에 회색이 들어있는 픽셀은 숫자로 1이 들어있고, 흰색에는 0이 들어있다고 생각해봅시다. 그럼 아래와 같은 그림이 됩니다.

 

모든 이미지들은 기본적으로 위와 유사하게 표현됩니다. 물론 포맷(압축) 방식에 따라서 차이가 있겠지만, 우리가 다루는 대부분의 이미지는 1개의 픽셀이 RGB를 의미하는 3개의 색상 값을 갖고 있어서 이 값을 통해서 1픽셀의 색이 결정되는 형태입니다.

(즉, 한 개 픽셀도 3개의 차원으로 구성된다는 것이죠...;; 지금은 간단히 0 또는 1의 값이 있다고 합시다. 자세한 건 나중에)

 

CNN에서는 이 이미지의 한 픽셀과 주변 픽셀들의 연관관계를 유지시키며 학습시키는 것을 목표로 합니다.

 

CNN은 일단 하나의 이미지로부터 픽셀 간의 연관성을 살린 여러 개의 이미지를 생성하는 것에서 시작합니다.

 

방법은 아래와 같습니다. 3x3의 크기로 이미지를 뽑아내서 마찬가지로 3x3크기의 랜덤값을 갖고 있는 데이터와 각 픽셀을 곱해서 더해줍니다.

 

이때 랜덤값을 갖고 있는 3x3데이터를 필터라고 부릅니다.

 

계산해보면 각 필터의 값에 따라서 4, 15, 12와 같은 서로 다른 값이 발생하는 것을 알 수 있습니다.

즉, 9개의 픽셀로부터 1개의 값이 생성되며, 빨간색 칸을 한 칸씩 옮겨가며 이 값들을 하나씩 생성하게 되면 12x12 이미지에서 필터 하나가 10x10 크기의 이미지를 생성하게 됩니다.

(빨간색이 1칸씩 움직이지 않게 할 수 도있습니다. strides라는 값을 통해서 이것을 설정할 수 있습니다.)

 

필터가 3개라면 10x10 이미지 3개가 생성되겠죠.(이미지의 각 픽셀에는 계산된 값이 들어갑니다.)

 

그럼 12x12 이미지가 10x10으로 줄어드는데 괜찮은 건가?라는 의문이 들 수 있습니다.

이에 대해서는 확실하게 문제다! 문제가 아니다!라는 확실한 그건 없습니다만, 추측하기에 어쨌든 손실되는 부분이 발생한다고 생각하는 경우가 많기 때문에 이러한 문제를 해결하기 위해서 padding이라는 값을 주게 됩니다.

 

padding이란 원래 이미지의 양옆에 0 값을 갖는 데이터를 추가하여 위와 같은 방법을 취한 후에도 원래의 크기와 동일한 이미지를 유지하도록 해주는 방법입니다.

 

이러한 일련의 과정을 CNN에서는 Convolution이라고 합니다. CNN의 핵심에 해당하는 부분이죠.

 

 

Convolution이 CNN의 한 부분이라면, 그 외의 부분도 있겠죠?

Pooling이라는 녀석과, Flatten이라는 과정이 존재합니다.

 

Pooling?

Pooling은 CNN의 문제점 중 하나를 교정해주는 작업입니다.

CNN의 문제점... 시작하자마자 문제네요...

 

위에서 Convolution이라는 과정을 통해서 많은 수의 이미지를 생성한 것은 좋은데... 너무 많아졌다는 게 문제입니다.

 

하나의 이미지에서 Convolution이라는 과정을 거칠 때마다 5배씩 이미지가 생성되는데, 이미지의 크기도 줄지 않고...

 

그래서 도달한 게 Pooling이라는 과정입니다.

 

이미지를 분석하는 데 있어서 과연 Null 값과 유사한, 즉 correlation이 낮은 영역은 없을까? 하는 의문이 들지 않나요?

 

사실 존재 여부를 떠나서 사람이 그것을 판단하는 건 쉽지 않은 일입니다.

 

따라서, Convolution과 유사한 과정인데, 이미지를 5배씩 뻥튀기시키지 말고, 1개의 이미지에 1개의 출력을 만들면서 동시에 기존 이미지에 Padding 없이 Filter만 적용해서 크기를 줄이는 방법을 Pooling이라고 합니다.

 

Flatten은?

 

간단합니다. 아래를 봐주세요.

 

전체 CNN의 과정입니다.

대충 전체적인 느낌이 오시나요?

 

Colvoltuion과  Pooling을 반복해주면 이미지의 숫자는 많아지면서 크기는 점점 줄어들게 됩니다.

 

이것은 최종적으로 도출된 nxn이미지는 이미지라는 의미보다는 특정 이미지에서 얻어온 하나의 특이점 데이터가 된다는 것입니다.

 

그 말 곧, 이것은 2차원이 아닌 1차원의 Row 데이터로 취급해도 무관한 상태가 된다는 의미이기도 합니다.

 

따라서 하나의 이미지로부터 다양한 특이점들을 뽑아내고 이것을 1차원의 데이터로 변형하는 것 이게 Flatten입니다.

 

위의 이미지를 보면 이해하실 수 있습니다~~!!! 제발...

 

Flatten과정을 거치면 이후에는 그냥 DNN과 동일하게 만들어진 네트워크를 통해서 Output을 출력하게 됩니다.

 

간단한 듯 아닌듯하죠?

 

아직은 어렵지만, 이다음에 Tensorflow와 mnist 데이터를 이용해서 분석하는 실전으로 한번 더 복습하면 됩니다.

반응형
반응형

Pandas 라이브러리에 대한 간단한 소개와 몇 가지 자주 사용되는 기능에 대해서 정리합니다.

 

1. Pandas?

파이썬에서 데이터 전처리를 할 때 가장 많이 사용되는 라이브러리 중 하나입니다.

 

Pandas라이브러리의 기본은 DataFrame이라는 구조에서 시작됩니다.

 

DataFrame(데이터 프레임)은 Excel과 같은 표로 된 형태로 데이터를 관리합니다. 아래 샘플 코드를 봐주세요.

 

import pandas as pd

data = { 'Outlook' : ['Rainy', 'Rainy', 'Overcast', 'Sunny', 'Sunny', 'Sunny', 
                      'Overcast', 'Rainy', 'Rainy','Sunny','Rainy','Overcast', 
                      'Overcast','sunny'
                     ],
         'Temp' : ['Hot','Hot','Hot','Mild','Cool','Cool','Cool','Mild','Cool',
                  'Mild','Mild','Mild','Hot','Mild'],
         'Humidity' : ['High','High','High','High','Normal','Normal','Normal',
                      'High','Normal','Normal','Normal','High','Normal','High'],
        'Windy' : ['False','True','False','False','False','True','True','False',
                  'False','False','True','True','False','True'],
        'Playgolf' : ['No','No','Yes','Yes','Yes','No','Yes','No','Yes','Yes','Yes',
                     'Yes','Yes','No']
}

df = pd.DataFrame(data)

폴더에 쌓인 많은 자료들중 아무 데이터나 갖고 와 봤습니다.

 

위의 코드를 보면, data라고 정의된 부분을 보면, key로 Outlook, Temp, Humidity 등이 설정되어있고, 리스트 형태의 Value들이 존재하는 것을 볼 수 있습니다.

 

그리고 이렇게 만들어진 data를 Pandas에 DataFrame으로 넣어주는데요. 이렇게 만들어진 데이터 Frame을 보면 아래와 같습니다.

 

DataFrame

보게 되면, Dict의 Key에 해당하는 부분이 Column으로 오게 되고, Value에 해당하는 내용들이 순서대로 0~13까지 들어간 것을 볼 수 있습니다.

 

이러한 형태의 데이터를 Pandas의 DataFrame이라고 부릅니다.

 

2. 자주 사용되는 함수들

Pandas에서는 많은 함수들을 제공합니다. DataFrame에 들어있는 데이터들을 쉽고 빠르게 핸들링하기 위함이죠.

 

주의할 점은 동일한 결과를 위한 함수라도 사용방법에 따라서 속도가 수십 배씩 차이가 날 수 있습니다.

 

특히 핸들링하는 데이터의 크기가 수백GB이상이되면 그 차이에 따라서 단 몇 분이면 끝나는 작업이 며칠이나 걸리는 경우도 허다합니다.

 

따라서 많은 기능들을 알고 적절하게 사용하는 게 중요합니다.

 

먼저 원하는 데이터들을 찾아내는 필터링에 대해서 정리하겠습니다.

 

- 특정 Column 선택하기

  • df[ 'Humidity' ] : 특정 Column(Humidity)의 데이터들을 뽑아냅니다.(출력 형태 : Pandas Series)
  • df[[ 'Humidity' ]] : 특정 Column(Humidity)을 뽑아냅니다.(출력형태 : Pandas DataFrame)
  • df[[ 'Humidity, 'Outlook' ]] : 특정 Column들(Humidity, Outlook)을 뽑아냅니다.(출력형태 : Pandas DataFrame)

 

각가의 실행결과

 

- 특정 Row 선택하기(loc, iloc)

DataFrame에서 Index는 DataFrame이 생성됐을 때 기준으로 설정됩니다. 따라서 중간에 Row가 삭제되거나, 새롭게 정렬하는 경우 Index번호가 순서대로 설정되지 않는 경우가 발생합니다.

 

따라서 특정 Row들을 뽑아낼 때, 이 Index로 뽑아내는 경우, 어떤 기준으로 뽑을지에 따라서 두 가지로 나눠집니다.

 

다음과 같이 Outlook Column을 기준으로 새롭게 정렬된 DataFrame은 Index의 순서가 섞여있는 것을 볼 수 있습니다.

df.sort_values('Outlook')

여기서 특정 Row를 선택해보겠습니다.

 

  • df.sort_values('Outlook').loc[3:9] : Index번호가 3인 것부터 9인 것까지 출력합니다.
  • df.sort_values('Outlook').iloc[3:9] : Index번호와 상관없이 3부터 9번 row를 출력합니다.(시작=0)

 

- 정렬(sort_index, sort_values)

  • df.sort_index() : Index 기준으로 정렬을 수행합니다. (중간에 삭제된 Index들이 새로 생기지는 않습니다.)
  • df.sort_values(by) : by에 해당하는 Column의 값을 기준으로 정렬합니다.

 

옵션

ascending = True(기본) / False  :  True는 오름차순, False는 내림차순 정렬입니다.

inplace=True / False(기본)  :  정렬한 결과를 기존 DataFrame에 반영할지 여부입니다.

 

 

- reset_index

기존 DataFrame의 Index를 새로 설정합니다. 기존의 Index는 새로운 Column으로 만들어집니다.

 

drop = True 옵션을 적용할 경우 기존 Index가 새로운 Column으로 만들어지지 않고 삭제됩니다.

 

- T (Transpose)

Index와 Column의 위치를 바꿉니다.

 

실행결과

- astype(type)

특정 Column의 데이터 타입을 변경합니다.

df['Outlook'] = df['Outlook'].astype('str') 과 같이 사용 가능합니다.

주로 숫자 데이터가 문자로 되어있는 경우 int64나 float64로 변환합니다.

 

- dropna

DataFrame에서 특정 값이 비어있는 경우가 있습니다. 사람에 따라서 이것을 Null, NA, NaN, None 등 다양하게 부릅니다.

이러한 데이터는 숫자도, 문자도 아니기 때문에 특정값으로 변형하거나 삭제하는 작업이 필요합니다.

 

dropna는 이러한 값을 삭제해주는 함수입니다.

df.dropna() : 빈 값이 존재하는 Row를 제거합니다.

 

- drop

특정한 Column을 제거하는데 주로 사용됩니다.

df.drop(columns = '컬럼명')의 형태로 자주 사용합니다.

 

- fillna(value)

위에서 언급한 것과 같이 빈 값은 그대로 사용이 불가능하기 때문에, 다른 값으로 변경하거나 제거해야 할 필요가 있다고 말씀드렸습니다.

fillna(Value)는 이러한 빈 값을 특정한 Value로 대체하는 역할을 합니다.

 

- isnull

또또, 이 녀석은 데이터에 빈 값이 존재하는지 확인하는 용도로 사용됩니다.

빈 값은 True로 아닌 값은 False를 반환합니다.

따라서 보통 이것만 사용되는 경우는 거의 없고, 저는 주로 특정 컬럼에 빈 값이 몇 개나 있는지 등의 용도로 사용합니다.

 

df.isnull().sum()

 

sum은 원래는 컬럼별로 숫자들을 더해주는 역할을 하는데 컴퓨터에서 False = 0, True = 1로 값을 다루는 경우가 많다보니 위와같이 사용할 경우 컬럼별로 빈 값의 개수를 반환해주게 됩니다.

 

x는 Null값만 존재하는 Column

- info

가장 중요한 녀석인데, 뒤늦게 나왔네요.

DataFrame의 정보를 요점 정리해서 보여줍니다.

위와 같이 각 컬럼에 대해서 Null 값의 개수와, 데이터 타입 등의 정보를 알려줍니다.

데이터를 불러오고 가장 먼저 사용하는 기능이며, 전처리가 끝난 후 최종적으로 확인하는 데 사용되는 기능이기도 합니다.

 

- columns

DataFrame의 Column 이름을 확인하거나 재정의할 경우 사용됩니다.

df.columns : 칼럼들의 이름 확인

df.columns = ['col1', 'col2' ~] : 컬럼명 재정의

 

- pd.concat( [ A , B ] )

DataFrame에 적용되는 기능이 아니라 pandas에 붙는 녀석임을 주의하시기 바랍니다.

이 기능은 둘 이상의 데이터를 연결하는 데 사용합니다.

여기서의 연결방식은 A데이터 아래에 B데이터를 붙이는 것으로 두 개의 DataFrame이 동일한 Column들을 갖고 있다는 가정에서 Row가 늘어나는 형태로 데이터가 늘어가게 됩니다.

 

- pd.merge( left, right, how='inner', on=None, left_on=None, right_on=None ~ )

정말 중요한 기능이어서 옵션들까지 몇 개 적었습니다.

SQL에서 Join을 생각하셔도 좋습니다. 실행 형태는 아래와 같습니다.

 

pd.merge( A, B ) : A와 B 두 개의 DataFrame에서 동일한 이름의 Column을 기준으로 병합합니다.

여기서의 병합은 A의 Column옆에 B의 Column을 추가하는 경우를 말합니다.

 

pd.merge( A, B, how='left' ) : how에는 left, right, inner의 3가지 경우가 사용됩니다.

left = A DataFrame은 그대로 둔 상태로 B를 붙입니다. 이때 맵핑되는 값이 없으면 Null 값이 생깁니다.

right = B를 기준으로 합칩니다.(위와 반대)

inner = 위의 결과 중 하나에서 null값이 존재하는 row를 제거한 형태입니다.

 

상세한 내용은 여기를 참고하세요.

 

https://datascienceschool.net/view-notebook/7002e92653434bc88c8c026c3449d27b/

 

Data Science School

Data Science School is an open space!

datascienceschool.net

 

 

일단 중요한 기능들은 이런 것들이 있습니다.

 

unstack이나 groupby 등 여러 가지 녀석들이 있지만, 이런 것들은 나중에 작업하면서 다시 다루겠습니다.

반응형

'머신러닝 > 데이터 전처리' 카테고리의 다른 글

[Colaboratory] 구글 Colab 사용하기  (1) 2019.07.17
반응형

scp명령어는 원격서버로 파일을 전송하는 경우와 파일을 원격서버로부터 갖고오는 경우로 나눠집니다.

 

0. SCP란?

SCP는 기존 파일전송 프로토콜들에 부족했던 보안성을 강화한 파일전송 프로토콜입니다.

기본적으로 ssh의 보안통신을 이용하기 때문에 포트는 ssh와 동일한 tcp/22번 포트를 사용하게됩니다.

scp를 이용한 전송과 기존 전송프로토콜을 이용한 전송시의 보안 차이점에 대해서는 [네트워크 카테고리]부분에 곧 올릴 예정입니다.

 

1. 원격서버로 파일전송하기

scp [옵션] [전송할 파일 경로] [서버계정]@[서버주소]:[파일 저장경로]

 

ex) scp -p 8888 /users/YoungQ/MyData pi@192.168.0.80:/home/DataFolder/

 : 포트 8888을 이용하여 MyData를 pi계정(192.168.0.80)의 /home/DataFolder/ 디렉토리에 저장한다.

 : -p 는 포트번호 지정옵션(기본은 22번)

2. 원격서버에서 파일 갖고오기

scp [옵션] [서버계정]@[서버주소]:[갖고올 파일 경로] [내부 저장경로]

 

ex) scp -r pi@192.168.0.80:/home/DataFolder/* /users/YoungQ/

 : pi계정(192.168.0.80)의 DataFolder이하의 모든 파일을 youngQ폴더 이하에 저장한다.

 : -r은 하위의 모든 파일 및 폴더를 의미

 

scp명령어는 앞에오는 곳에서 다음에오는 곳으로 파일을 전송하는 형태입니다.

 

 

 

반응형

'운영체제 > 리눅스 명령어' 카테고리의 다른 글

[Linux] SCP를 사용한 파일전송  (0) 2019.01.03
반응형

구글 API에 올라와있는 샘플코드를 응용하여 만들었습니다.

 

Python 코드

 

from google.cloud import texttospeech

client = texttospeech.TextToSpeechClient()

voice_eng = texttospeech.types.VoiceSelectionParams(
    language_code='en-US',
    ssml_gender=texttospeech.enums.SsmlVoiceGender.NEUTRAL)

voice_kor = texttospeech.types.VoiceSelectionParams(
    language_code='ko-KR',
    ssml_gender=texttospeech.enums.SsmlVoiceGender.NEUTRAL)

audio_config = texttospeech.types.AudioConfig(
    audio_encoding=texttospeech.enums.AudioEncoding.MP3)

-> 기본적으로 음성변화 기능을 불러오는 코드입니다.

 

def exchange_eng(input_text): # 영어를 음성으로 변형하기
    synthesis_input = texttospeech.types.SynthesisInput(text=input_text)
    response = client.synthesize_speech(synthesis_input, voice_eng, audio_config)
    return response.audio_content

def exchange_kor(input_text): # 한국어를 음성으로 변형하기
    synthesis_input = texttospeech.types.SynthesisInput(text=input_text)
    response = client.synthesize_speech(synthesis_input, voice_kor, audio_config)
    return response.audio_content

-> 텍스트를 음성으로 변형시키는 함수입니다.

 

def makeFile(textList, *adder):
    if len(adder) == 0: adder = 'output'
    else : adder = adder[0]
        
    for i, text in enumerate(textList):
        if type(text) == type(list()):
            with open('/Users/youngQ/tts_output/'+str(adder)+str(i)+'_eng.mp3', 'wb') as out:
                out.write(exchange_eng(text[0]))
            with open('/Users/youngQ/tts_output/'+str(adder)+str(i)+'_kor.mp3', 'wb') as out:
                out.write(exchange_kor(text[1]))
        else:
            with open('/Users/youngQ/tts_output/'+str(adder)+str(i)+'.mp3', 'wb') as out:
                out.write(exchange_eng(text))

-> 음성으로 변환된 파일을 저장하는 코드입니다.

 

 

다음은 위의 코드를 실행하는 부분입니다.

 : makeFile( 변환할 텍스트 리스트, 저장할 파일명 ) 입니다.

 

1) 단순 영어를 음성으로 변형시키는 경우

location = ['in front of a fountain', 'in a clothing store', 'at a construction site', 'at a plaza',
           'in a parking lot', 'in a shopping district', 'at a crosswalk']
makeFile(location, 'location')

2) [영어 + 한국어] 텍스트를 음성으로 변형하는 경우

behavior = [['he is sitting arm in arm', '그는 팔짱을끼고 앉아있다.'], 'they are holding hands', 
            ['he is holding up someting', '그는 무언가를 들고있다.'],
            ['they are smiling at each other', '그들을 서로를 보며 웃고있다.'],
            ['he is legs crossed', '그는 다리를 꼬고있다.'], 
            ['A man is raising his hand', '한 남자가 손을 들고있다.'],
            ['he is taking a walk', '그는 산책을 하고있다.'],
            ['A man is crossing a street','한 남자가 길을 건너고있다.'],
            ['A man is working at a construction site','한 남자가 건설현장에서 작업하고있다.'],
            ['They are having a meeting at work', '그들은 직장에서 회의중이다.'],
            ['They are looking at something', '그들은 무언가를 보고있다.'],
            ]
makeFile(behavior, 'behavior')

 

실행결과

위에 makeFile 뒤에 오는 인자가 파일명에 해당합니다.

 

반응형
반응형

구글 API로 문자를 음성으로

구글 API 등록부터 입력한 문자를 음성으로 저장하는 방법을 정리합니다.

Python코드는 다음 페이지에 있습니다.

 

구글 API 관리 : https://console.developers.google.com

 

Google Cloud Platform

하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.

accounts.google.com

 

Cloud Text-to-Speech API

사용할 API의 이름입니다.

 

1) 프로젝트 생성하기

현재 tts proj라는 기존의 프로젝트가 있는 상태입니다.

따라서 새로 프로젝트를 생성해주겠습니다.(프로젝트 생성방법은 큰 차이가 없습니다.)

프로젝트 생성
[새 프로젝트] 클릭
프로젝트 이름 설정 후 만들기

위와같은 순서로 진행됩니다.

프로젝트 이름은 본인이 사용할 API들을 관리하는 하나의 큰 틀이라고 생각하시면 좋습니다.

 

2) API 설정하기

상단에 프로젝트명이 바뀐것을 볼 수 있습니다.

위와같이 프로젝트가 생성이되면, [EABLE APIS AND SERVICES]를 클릭하여 프로젝트에 API를 새로 추가하겠습니다.

API 검색

사용할 API의 이름을 검색하고 선택합니다.

[사용 설정] 클릭

 

 

API 사용 설정 버튼을 클릭하시면 결제방법을 등록하시라는 창이 나올 수 있습니다.

처음 사용하시는 중이라면 무료 크리딧이 주어집니다.

또한, 일정 사용량까지는 무료로 제공되기 때문에 제품을 위한 API가 아니고 혼자 사용하시는 것이라면 큰 결제가 발생하지는 않습니다.

API 가격표

 

3) 사용자 인증정보 만들기

 

위와같이 API사용중지라는 버튼이 활성화된 상태라면, API설정이 완료된 상태입니다.(클릭하지마세요!!!)

 

우측에 [사용자 인증 정보 만들기]를 클릭하세요.

 

인증정보 설정

 

사용할 API를 선택하세요.

 

적당히 선택하시면됩니다.

 

키 생성 완료

 

키 생성완료가되면 위의 파일이 PC에 저장됩니다.

 

이제 환경변수만 설정과 SDK설치만하면됩니다!!

 

 

거의 다 왔습니다!!

 

 

4) 환경변수 설정하기

API문서를 참고하였습니다.

 

OS에 따라서 설정방법이 다르기 때문에 아래를 참고하셔서 설정해주시면 감사하겠습니다.

 

 

 

[OSX에서 환경변수 설정 후 확인한 내용입니다.]

환경변수 확인

 

SDK 설치하기

https://cloud.google.com/sdk/docs/

 

Google Cloud SDK 문서  |  Cloud SDK  |  Google Cloud

Google Cloud SDK 문서 Google Cloud SDK는 Google Cloud Platform에서 호스팅되는 리소스와 애플리케이션을 관리하는 데 사용할 수 있는 도구 집합으로, 여기에는 gcloud, gsutil, bq 명령줄 도구가 포함됩니다. cloud 명령줄 도구는 Cloud SDK와 함께 다운로드됩니다. gcloud 명령줄 도구 개요에서 gcloud CLI에 대한 종합 가이드를 참조할 수 있습니다. 또한 gcloud CLI 참조에는 g

cloud.google.com

구글은 보안을 위해서인지 API키 파일을 통해 직접 API서버에 접속하지 않고 SDK를 통해서 API를 관리합니다.

 

위의 링크에서 해당 프로그램을 설치하시면됩니다.

 

 

 

SDK까지 설치가 끝나시면 이제 프로그램코드 부분으로 넘어갑니다.

 

이어지는 다음 페이지에 해당 코드가 있습니다.

반응형
반응형

Python으로 WOL 매직패킷 전송하기

사실 별거 없다... 파이썬 socket통신을 이용하면 될 뿐이기에...

 

1. WOL 패킷 생성코드

import socket, struct

def WOL(macAddr):
    sep = macAddr[2]
    macAddr = macAddr.replace(sep,'')
        
    data = b'FFFFFFFFFFFF' + (macAddr * 16).encode()
    send_data = b''
    
    for i in range(0, len(data), 2):
        send_data += struct.pack('B', int(data[i: i + 2], 16))
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    sock.sendto(send_data, ('192.168.35.255',9))
    
WOL('11:22:33:44:55:66')

코드 설명

 > sep = macAddr[2]
 > macAddr = macAddr.replace(sep,'')

 : MAC주소에서 ':' 을 제거합니다.

 

 > data = b'FFFFFFFFFFFF' + (macAddr * 16).encode()
 > send_data = b''

 : data는 WOL 패킷에 전송할 데이터이며, send_data는 실제 전송을 위해서 인코딩된 값이 들어갑니다.

 

 > for i in range(0, len(data), 2):
 >     send_data += struct.pack('B', int(data[i: i + 2], 16))

 : struct.pack(format, value) 함수는 value에 해당하는 값을 원하는 포맷으로 반환합니다.

 : 'B'는 unsigned char형태를 의미합니다. 와이어샤크에서 봤었듯이 전송할 데이터가 FF FF FF 와 같이 2byte 단위 데이터이기 때문에 2byte씩 끊어서 unsigned char형태로 변환해주는 작업을 해주었습니다.

 : 포맷형식을 변환하여 사용도 가능하지만, 예를들어 unsigned int를 사용할 경우 8byte의 반환값을 갖기 때문에 range(0, len(data), 8)로 설정해줘야하며, 이 경우 전체 데이터의 길이가 8로 나누어 떯어지지 않으면 별도의 처리를 해야하는 문제가 있습니다.

 

 > sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

 : socket을 정의합니다. 전송할 WOL패킷은, UDP를 사용하기 때문에 SOCK_DGRAM을 사용합니다.

 

> sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

 : socket의 옵션을 설정합니다. 망내에 Broadcasting 시킬 예정이기에 위와같이 설정해야합니다.

   (아래와같이 망주소를 알 경우 안써도 되는거 같습니다.)

 

 > sock.sendto(send_data, ('192.168.35.255',9))

 : 변환된 데이터를 원하는 망(192.168.35.255)에 9번 포트로 전송합니다.

 

전송결과

와이어 샤크 화면

위에 보이

는것처럼, 전송결과 WOL프로토콜로 인식되는 패킷을 송신하는 것을 볼 수 있었습니다.

패킷의 전송내용도 기존에 어플을 이용해서 보냈던것과 거의 큰 차이가 없습니다.

 

차이는 ID, Checksum, 그리고 flags에서 보이는데, ID는 패킷마다 독립적으로 부여되는 값이기에 다른것이 정상이며, Checksum 역시 패킷의 값에 의존하기 때문에 달라질 수 있습니다. (기능적 문제 X)

 

Flags에서 차이가 있었는데, 확인하보니 Don't Fragment에 대한 부분이 채크가 안된것을 볼 수 있었습니다.

 

하지만, 전송하는 데이터의 크기가 144byte기 때문에 정상적인 망에서 해당 패킷이 Fragment(단편화)가 될 일이 없음으로 전혀 문제가 없습니다.

 

이상입니다~

 

끝 ㅎㅎ

 

궁금한것 댓글로 주세요~

반응형
반응형

와이어샤크 + WOL + python

실제 구현에 관련된 코드는 2부에 있습니다.

1부에서는 와이어샤크로 WOL패킷을 확인하고 간단한 이론을 보겠습니다.

 

WOL

WOL은 전원이 종료된 컴퓨터의 랜카드에 특별한 패킷을 송신함으로써 PC를 켜주는 기능을 의미합니다.

WOL을 수행하기 위해서는 기본적으로 PC의 랜카드가 컴퓨터 종료 후에도 WOL 패킷(매직패킷)을 수신할 수 있는 상태여야합니다.(이부분은 여기서 다루지 않겠습니다.)

 

Wireshark

와이어샤크는 네트워크 패킷을 분석하는 가장 대중적인 툴입니다.

간편하게 현재 랜카드가 송신/수신한 모든 패킷들을 확인 할 수 있으며, 해당 패킷의 정보를 쉽게 확인할 수 있도록 간편한 인터페이스를 제공합니다.

 

WOL 패킷확인

Wake On Lan 어플

 

 

 WOL 패킷 확인을 위해서 해당 패킷을 전송하는 어플 [Wake On Lan]을 사용했습니다.

 

 

 

 

왼쪽에 보이는 것처럼 [wol test]라고 [11:22:33:44:55:66]이라는 맥주소를 갖고있는 컴퓨터에 WOL 패킷을 전송하도록 해주었습니다.

 

이때 와이어샤크로 감자하는 PC와 해당 스마트폰은 동일한 네트워크망에 접속되어있어야합니다.(공유기 종류 무관)

 

 

 

 

 

 

 

 

 

 

 

 

 

와이어 샤크 패킷수신화면

WOL이 사용하는 udp 9번 포트를 필터링한 결과 3개의 패킷이 전송된 것을 볼 수 있었습니다.

(맥주소는 굳이 가려봤습니다.)

 

한번에 어플이 3개의 패킷을 송신하는 것을 볼 수 있었습니다.

 

 

패킷정보(총 144byte)

와이어샤크 수신 패킷

와이어샤크 화면 하단에 표시된 내용을 순서대로 말씀드리겠습니다.

 

 

Ethernet 계층 (MAC프레임)

Ethernet (Data Link) Layer
이미지 출처 : 정보통신기술용어해설

  • DA(Dst Mac Address) = 'ff ff ff ff ff ff'
  • SA(Src Mac Address) = '50 77 05 -- -- --' 
  • Ethertype(Ethernet Protocol Type) = '08 00' (IPv4)

참고) 이더넷 타입표

  • Data = Layer3 이상부분

 

 

 

Network 계층 (IP Header)

Network Layer
이미지 출처 : 정보통신기술용어해설

  • Verson = '4'
    • IPv4
  • Header Length = '5'
    • Header Length는 위 IP헤더에서 한 줄을 의미합니다.
    • 즉 5x4byte = 20byte로 IP헤더의 최소길이를 의미합니다.
  • Type of Service = '00'
    • 미할당 영역으로 추가기능을 위한 공간입니다.
  •  Total Length = '00 82'
    • 8x16+2 = 130byte
    • 즉, IP Packet = Header(20byte) + Data(110byte) 로 이루어집니다.
  • Identification = '29 22'
    • Packet에 부여되는 식별자(오류제어등에 사용됨)
  • Flags + Fragment offset
    • Flags는 3bit 공간에 각 자리수가 특정의미를 갖음
    • [ Reserved bit | Don't Fragment | More Fragments | 
    • 40 = 010 = Don't Fragment
    • offset은 단편화가 된 경우 패킷의 순서를 확인하는 용도로 사용됨
  • TTL(Time to Live) = '40'
    • 패킷이 통과할 수 있는 노드의 수를 의미합니다.
    • 노드를 통과할 때 마다 1씩 감소하며 0이되면 전송실패와 함께, ICMP 메시지를 전송합니다.
  • Protocol type = '11'
    • 프로토콜 맵팽은 아래와 같습니다.
    • ICMP = 1 | IGMP = 2 | TCP = 6 | EGP = 8 | UDP = 17 | OSPF = 89 등...
    • 11 = 10진수로 17(즉, UDP를 의미)
  • Header Checksum = '48 69'
    • Checksum은 오류검출용 코드입니다.
  • Src IP Addr = 'c9 a8 23 90' (192.168.35.144)
  • Dst IP Addr = 'c0 a8 23 ff' (192.168.35.255)
    • WOL 기능은 목적지 주소를 망주소로 전송합니다.

 

 

 

Transport (UDP Datagram)

Transport Layer (UDP Datagram)
이미지 출처 : 정보통신기술용어해설

  • Src Port = 'eb e5' (60389)
  • Dst Port = '00 09' (9)
    • WOL은 수신 Port로 7 또는 9를 사용합니다.
  • Length = '00 6e' (110)
    • 위어서 언급한 것처럼, IP Packet에서 Data영역이었던 UDP부분이 110Byte임을 볼 수 있습니다.
  • Checksum = 'ad 79'
    • 수신측 오류확인을 위해 사용합니다.

 

 

 

Application (WOL Data)

Application Layer (WOL Data)

WOL은 특별한 데이터를 넘겨줍니다.

UDP Data로 들어온 WOL 정보

'FF FF FF FF FF FF' Broadcast MAC 주소와 목적지의 MAC 주소의 조합으로 이루어집니다.

 

위와 같이 하나의 'Broadcast' + 16개(또는 20개)의 '목적지 MAC 주소'로 이루어집니다.

 

 

 

 

끝?

 

다음 게시물은 위의 패킷을 생성하는 파이썬 코드를 보겠습니다. 이상입니다.

반응형
반응형

네이버 동영상 크롤링

완료 누르기 전에 미리보기 눌렀다가 실수로 작성한글 날려서 처음부터... 덕분에 하루늦게 올립니다.

시작하기 전에

크롤링 공부를 위한 자료입니다. 데이터 수집을 위한 다양한 방법을 소개하기 위한 포스터로 개인의 공부 등을 위해서만 아래 내용을 사용해주시면 감사하겠습니다.

네이버를 포함하여 웹서버에 과도한 트래픽을 발생시키거나, 다운받은 영상을 공유할 경우 영업방해와 저작권위반등에 문제가 발생할 수 있습니다.

이에따른 문제에 대해서는 책임지지 않습니다.

 

1. URL 얻어오기

여직까지 URL을 찾는다고 표현을 해왔는데, 이번에는 얻어온다고 표현하겠습니다.

15초 광고 후 재생의 경우에는 확인해보니 광고가 재생되는 시점에 웹브라우저가 서버로부터 광고 후 재생될 영상의 url을 전송받는 것을 확인할 수 있었습니다.

 

크롬 네트워크

[ 크롬 -> 검사 -> 네트워크 ]로 들어가보면 위와같은 화면을 볼 수 있습니다.

확인해보니 이 시점에 영상의 url을 전송받으며, 광고가 끝난 후 영상을 전송받는 것을 확인 할 수 있었습니다.

 

영상의 URL을 담은 응답메시지

위 화면에서 "source" : "~~~" 라고 되어있는 부분이 영상의 URL이 되는 부분입니다.

확인해보니 영상의 해상도에 따라서 URL이 서로 다른것을 볼 수 있었습니다.

 

저 응답메시지를 직접 파이썬에서 불러와서 확인하면 좋겠지만, 아직미숙해서...

 

저는 요청메시지를 그대로 갖고와서 서버로부터 응답메시지를 받아서 처리하는 방법으로 가보겠습니다.

 

2. 요청메시지(Request)

요청메시지를 먼저 확인해보겠습니다. 

 

요청메시지

GET 메서드를 이용해서 전송되는 요청메시지의 파라미터들은 위와같습니다.

일부 내용은 요청메시지마다 중복되는 것들이겠지만, 영상의 종류에 따라서 내용이 많이 다를 수 있기 때문에 파라미터들에 들어갈 내용을 분석해보지는 않겠습니다.

 

저 파라미터 내용은 나중에 심심하면 어떻게 만들어지는지 한번 하나씩 분석해보겠습니다.

 

어찌되었든, 우리의 브라우저에서 저러한 메시지를 웹서버로 전송하기 때문에, 브라우저 로그를 기록하여 요청메시지를 얻어보겠습니다.

 

브라우저 로그

위와같은 방식으로 브라우저를 실행하면 위와같이 전송된 요청메시지를 확인 할 수 있습니다.

 

3~4초에 800개정도의 메시지가...보내졌습니다...

 

우리는 이 많은 메시지에서 원하는 메시지(URL을 응답받을 수 있는 메시지)를 찾는 작업을 해야합니다.

 

흠...

 

요청파라미터의 내용을 보셔서 아시겠지만, 전송되는 메시지의 길이가 상당히 긴 편입니다.

따라서 메시지 길이가 6000자 이하면 버리도록 하겠고, 또하나 메시지에 

 

[ "url":"(https://apis.naver.com/rmcnmv/rmcnmv/vod/play ] 라는 내용이 존재해야합니다. 요청메시지의 기본내용이니까요. (혹시 틀리면 나중에 수정하겠습니다.)

 

따라서 위의 조건을 사용해서 원하는 메시지를 찾아보겠습니다.

 

요청메시지 확인하기

위와같이 실행해보니까 딱 하나, 요청메시지가 걸립니다. 빈 리스트들은 메시지가 6000이상이지만, 정규표현식에서 안잡히는 녀석들입니다.

 

3. URL 응답받기

마지막으로 매우 간단한 작업이 남았습니다.

import requests 를 해주신 후 앞에서 찾아낸 요청메시지를 전송하고, 응답메시지를 받으면 거기서 원하는 정보를 찾으면 끝입니다.

 

응답메시지에서 URL 확인

위와같이 원하는 부분을 추출할 수 있습니다. (JSON을 이용해도 무관합니다.)

 

여러개의 URL에 검색되는 것은 말씀드린 것처럼, 해상도별로 URL이 조금씩 다르기 때문입니다.

 

우리는 가장 고해상도를 필요로 함으로 마지막 append부분을 아래처럼 바꿔주겠습니다.

 

URL 확인

끝~

 

깔끔하게 하나의 URL을 얻어왔습니다.

 

결과화면

 

 

일단 여기까지!

 

에혀...

 

확인해보니까 15초 후 SKIP과 같은 방식도 위와같이 광고시간에 URL을 전송받더군요...

(왜 생각을 못했지...)

 

따라서 그냥 위의 코드만 이용해서 url을 얻어와도 될테고, 혹은 서버에 응답요청 한번이라도 덜주겠다 싶으시면, 그냥 skip버튼 활성화해서 클릭하셔도 될꺼같습니다...

 

큰 차이는 없을꺼 같네요...

 

다음에는 코드정리와 멀티프로세싱을 다루겠습니다.

반응형
반응형

네이버 동영상 크롤링

 

목표!

이전편에 말씀드린 것처럼 동영상 광고 후 스킵에대한 문제를 해결하도록 하겠습니다.

 

1. 의외로 간단한 해결...

5초/ 15초 광고 후 스킵이 가능한 영상의 코드를 확인해봤는데 단순히 skip버튼이 숨김상태로 존재하는 것을 확인할 수 있었습니다.

 

네... 그냥 script 수정해서 활성화 시켜주고, 클릭하도록 해주면 됩니다.

 

SKIP 버튼 확인

위 영상은 15초 광고 후 스킵이 가능한 영상입니다.

위에 붉게 칠해진 부분을 보면 [ button ] 속성을 볼 수 있습니다.

 

이부분이 SKIP 버튼에 대한 부분일 것을 볼 수 있습니다.

 

보게되면 style 영역에 [ display : none; ] 라고 되어있는 부분이 있는 것을 알 수 있습니다. (크흠...)

 

이부분을 [ display : block; ] 으로 변경해보면 아래같이 바뀌는 것을 볼 수 있습니다.

 

너무... 간단하네요... ㅎㅎ

 

 

SKIP 버튼 활성화

위와 같이 SKIP버튼이 활성화 되는 것을 볼 수 있습니다.

 

실제로 클릭하면 SKIP도 됩니다.

 

그럼 위의 과정을 코드로 작성하겠습니다.

 

먼저 XPath를 얻어와야합니다. (이전글에서 사용했던 방법 그대로 진행했습니다. id 변경해준 후 XPath Copy)

 

그다음 script를 수정해주는 코드를 넣어주고, 버튼에 click을 붙여주면 됩니다.

 

2. 코드

전체 코드

한칸한칸 설명드리겠습니다.

 

1) 기본 라이브러리 호출

2) 크롬브라우저 실행, 다운로드를 원하는 페이지 접속

3) 숨겨져있는 SKIP버튼 호출 (skip버튼의 상태가 none로 된걸을 볼 수 있습니다.)

4) SKIP버튼의 style을 display:block;으로 재설정 (skip버튼의 상태가 block으로 변한것을 볼 수 있습니다.)

5) 활성화된 SKIP버튼 클릭

6) 동영상 url을 갖고와서 저장

 

간단하게 첫번째 문제는 해결했습니다.

 

그럼 다음으로 두번째 문제, [광고 15초 후 재생]의 경우의 해결법을 찾아보겠습니다. (난항이 예상되는...)

반응형

+ Recent posts