#숙제 1번
chache = {} # key, value pair 를 사용하기 위해서 dict에 데이터 저장
class Fibonacci():

    def __init__(self):
        self.cache = {}    # 빈 딕셔너리다.
    
    def __call__(self, n):
        if n in self.cache:   
            return self.cache[n]
        # n이 self.cache에 없는 경우 -> n<0, n=0 n=1 -> fibo(0)=0, fibo(1)=1
        if n < 0:
            return 0
        if n == 0:
            self.cache[n] = 0
            return self.cache[n]   # return fibo(0)
        if n == 1:
            self.cache[n] = 1
            return self.cache[n]    # return fibo(1)
        
        result = self.__call__(n-1) + self.__call__(n-2)
        self.cache[n] = result
        return self.cache[n]

fibo = Fibonacci()    #피보나치 객체, 현재까지 저장된 피보 결과값 ({})

fibo(7)

#리펙토링
chache = {}

class Fibonacci():
    # 앞의 것은 정의가 재귀함수로 되어 있고 기본값으로 되어 있다.
    # 초기값 설정으로 날릴 수 있어
    def __init__(self):
        self.cache = {}
        self.cache[0] = 0
        self.cache[1] = 1
        
    def __call__(self, n):
        if n in self.cache:
            return self.cache[n]
        if n < 0:
            return 0
        
        result = self.__call__(n-1) + self.__call__(n-2)
        self.cache[n] = result
        return self.cache[n]
    
    def __str__(self):    #원하는 형태로 출력하기 위해서
        return "\n".join([      #한줄 한줄은 문자열의 리스트로 조인하겠다.
                "fibo({n}) = {result}".format(n=key, result=value)
                for key, value
                in self.cache.items()
            ])

fibo = Fibonacci()    #피보나치 객체, 현재까지 저장된 피보 결과값 ({})
fibo(5)

print(fibo)

class Student():
    def __init__(self, name):
        self.name = "kipoy"
        
kipoy = Student("김기표")

kipoy.name   #str. 타입만 다를 뿐이지 같은 예이다.

fibo.cache   #dict

"""
Explanation: 1T_피보나치 구현 - Class 를 이용하여 구조화해서 해결하기
End of explanation
"""


class Student():
    def __init__(self, name):
        self.name = "kipoy"
        
    def create_study_mate(self, other):   #self, other
        pass

# kipoy.create_study_mate(kimkipyo)
# kimkipyo = Student(...)

"""
Explanation: 클래스의 역할은 관련 있는 값들과 관련 있는 행동(메쏘드)를 모아놓는 역할
관련 있는 값(속성) + 관련 있는 행동(함수, 메쏘드)
값이라는 것은 클래스가 가지고 있는 속성들
예를 들면 student의 경우에는 이름, 나이, 자기 소개 텍스트
행동은 함수(메쏘드)
End of explanation
"""


import requests

# import bs4
from bs4 import BeautifulSoup

BASE_URL = "https://search.naver.com/search.naver?where=post&sm=tab_jum&ie=utf8&query=%EC%8B%AC%ED%95%B4%EC%9B%90+%EC%86%94%EB%A1%9C%EC%9B%8C%EC%A6%88"

# 1. requests => Crawling 하는 것이다.
#  Requests: HTTP for Humans _ 사람이 이해하기 쉽도록 쓰인 라이브러리
response = requests.get(BASE_URL)  #get이라는 함수를 실행 시킨 것이다.

response.status_code   # 2XX => Successful ( 200 OK )
                       # 3XX => Redirection
                       # 4XX => Failed ( 403 Forbidden )

response.content

response.text

dom = BeautifulSoup(response.content, "html.parser")
# dom ( 돔 ) => Document Object Model
# html > div > h1 > p > ul > li > ... 이거 하나하나를 객체로 보고
#그것들의 상관관계(속해 있다 라는 개념)를 구조화해서 보여준다.
dom

# Parsing

# tag => "태그이름" ( "div", "a" )
# id => 문서 전체에서 unique 한 값 => "#" (하나만 뽑을 때 유용할 수도 있다.)
# class => 문서 전체에서 1~n => 공통적인 특징을 가진 tag 들 => "."

post_elements = dom.select("li.sh_blog_top")

len(post_elements)

post_element = post_elements[0]
post_element

post_element.select_one("a.sh_blog_title")   #type이 list이다.

title_element = post_element.select_one("a.sh_blog_title")   #하나만 뽑으려면 _one을 붙이면 된다.
title_element

title_element.text

title_element.get("href")

for post_element in post_elements:
    title_element = post_element.select_one("a.sh_blog_title")
    title = title_element.text
    url = title_element.get("href")
    print((title, url))

import pandas as pd

df = pd.DataFrame(columns=["url", "title"])

df

for post_element in post_elements:
    title_element = post_element.select_one("a.sh_blog_title")
    title = title_element.text
    url = title_element.get("href")
    df.loc[len(df)] = [url, title]

df

df.to_csv("solowars.csv")

"""
Explanation: 2T_크롤링 ( Crawling ) 개요 - crawling, scraping, parsing

Crawling => "데이터를 모으는 과정" ... => Google bot(주로 하는 것)
fastcampus.co.kr/robots.txt
=> 어디를 긁어가고 어디를 긁어가지 말 지 알려주는 txt파일
만약 이게 없다면 다 긁어도 되는 것이 정책이다.



웹 문서 ( HTML ) Crawling
Crawling => 모든 정보를 쌩으로 다 가져오는 작업 ( 의미 X )
Scraping => 링크 + 어떤 특정 정보를 걸러내는 거 
Parsing => 의미있는 정보를 뽑는 과정


어떤 과정?

Crawling =>라이브러리 호출 / urllib, urllib2, ..., requests ( HTTP Request/Response )
Scraping => 
직접 Crawling 한 결과 => a 태그를 찾아서 => 다시 크롤링
Scrapy(framework)
Parsing =>
Regular Expression ( 정규 표현식 )
BeautifulSoup

lxml ( xml )


Crawling => requests

Parsing => BeautifulSoup


Framework와 Library의 차이

Framework => 기능들의 집합 ( 라이브러리들의 집합 ) => "틀" => 하고자 하는 목표가 있음(예를 들어 백엔드 개발 프래임워크나 프런트엔드 개발 프래임워크)
Library => 기능들의 집합. Framework가 조금 더 큰 개념
모듈 == 라이브러리 == 패키지(python에서는 거의 비슷하게 사용할 것이다.)


정규 표현식?

공통적인 모양새를 가지고 있는 문자열을 찾기 위해서
문자를 편하게 변환하기 위해서

3T_네이버 블로그 크롤링 - requests, beautifulsoup
End of explanation
"""


