본문 바로가기

Python/Python 웹 크롤링

파이썬 수업_07월 17일

  • 캡슐화

- 왜 써야하나?

 : 잘못된 값을 넣지 못하게 하기 위해

   ex ) myDate = MyDate(2001, 13, 34) //년, 월, 일 _ 잘못된 값 들어감

 

- 사용법

* java --> private 사용

* python --> self.__year = year 과 같이 사용

 : python 에서는 클래스 내부에서만 사용되는 변수 언더바 2개 - __year 사용

 

- 변수 불러올 때

* java --> getter, setter 

* python --> 아래와 같이 사용, 항상 getter가 먼저 선언되어있어야 하고, 쌍을 이루어 같이 선언되어있어야함

# getter
@property
def year():
    return self.__year
    
# setter
@year.setter
def year():
    self.__year = year
myDate.__year = 2005 (X)
myDate.year(2000) (O)
print(myDate.year)

 

- 예제들 

# Product class 선언
class Product(object):
    # 생성자
    def __init__(self, name):
        # __name이 private 변수
        self.__name = name

    # toString()
    def __str__(self):
        return f'Product의 이름은 {self.__name}'

    # getter
    @property
    def name(self):
        return self.__name

    # setter
    @name.setter
    def name(self, name):
        self.__name = name

# 객체 생성
product = Product('텔레비전')
print(product) #Product의 이름은 텔레비전
# print(product.__name) #AttributeError: 'Product' object has no attribute '__name'
print(product.name) #텔레비전
product.name = '안녕클레오파트라'
print(product) # Product의 이름은 안녕클레오파트라

 

  • 상속

: '부모의 재산이 내꺼다' 라는 뜻 ㅎㅎ

# 예시
class Manager
    # 속성
    name
    salary
    dept


class MereClerk
    # 속성
    name
    salary


# 속성이 계속 반복됨 --> 각자 클래스를 만들면서 속성을 개별적으로 만들지 말고 
# 공통적이 속성은 하나의 클래스(부모 클래스)에 만들어서 중복을 최소화 하자

# 의미상으로 
# Manager is a Employee
# MereClerk is a Employee
# 와 같이 의미가 성립이 되어야 상속 가능

class Employee
    # 공통 속성
    name
    salary


class Manager(Employee)  # java에서는 extends
    # 나머지 속성
    dept
# 부모 클래스 Person 선언
class Person(object):
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def about_me(self):
        print(f'Person의 이름은 {self.name}, 나이는 {self.age}')


# 자식 클래스
class Employee(Person):
    def __init__(self, name, age, gender, salary, hire_date):
        super.__init__(name, age, gender)
        self.salary = salary
        self.hire_date = hire_date

    def about_me(self):
        super().about_me()
        print(f'제 급여는 {self.salary} 원이구요, 제 입사일은 {self.hire_date} 입니다')

 

  • 추상클래스

- 메소드가 선언만 되고 구현이 안됨 --> 자식이 반드시 구현해줘야함

- 오버라이딩 반드시 해야함(선택 아닌 필수!!)

- 왜 만듬? 오버라이딩 강제적으로 하게 하기 위해

- abstract 키워드 따로 없음

//자바
class abstract Animal{
    abstract void my_method();
}

class Dog extends Animal{

}

class Cat extends Animal{

}

Animal ani = new Animal(); //--> (X) 이 자체가 안됨, 봉쇄
Animal cat = new Cat(); //--> (O)
Animal dog = new Dog(); //--> (O)

// --> 다형성 (One Interface, Multi Implements)

// 파이썬
// 자바와 달리 생성은 되지만 호출이 발생했을 때 Exception 발생
// abstract라는 키워드 없이 raise를 통해 exception발생시킴 ..?

 

  • 다형성

- Poly(다양한) + morphism(변형, 변신)

: One Interface, Multiple Implements

 

- Animal이라는 한가지 타입으로 여러 객체를 핸들링 할 수 있게 하기위해 사용

//Animal Type의 Array 생성
Animal ani = new Animal[3]
ani[0] = new Dog();
ani[1] = new Cat();

 

- 상속 & 다형성 예제

# abstract method를 가진 부모 클래스 선언
class Animal(object):
    def __init__(self, name):
        self.name = name

    # abstract method
    def talk(self):
        raise NotImplementedError('Subclass must implement abstract method')

class Cat(Animal):
    def talk(self):
        return 'Meow!'

class Dog(Animal):
    def talk(self):
        return 'Woof Woof!'
    def pet(self):
        return 'I,m Pet'

my_ani = Animal('동물')
#print(my_ani.name)#동물
#my_ani.talk() #에러 발생

animals = [Cat('고양이'), Dog('강아지1'), Dog('강아지2')]
for ani in animals:
    print(ani.talk())
    '''
    Meow!
    Woof Woof!
    Woof Woof!
    '''
    #print(ani.pet()) #'Cat' object has no attribute 'pet'

 

 

  • 모듈과 패키지

- .py 파일을 의미

- import문을 사용해 모듈 호출

- 모듈을 import하는 방법

 1) 모듈명 import하기

 2) 모듈명을 Alias 설정하기

 3) 모듈에서 특정 함수 또는 클래스만 import하기

 4) 모듈에서 모든 함수 또는 클래스를 import하기

 

[fah_converter.py]

# 섭씨를 화씨로 변환하는 함수
def convert_c_to_f(temperature):
    fah = ((9/5) * temperature) * 32
    return fah

def say_hello(msg):
    return "Hello" + msg

 

[using_converter.py]

# 섭씨 온도를 화씨 온도로 변환하는 코드
# 1. 모듈명을 import 하기 : from 시작기준은 프로젝트 폴더명 기준이다!!
from mycode import fah_converter
# 2. 모듈명을 import 하면서 alias 명 설정하기
from mycode import fah_converter as conv
# 3. 모듈에 속한 convert_c_to_f 함수만 import 하기
from mycode.fah_converter import convert_c_to_f
# 4. 모듈에 속한 모든 함수 import 하기
from mycode.fah_converter import *

print('변환하고 싶은 섭씨 온도를 입력해 주세요:')
temperature = float(input())
print('섭씨온도 :', temperature)

# 1. 모듈명.convert_c_to_f() 함수 호출
fah = fah_converter.convert_c_to_f(temperature)
# 2. aliasing 된 모듈명.convert_c_to_f() 함수 호출
fah = conv.convert_c_to_f(temperature)
# 3. import 된 convert_c_to_f() 함수 호출
fah = convert_c_to_f(temperature)

# print('화씨온도 :', round(result, 2))
# 소수점 둘째자리까지 출력
print('화씨온도 : {:.2f}'.format(fah))

print(say_hello('Python'))

 

- import class시 import한 출력값이 나오지 않도록 변경

 

* 아래와 같이 작성하면 다른 파일에서 import시 Hello 파이썬 출력문구가 같이 나옴

def say_hello(msg):
    return "Hello" + msg

print(say_hello(' 파이썬')) #Hello 파이썬

 

Terminal창에서 Test해본 결과

 

* main함수로 묶어주는게 좋음

def say_hello(msg):
    return "Hello" + msg
def main():
    print(say_hello(' 파이썬'))
main()

#Hello 파이썬

* 아래와 같이 제어문 넣어주면 다른 파일에서 import해도 Hello 파이썬이 출력됨

def say_hello(msg):
    return "Hello" + msg
def main():
    print(say_hello(' 파이썬'))

if __name__=='__main__':
    print('직접실행')
    main()
else:
    print('import 되어 실행됨')

 

Terminal창에서 Test해본 결과

 

 

- 빌트인 모듈 - 가변적인 값을 줄 때

* sys

import sys

def say_hello(msg):
    return "Hello" + msg

def main():
    msg = sys.argv[1]
    print(msg) #dooly
    if msg is None:
        print('enter msg')
    else:
        print(say_hello(msg)) #Hellodooly

#sys.argv[0]으로 바꾸면 Hellohello.py로 출력됨

if __name__=='__main__':
    print('직접실행')
    main()
else:
    print('import 되어 실행됨')

 

sys 사용 후 출력 값 - hello.py : 첫번째 인자값 / dooly : 두번째 인자값

 

* Built in module 참조 링크 : https://docs.python.org/3/py-modindex.html

 

Python Module Index — Python 3.8.4 documentation

numbers Numeric abstract base classes (Complex, Real, Integral, etc.).

docs.python.org

 

  • 패키지

- 다양한 모듈들의 합 : 폴더

- __init.py__ 파일이 디렉토리에 위치하면 파이썬은 패키지로 인식

- 다양한 오픈소스들이 패키지로 관리됨

 

  • 예외처리

- 사용이유 : 에러를 우아하게 내기위해

- 유형

   1) 예상 가능

   2) 예상 불가능

- 방법1 : try ~ excet구문 사용

try:
    예외 발생 가능 코드
except <Exception Type>
    예외 발생시 대응하는 코드

- 방법2 : built-in Excet구문 사용

- 방법3 : try ~ except ~ else

- 방법4 : try ~ except ~ finally

- 방법5 : raise 구문 - 에러를 강제로 발생 (java 에서 throw)

- 사용자 정의 예외

# 사용자 정의 Exception 클래스
# 음수 값이 입력되었을 때 강제로 예외를 발생기키기
class NegativePriceException(Exception):
    def __init__(self):
        print('Price can\'t be Negative')
        raise AttributeError

def calc_price(value):
    price = value + 100
    if price < 0:
        raise NegativePriceException
    return price

#result = calc_price(100)
#print(result) #1100
result = calc_price(-101)
print(result) #Price can't be Negative

 

- 예제

for i in range(10):
    result = 10 / i
    print(result) #ZeroDivisionError: division by zero

 

# try ~ except ~ else
# try ~ except ~ finally

for i in range(10):
    try:
        result = 10 / i
    except ZeroDivisionError as err:
        print(err) #ZeroDivisionError: division by zero
    else:
        print(result) 
    finally:
        print('종료되었습니다.')
'''
division by zero
종료되었습니다.
10.0
종료되었습니다.
5.0
종료되었습니다.
3.3333333333333335
종료되었습니다.
2.5
종료되었습니다.
2.0
종료되었습니다.
1.6666666666666667
종료되었습니다.
1.4285714285714286
종료되었습니다.
1.25
종료되었습니다.
1.1111111111111112
종료되었습니다.
'''

- raise 예제

while True:
    value = input("변환할 정수값을 입력해주세요")
    for digit in value:
        if digit not in "0123456789":
            raise ValueError("숫자값을 입력하지 않으셨습니다")
    print("정수값으로 변환된 숫자 -", int(value))

 

  • 로깅

사용 이유!!! : 

프로그램 개발 단계 있음(개발모드, 테스트모드, 운영모드 등)

print함수를 쓰면 개발모드, 운영모드 구분이 안돼

가장 중요한 이유 --> 로그레벨에 따라서 다르게 기록을 보기 위해서

 

**로그레벨 - debug < info < warn < error < fatal

logger.debug('aaa')

 

운영모드에서 error로 높여놓으면 debug로 찍은 것은 운영에서 나오지 않음 ^.<

 

- 로그 콘솔 출력

import logging

def say_hello(msg):
    return 'Hello' + msg

# logging 설정
logging.basicConfig(level=logging.DEBUG, \
                    format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of Program')
logging.debug(say_hello('디버그 모드'))
logging.info(say_hello('인포 모드'))
logging.debug('End of Program')

'''
2020-07-17 16:11:39,772 - DEBUG - Start of Program
2020-07-17 16:11:39,772 - DEBUG - Hello디버그 모드
2020-07-17 16:11:39,772 - INFO - Hello인포 모드
2020-07-17 16:11:39,772 - DEBUG - End of Program
'''

 

import logging

def say_hello(msg):
    return 'Hello' + msg

# logging 설정
logging.basicConfig(level=logging.INFO, \
                    format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of Program')
logging.debug(say_hello('디버그 모드'))
logging.info(say_hello('인포 모드'))
logging.debug('End of Program')

'''
2020-07-17 16:13:17,390 - INFO - Hello인포 모드
'''

 

- 로그 파일로 저장 , 콘솔 저장

import logging

def say_hello(msg):
    return 'Hello ' + msg

# logger 생성
root_logger = logging.getLogger()

# log level 설정
root_logger.setLevel(logging.DEBUG)

# logger file Handler 생성
fileHandler = logging.FileHandler('test.log', 'w', 'utf-8')

# logger console Handler 생성
streamHandler = logging.StreamHandler()


formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s : %(lineno)s - %(message)s')

# FileHandler에 file_formatter 설정
fileHandler.setFormatter(file_formatter)
streamHandler.setFormatter(formatter)

# logger 객체에 fileHandler와 streamHandler를 등록
root_logger.addHandler(fileHandler)
root_logger.addHandler(streamHandler)

root_logger.debug('Start of Program')
root_logger.debug(say_hello('debug 모드'))
root_logger.info(say_hello('info 모드'))
root_logger.warning(say_hello('warning 모드'))
root_logger.error(say_hello('error 모드'))
root_logger.debug('End of Program')


'''
2020-07-17 16:35:23,220 - DEBUG - Start of Program
2020-07-17 16:35:23,220 - DEBUG - Hello debug 모드
2020-07-17 16:35:23,220 - INFO - Hello info 모드
2020-07-17 16:35:23,220 - ERROR - Hello error 모드
2020-07-17 16:35:23,220 - DEBUG - End of Program
'''

 

test.log파일 생성됨

 

  • 파일 다루기

- 파일 읽기

- 예제문제

- 풀이

# mode 설정하지 않으면 default가 r (read)
# myfile = open('i_have_a_dream.txt')
# contents = myfile.read()
# print(contents)
# myfile.close()


# with 구문 사용
with open('i_have_a_dream.txt') as my_file:
    content = my_file.read()
    word_list = content.split(' ')
    line_list = content.split('\n')

print('Total Number of characters', len(content))
print('Total Number of word', len(word_list))
print('Total Number of line', len(line_list))

'''
Total Number of characters 9198
Total Number of word 1656
Total Number of line 87
'''

 

- readline()

# readline() 함수 사용
with open('i_have_a_dream.txt') as my_file:
    # line number
    i = 0
    while True:
        line = my_file.readline()
        if line.strip() != '':
            print(str(i) + '===' + line.strip())
        if not line:
            break
        i = i + 1

'''
0===I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation.
2===Five score years ago, a great American, in whose symbolic shadow we stand today, signed the Emancipation Proclamation. This momentous decree came as a great beacon light of hope to millions of Negro slaves who had been seared in the flames of withering injustice. It came as a joyous daybreak to end the long night of their captivity.
4===But one hundred years later, the Negro still is not free. One hundred years later, the life of the Negro is still sadly crippled by the manacles of segregation and the chains of discrimination. One hundred years later, the Negro lives on a lonely island of poverty in the midst of a vast ocean of material prosperity. One hundred years later, the Negro is still languished in the corners of American society and finds himself an exile in his own land. And so we've come here today to dramatize a shameful condition.
6===In a sense we've come to our nation's capital to cash a check. When the architects of our republic wrote the magnificent words of the Constitution and the Declaration of Independence, they were signing a promissory note to which every American was to fall heir. This note was a promise that all men, yes, black men as well as white men, would be guaranteed the "unalienable Rights" of "Life, Liberty and the pursuit of Happiness." It is obvious today that America has defaulted on this promissory note, insofar as her citizens of color are concerned. Instead of honoring this sacred obligation, America has given the Negro people a bad check, a check which has come back marked "insufficient funds."
8===But we refuse to believe that the bank of justice is bankrupt. We refuse to believe that there are insufficient funds in the great vaults of opportunity of this nation. And so, we've come to cash this check, a check that will give us upon demand the riches of freedom and the security of justice.
10===We have also come to this hallowed spot to remind America of the fierce urgency of Now. This is no time to engage in the luxury of cooling off or to take the tranquilizing drug of gradualism. Now is the time to make real the promises of democracy. Now is the time to rise from the dark and desolate valley of segregation to the sunlit path of racial justice. Now is the time to lift our nation from the quicksands of racial injustice to the solid rock of brotherhood. Now is the time to make justice a reality for all of God's children.
.
.
.
'''

 

- 파일 쓰기

my_file = open('count_log.txt', 'w', encoding= 'utf-8')
for i in range(1, 11):
    data = '%d번째 줄 입니다.\n' %i
    my_file.write(data)
my_file.close()

 

만들어진 count_log.txt 파일

 

my_file = open('count_log.txt', 'w', encoding= 'utf-8')
for i in range(1, 11):
    data = '%d번째 줄 입니다.\n' %i
    my_file.write(data)
my_file.close()

with open('count_log.txt', 'a', encoding= 'utf-8') as f:
    for i in range(100, 111):
        data = '%d 번째 줄입니다.\n' %i
        f.write(data)

 

만들어진 count_log.txt 파일

 

- os모듈 사용하여 활용하기

import os
# log 디렉토리가 없으면 log 디렉토리 생성
if not os.path.isdir('log'):
    os.mkdir('log')

with open('log/count_log.txt', 'a', encoding= 'utf-8') as f:
    for i in range(100, 111):
        data = '%d 번째 줄입니다.\n' %i
        f.write(data)

 

log폴더와 폴더 안에 count_log.txt 파일이 생성된 모습

- 연습문제

- 풀이(내가 푼 방법)

import os
import random
import datetime

# log 디렉토리가 없으면 log 디렉토리 생성
if not os.path.isdir('log'):
    os.mkdir('log')

with open('log/count_log.txt', 'a', encoding= 'utf-8') as f:
    for i in range(1, 11):
        stamp = str(datetime.datetime.now())
        value = random.random() * 100000
        f.write(f'stamp : {stamp}, value : {value}\n')

- 결과

결과 값

- 풀이(강사님 방법)

import os
import sys
# python directory_handling.py log/count_log.txt

#디렉토리가 없으면 log 디렉토리 생성
if not os.path.isdir("log"):
    os.mkdir("log")

if len(sys.argv) >= 2:
    file_name = sys.argv[1]
    print(file_name)

    print('file write start')
    #log/count_log.txt 파일이 존재하지 않으면
    if not os.path.exists(file_name):
        f = open(file_name, 'w', encoding="utf8")
        f.write("기록이 시작됩니다\n")
        f.close()

    with open(file_name, 'a', encoding="utf8") as f:
        import random, datetime
        for i in range(1, 11):
            stamp = str(datetime.datetime.now())
            value = random.random() * 1000000
            log_line = stamp + "\t" + str(value) +" 값이 생성되었습니다\n"
            f.write(log_line)
    print('file write ends')
else:
    print('enter file name')

- 실행방법

상단 directory_handling > Edit Configuration > Parameter에 원하는 파일 이름 입력후 실행하면 아래와 같이 생성

'Python > Python 웹 크롤링' 카테고리의 다른 글

파이썬 OpenAPI_07월 21일  (0) 2020.07.21
파이썬 OpenAPI_07월 20일  (0) 2020.07.20
파이썬 수업_07월 17일  (0) 2020.07.17
파이썬 수업_07월 16일  (0) 2020.07.16
파이썬 수업_07월15일  (0) 2020.07.15
파이썬 설치 및 특징  (0) 2020.07.14