분류 전체보기

CRUD

  • Create(데이터 추가, row 추가)와 Read(가져오기 +  필터링, 정렬, 데이터수 제한)는 중요하다
  • Update(수정)와 Delete는 없을 수 도 있다.


Create & READ: INSERT문과 SELECT문

참고 사이트 : https://www.w3schools.com/sql/sql_insert.asp

image


우리가 만들어야할 table예시

image



  • table구조 확인하는 명령어 : DESC topic;
    image

  • AUTO_INCREMENT되는 id칼럼을 입력해주지 않으면, 값은 자동으로 +1 될 것이다.
  • 먼저, row를 삽입하는 것이므로,
    INSERT INTO topic () VALUES(); 형태를 작성하고, 앞()에는 칼럼명, 뒤 ()에는 value값을 입력할 준비를 한다.
    image

  • 칼럼-value를 하나씩 채워나간다.
    image
    image

  • create라는 날짜시간 칼럼에서는 직접 값을 입력해도 되지만, NOW()라는 함수를 통해 현재 날짜가 자동입력되도록 한다.
    image

  • table의 내용물(모든 칼럼)을 확인하는 명령어 : SELECT * FROM topic;
    image

    나머지도 다 입력하여 SELECT * FROM table;로 확인한다.
    image



READ

  • 일부 칼럼만 보기 : * 대신 컬렴명을 적어준다.
    mysql> SELECT id, title, created, author FROM topic;
    image


  • mysql select syntax를 구글에서 검색하여 나온 공식문서의 syntax설명을 보자.
    image
    공식 문서에서 SELECT문을 보면,
    [ ]는 생략가능하다는 뜻, select_expr = projection = 표현되어야할 칼럼들을 의미한다.

  • 만약, SELECT 다음에 FROM 테이블명이 없다면?
    해당 projection을 컬럼으로 하는 어떤 데이터가 보여진다.
    image


  • FROM table명 다음에 올 수 있는 WHERE 칼럼명=value; -> 엑셀의 칼럼 필터링같이, 특정칼럼 = 값의 형태로 author = 'egoing'인 것만 골라 올 수 있다.
    mysql> SELECT id, title, created, author FROM topic WHERE author='egoing';
    image


  • FROM -> WHERE 다음에 올 수 있는 ORDER BY = 칼럼명 ASC/DESC ;오름/내림차순 정렬을 할 수 있다.
    SELECT id, title, created, author FROM topic WHERE author='egoing' ORDER BY id DESC;image


  • row의 개수를 제한할 때는 LIMIT row수;를 달아준다.
    mysql> SELECT id, title, created, author FROM topic WHERE author='egoing' ORDER BY id DESC LIMIT 2;
    image

# 데이터 다운로드 : http://www.bio.ic.ac.uk/research/mjcraw/therbook/
# 책 pdf 주소 : https://www.cs.upc.edu/~robert/teaching/estadistica/TheRBook.pdf
# chapter 8 classic test 부터 다룬다.

# 데이터 준비
getwd()
# header = T를 안붙힐 경우, txt에서온 칼럼명이 row로 들어가고 V1이라는 칼럼명이 생성된다.
light <- read.table("data/light.txt", header = T) #폴더에 접근할때는앞에 / 안붙히고 바로..
light


#### normal QQ plot ####
# 2개의 그래프를 그리고 접선과 일치할수록, 정규분포를 따르는 데이터라 할 수 있다.

# 1) 눈 대중..으로 데이터의 분포를 보기 위한 hist() 히스토그램확인
hist(light$speed, col = "green")
image


# 2) rnorm()으로 생성한 정규분포 데이터로 그래프 비교해보기
x <- rnorm(1000)
hist(x)

# 3) 데이터 통계를 보기 위한 summary() + boxplot()****
summary(light) # 통계정보
boxplot(light) # 통계정보를 그래프로
image

# 4) hist()그램보다 더 정확하게 정규분포인지를 확인할 수 있는 QQplot *** ####
# qqnorm() : 데이터들을 점으로 표시하여, qqline()과 비교할 준비를 한다.
# qqline() : quantile을 기준으로 줄을 세워, 정규분포를 가정하는 선을 생성
# 생성된 qqline과 점들의 분포가 비슷하면, normal distribution을 "부정하기 어렵다"라고 말함.

# 1단계 : H0 : 정규분포 되어있다. 를 가정
# 2단계 : qqnorm()+qqline()-> 그려보고 선에 안맞으면 reject할 준비
# 3단계 : 실제적으로 shapiro.t()를 넣어 p-value를 확인하여 0.05(5%)보다 큰 것을 확인한다.
 

# H0 : 정규분포를 가진다

qqnorm(light$speed)
qqline(light$speed, col = "red")
# 선에 벗어나 있으므로 H0 거절할 준비하기
image

# p-value확인
shapiro.test(light$speed) # (대립가설이)0.09를 가져 0.05보다 크다. => H0를 채택해야하는 상황.
# 정규분포라 봐야한다...


# 5) 완전 정규분포인 데이터를 가지고 qqplot을 그려보자.
# 1단계
# H0 : 정규분포 되어있다. 를 부정할 수 없을 것이다..예상
x <- rnorm(1000)

# 2단계
qqnorm(x)
qqline(x, col = "red")
# 정규분포 선과 점들이 거의 일치
image

# 3단계
shapiro.test(x) # p-value가 0.05보다 커서 H0채택 H1거절 -> 정규분포   아니라고말할수x
# cf) 카이제곱검정 H0 : chisq.test()로 검정 : 남/녀가 영향안줄 것이다. 결과들 독립이다. 를 검정
#      - p가 0.05보다 작으면 H0거절 H1(남여영향줌)을 채택
# cf) 정규분포검정 H0 : shapiro.test()로 검정정규분포를 따를 것이다.
#      - p가 0.05보다 작으면 H0거절 H1(정규분포라고 말할 수 없다.)을 채택
      

#  다시 한번 정규분포x인 데이터로 연습해보자.
x <- exp(  rnorm(1000)  )

# 1단계
# H0 : 정규분포 되어있다. 를 부정(reject)


# 2단계
qqnorm(x)
qqline(x, col = "red")
# 정규분포 선과 점들이 일치x
image

# 3단계
shapiro.test(x) # p-value가 엄청 작다 -> H0 거절 H1채택 -> 정규분포 라고 보기 힘듬.



# 7) wilcox.test()를 통해, 정규분포가 아닌 측정된 샘플데이터에서 [H0:빛의 속도(모집단)의 평균(mu)는 299 990 k/ms]이다.를 검정해보자
# ***정규분포를 따르지 않으므로 Student's t test(데이터가 정규분포일 때, 모집단의 평균 검정)는 하지 못하여 wilcox.test()를 사용한다.
# 데이터 설명
# 빛의 속도라고 알려진 299990에서 299000을 뺀 수치들이다.
# 그 결과 정규분포를 따르지 않게 되고
# 정규분포를 가정하고 실험하는 Student's t test를 하지 못한다.***

#*** 윌콕슨 검정 H0 : 샘플로 본 빛의 속도(모집단)의 평균은 990 -> 299 990일 것이다.
wilcox.test(light$speed, mu = 990 )
# 그 결과 p-value가 0.05보다 작다 -> H0:거절 / H1 채택-> 빛의 속도평균 299990 아님

# summary()로 확인한 샘플들의 Mean값을 가지고 윌콕슨 검정해보자.
summary(light$speed) # Mean = 909
#*** 윌콕슨 검정 H0 : 샘플로 본 빛의 속도(모집단)의 평균은 909 -> 299 909일 것이다.
wilcox.test(light$speed, mu = 909 )
# 그 결과 p-value가 0.69 -> H0: 채택-> 빛의 속도평균 299 909 이 아니라고할수x

카이제곱 검정 ( 2변수간에 연관관계(독립성) 검정 )

http://nittaku.tistory.com/365

  • 카이제곱검정 H0 : chisq.test()로 검정 : 남/녀가 영향안줄 것이다. 결과들 독립이다. 를 검정
       - p가 0.05보다 작으면 H0거절 H1(남여영향줌)을 채택

샤피로 테스트 ( 정규분포 검정 )

http://nittaku.tistory.com/386

  • 정규분포검정 H0 : shapiro.test()로 검정 : 정규분포를 따를 것이다.
      - p가 0.05보다 작으면 H0거절 H1(정규분포라고 말할 수 없다.)을 채택      
  • 정규분포를 확인 : hist() -> summary() + boxplot() -> qqnorm() + qqline() -> shapiro.test()

윌콕슨 (모집단 평균 추정1 - 샘플이 정규분포를 따르지 않는 비모수적 검정시)

http://nittaku.tistory.com/386

  • 윌콕슨 순위합 검정 H0 : wilcox.test(, mu=)로 검정: (정규분포x인 샘플로 추정할 때) 모집단의 평균이 xxx일 것이다.
    - 만약, 샘플데이터가 정규분포를 따르는 상태라면, 윌콕슨이 아니라 Student's t test를 해야한다.

부트스트래핑 (모집단 평균 추정2)

http://nittaku.tistory.com/389

  • 부트스트래핑 H0 : 모집단의 평균은 xxx일 것이다. 를 적은샘플을 1000번 이상, 샘플수대로 복원추출하고 그 평균의분포가 이 정규분포를 이루니 그 분포의 평균을 이용하여 모집단의 평균 추정한다.

Fisher 검정 ( 2그룹간의 분산차이 검정 )

http://nittaku.tistory.com/398

  • 피셔 검정 H0 : var.test( c1, c2 )로 검정 : 2 그룹간의 분산차이가 없을 것이다.
    - 만약, p-value가 0.05 이하면, H0거절 H1채택 -> 두 그룹간의 분산 차이가 유의미히다.

Kruskal-Willis 검정 ( 비정규분포 3그룹간 차이 비교 )

https://nittaku.tistory.com/433

  • 크루스칼윌리스 검정 H0 : kruskal.test( 수치칼럼, 그룹칼럼)으로 검정 : 3그룹간의 차이가 없다

MySQL 구조

SQL은 최종적으로는 table가 완성된다.
image

댓글, 게시판 등등 다양한 table가 완성된다.
image

연관된 table를 모은 것이 database = schema이다.
image

연관된 table을 모은 schema를, 모은 것database server이다.


MySQL server 접속

  • 운영체제 ----------------------------------------------------> 폴더 를 막 다루는 것과 다르게,
    MySQL server -- 보안(자체 보안기능), 권한(여러 사용자 등록) --> schema, table을 읽기/쓰기/수정/삭제를 할 수 있다.
    즉, MySQL의 효용은 자체적으로  1) 보안 2) 권한을 가지고 있다.
    image


  • 접속 방법 : bin폴더까지 간 다음 아래 명령어를 친다.
    root : 모든 권한을 가짐. 중요한 시스템이라면 별도의 사용자를 등록해야한다.
    C:\Bitnami\wampstack-7.1.25-0\mysql\bin>mysql -uroot -p


Schema(database)의 사용

  • Database 생성
    -  sql문에서 맨 마지막에는 ;(세미콜론)을 꼭 달아야한다.
    mysql> CREATE DATABASE opentutorials;
    Query OK, 1 row affected (0.00 sec)

  • Database 삭제
    mysql> DROP DATABASE opentutorials;
    Query OK, 0 rows affected (0.01 sec)

  • Database 확인
    mysql> SHOW DATABASES;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | opentutorials      |
    | performance_schema |
    | sys                |
    +--------------------+
    5 rows in set (0.00 sec)

  • Database 사용
    mysql> USE opentutorials;
    Database changed

table을 다루기 위한 SQL

database server 접속 -> Database(schema) 사용 -> 연관된 table을 다루기 위한 SQL

  • SQL
    S: Structured (구조화됨 )
    Q: Query ( database에 요청, 질의 )
    L: Language ( 공통의 약속 )

  • SQL의 특징
    1) 쉽다.
    2) 중요함. 관계형 데이터베이스를 모두 다룰 수 있는 표준화된 언어

  • table 용어 정리
    image
    - x축 : row , record, 행
    - y축 : column, 열


Table 생성

  • 1) column의 이름 생성, 순서
  • 2) row 생성
    image


  • Cheat sheet를 보고 table을 작성해보자.


  • 아래 표를 table로 생성해보자.
    image
     
  • sql의 칼럼은 , 엑셀과 다르게, 컬럼의 데이터형을 가지고 있다. 그 결과 데이터형이 맞지 않으면 입력을 거부할 수 있다.
    - https://www.techonthenet.com/mysql/datatypes.php
    또한 길이에 대한 규제( VARCHAR(size) )도 가능하다.
     
  • id 칼럼은, 식별컬럼으로서, 보통 11자리수 까지 반영하며, 빈칸이어선 안되며(NOT NULL), 자동적으로 1씩 증가하도록 설정해야한다(AUTO_INCREMENT)
  • title 칼럼은, 제목은 길지 않아도 되며(255개 문자를 허용하는 VARCHAR), 문자열의 길이를 규제할 수 있다(100), 빈칸이어선 안된다.
  • description(본문) 칼럼은, 길어야 하므로(65,000 문자를 허용하는 TEXT), 내용이 없는 것도 허용한다(NULL)
  • create(생성시간) 칼럼은, 날짜(data) 시간(time)을 모두 허용하는 (DATETIME), 빈칸이어선 안된다(NOT NULL)
  • author(저자) 칼럼, 문자인데 30글자 안으로 자르면 될 것 같다(VARCHAR(30). 익명으로 쓸 수 있으니 빈칸 허용(NULL)
  • profile(프로필)칼럼은, 길 필요없으니 VARCHAR 100글자 정도로 허용해주고, 자기소개없을 수 있으니 빈칸 허용(NULL)

  • PRIMARY KEY는 2가지 측면이 있다. 1) 성능 2) 중복방지 기능을 가지므로, 식별 칼럼을 지정해준다.

  • mysql> CREATE TABLE topic(
         -> id INT(11) NOT NULL AUTO_INCREMENT,
         -> title VARCHAR(100) NOT NULL,
         -> description TEXT NULL,
         -> created DATETIME NOT NULL,
         -> author VARCHAR(30) NULL,
         -> profile VARCHAR(100) NULL,
         -> PRIMARY KEY(id)
         -> );
    Query OK, 0 rows affected (0.04 sec)
    image


    비밀번호 변경

    *비밀번호 변경 오류가 뜨면, 변경하자.
    SET PASSWORD = PASSWORD('asdfasdf');

bitnami WAMP 설치

https://bitnami.com/stack/wamp/installer

  • 위 사이트에 접속하여 다운로드 및 설치
    - 설치경로는 확인해두자!

    imageimageimage

    - 기본은 root 사용자이다. 비밀번호도 설정하자.
    - 설치시 포트는 3307로 하는 것 같다.
    image
    image

    image
    - 설치시 제법 걸린다.

    image
    설치된 화면이다.

  • 우리가 관심가져야할 부분은 Manager Servers
    image

    만약, 서버가 꺼졌거나 확인해야한다면, 설치 경로의 아래 파일을 실행하면 된다.
    image


  • Mysql  프로그램 실행
    C:\Bitnami\wampstack-7.1.25-0
    win + r   ->  cmd -> 설치경로 mysql 폴더 > bin 폴더까지 이동 후 아래 명령어를 쳐보자.


  • C:\Users\is2js>cd C:\Bitnami\wampstack-7.1.25-0

    C:\Bitnami\wampstack-7.1.25-0>cd mysql

    C:\Bitnami\wampstack-7.1.25-0\mysql>cd bin

    C:\Bitnami\wampstack-7.1.25-0\mysql\bin>dir

    C:\Bitnami\wampstack-7.1.25-0\mysql\bin>mysql -uroot -p
    Enter password: ********


    image
    image

  • 이전시간에 설치했던 APMSETUP은 아무대서나 실행이 가능했는데 비교(서로 다른게 설치)해봐야할 듯하다.
    image
    image
    - bitnami는 해당폴더까지 가서 mysql 명령어 입력 / 버전차이 존재(b : 5.7.23 / a : 5.1.41)



파일명 : watch_court.py
필요파일 : 크롬드라이버.exe


나만의 beautifulsuop 객체에 대한 정의

  • ?.태그명 : 해당 태그 하위 전체구조들까지 다 가져오기    ex> soup.body

  • 태그명.find_all( '태그명' ) : 하위의 모든 태그 중 여러개의 특정 태그를 리스트로 가져오기    ex> .find_all('tr')
  • 태그명.find( 속성 = '특정 속성명' ) : 하위의 모든 태그 중  특정 속성으로 검색    ex> .find(id = 'ea_list')

  • 태그명.get('속성') : 해당 태그안의 속성의 내용물을 가져옴   ex> a.get('href')



19.에서 했던 web_scrapping_example.py에 대해서,, 게시판 링크를 타고 추가 정보도 가져와야할 상황이다.
즉, 게시판을 클릭에서 그 글속에 정보도 가져와야한다.
image
image

  • 먼저, 1 ~ 100page까지 스크래핑했던 for문을 range(1, 2)까지로 줄이자. ( 다 완성된 뒤 100으로 수정하자)
    - # TODO 를 활용하였다.
    image


  • 게시판의 각 줄을 의미하는 line안의  각 칸<td> 중 게시글 제목칸인 td_list[1]를 보자.
    .text제외시키고  제목칸 <td>태그 안에는 링크 주소태그 <a> 태그가 있다.
    image


  • *** my) 만약, 이것을 bs4로 scrapping으로 처리한다면, 클릭해서 게시판으로 들어가는 시간 등을 처리 못하게 된다.
    *** 또한, href주소를 main url 뒤에 붙혀넣은 뒤, 홈페이지의 주소가 다르게 바뀌는 것 또한 문제를 발생시킨다
    그래도 한다고 가정하고 시행해보면,
    1. td 태그의 a태그로 이동 : td.a
      image
    2. a 태그의 href 속성의 내용물 가져오기 : a.get('href)
      - ***여기서 /뒤의 주소는 원래 웹사이트의 메인url인 http://watch.peoplepower21.org 뒤에 달리는 것이다.
      image
      image

      *** 하지만, 홈페이지가 로딩이 완료되면 주소가 변해있다.
      *** 이로 인해 문제가 발생할 것이다.

      image

    3. 이제 main url + href의 문자열을 합한 url을 requests.get() -> response.text -> html-> soup -> body 로 접근할 수 있다.
      *** 하지만, 데이터 로딩중이라는 문구와 함께 body치고는 너무 짧은 태그들만 보인다.
      *** 그 이유는 href를 이용한 url은 로딩을 준비하는 페이지로 가기 때문이다.

      image
      image


    4. 이럴 때 사용하는 것이 selenium이다.


selenium의 webdriver & chromedriver 설치

  1. 설치
    image

  2. from selenium import webdriver
    image

  3. 웹드라이버 중 크롬드라이버 이용을 위한 browser객체 만들기
    *** 첫 실행시 오류가 뜬다. 에러 중 마지막 줄 사이트로 이동해서 크롬드라이버 최신버전을 설치하자.
    image


  4. 크롬드라이버 설치
    https://sites.google.com/a/chromium.org/chromedriver/home

    image
    image
    image

    압축푼 파일을 해당 파이참 프로젝트 안에 붙혀넣기하자.
    imageimage
    image

  5. 다시 한번 크롬드라이버 객체browser를 생성하는 것을 실행시켜보자.
    - 크롬창이 하나 뜨면서 자동화된 테스트 소프트웨어에 의해 제어되고 있다고 뜬다.
    - 크롤링이 다 끊나고 browser도 꺼져야 하므로, py파일 맨 마지막에 browser.quit를 생성과 동시에 적어주는 버릇을 들이자.
    image

    image




selenium - webdriver - chromedriver를 이용해서 연결페이지를 가서 추가정보 가져오기

  1. 앞에서 시도 했던 부분 중  게시글td태그안의 a태그 -> href내용물 가져오기의 코드만 살려놓는다.
    - sele - web- chromedriver로 페이지를 타고 갈 때는, requests.get( url )부분을 대체하여 사용하는 것이다.
    - url을 얻은 상태에서 browser.get( url )시작한다.
    - 현재 상태로 실행하면, 작업은 없지만 연결된 페이지가 로딩이 완료되고, 다음 loop로 가는 것을 확인할 수 있다.
    - 그 이후에는

    image
    image


    image
    image
    image


  2. browser.get(url)로 받은 반응은    response = requests.get(url) 에 대응되고
    변수없이 browser객체에 할당된 반응은
    html = broswer.page_source 를 통해 html을 받아와야한다. 이것은 html = response.text에 대응된다.
    image



  3. html을 받았으면, 이전과정과 똑같이, beautifulsoup을 통해 스크래핑 하면 되는 것이다.
    image


  4. body 이후에서는 무엇을 가져와야할지(이전에는 게시판 첫 글을 검색) ctrl + u 를 통해 필요한 내용물의 자리를 살펴보자.
    - 우리는 해당 페이지에서 발의자라고 써있는 부분을 찾아보자.
    image
    image

  5. 우리가 필요한 발의자들 목록의 상위에서 많은 <div>태그들 가운데 id를 가지고 있는 <div>태그가 보인다.
    id는 한 페이지당 고유값이므로 body에서 .find(id = )로 한방에 타고들어간다.
    또한, 해당id <div>태그만 찾으면, 안에 text내용물은 발의자 목록 밖에 안보이므로, 쉽게 내용물을 가져올 수 있을 것 같다.
    image
    image

    하지만, 내용물이 제대로 안보인다.
    .text는 하위태그의 텍스트를 다 가져오긴 하지만,
    단지, selenium-webdriver-chromedriver가 페이지로딩이 완료가 다되고, 다음loop를 도는 기능은 있으나,
    selenium이  최종 페이지를 로딩하자마자, 바로 다음 loop로 넘어가는 식으로 수행하기 때문에
    bs4가 스크래핑할 시간이 없게 된다.
    image


  6. 이 때, 사용하는 것이 크롬드라이버의 객체 broswer를 이용한 암묵적인 기다림을 의미하는 .implicitly_wait( )이다.
    필요한 html코드를 페이지에서 받아오기 전, 5초를 기다려준다고 해봤다.
    하지만, 로딩되자마자 떠나는 것이 문제이므로 이것은 해결책이 안된다.
    image


Selenium의  WebDriverWait() + EC + By클래스를 이용하여 특정속성의 출현 확실히 기다려주기

  1. selenium이 로딩되자마자 떠나는 것을 방지하기 위해,
    해당id태그가 확!실!히! 출현한 이후에---> 다음loop로 빠져나가도록 해주는 selenium의 클래스는 3가지가 필요하다.
    image
    image
    - By. 대문자 ID

  2. WebDriverWait()를 쓰면, 무조건 html정보에 id = collapseTwo 이하의 태그들이 포함되어 있다.
    bs4는 그 정보를 가져온다. 마치 아래처럼 텍스트가 없는 것 처럼 보이나..
    빈칸이 너무 많아서... 콘솔을 오른쪽으로 돌려보면 있다

    image
    image


  3. 이제, 발의자 정보를 2차원 리스트에 추가로 append시킬 수 있도록
    1) append구문을 bs4로 스크래핑 한 뒤쪽자리로 옮기고
    image
    2) pandas의 칼럼 역시 추가해준다. 이 때, 수기로 추가해주자.
    image

    저장된 엑셀파일을 확인하면 아래와 같다. 하지만,,, 빈칸이 너무나도 많다.
    image


  4. 빈칸을 없애주기 위한 .replace( ' ', '')
    image


  5. 마지막으로 page를 수정해서 10page까지만 해보자.
    image
    image

year <- c(2000:2004)
year

value <- c(2.3, 3.2, 5.6, 5.4, 5.8) # 약간 선형으로 증가하게 만듬

# 기본 plot
plot(year, value)

# 대략적인 2005년도 값 추정하기 위해 선을 그리는데, 오차범위(잔차, residual)가 존재한다
# 각 점들과 선의 오차가 최소로 되도록 선을 긋는 것을 선형모델 Linear Regression model이라고 한다.
lm(value ~ year) # y ~ X

# 오차를 최소로하는 선을 긋는 lm()의 결과값은  절편과 기울기 +@(가 생김
fit <- lm(value ~ year)
fit

# linear regression model의 선을 그래프에 추가
abline(fit)
image

# y가 잘리니까 그래프의 y축 범위 늘려주기
plot(year, value,
      ylim = c(0, 10))

# 선 추가 + 색 추가
abline(fit, col="red")
image

# *** 선<-> 점들 간에 차이인 잔차(residual)을 최소로 하는 선이 그어진다. ***

# *** lm()결과에서 성분들 뽑아보기***
fit$coefficients[[1]] # 1) 절편값
fit$coefficients[[2]] # 2) 기울기
fit$residuals # 3) x 5개의 y값에 대한 선들과의 잔차(y-선)

# *** lm()이후 결과값 fit에 대해 summary()를 하는 버릇을 가지자 ***
# *** 선형 모델이 말이 된다/안된다를 판단하는 대략 기준
# 1) summary()시 *가 찍혀있는지/없는지  2) p-value(선형모델이 우연히 나올 확률*)가 0.05이하인지
summary(fit)


#### 2005 - 100값으로 확 증가하는 1개의 점 추가하고 fit결과를 summary()해보기 ####
year <- c(2000:2005)
value <- c(2.3, 3.2, 5.6, 5.4, 5.8, 100) # 약간 선형으로 증가하게 만듬

fit <- lm(value ~ year)

plot(year, value,
      ylim = c(0, 150))


abline(fit, col="red")

summary(fit) # 1) *가 없어지고 2) p-value가 0.05보다 훨씬 큰 0.13이 나옴. --> 데이터를 설명 잘 못하는 모델이다.
image


#### 더 직선에 가깝게 y값을 조절해보자.
year <- c(2000:2004)
value <- c(2.3, 3.2, 4.9, 5.4, 5.8) # 2003의 값을 더욱 선형에 가깝게 조절

fit <- lm(value ~ year)

plot(year, value,
      ylim = c(0, 10))


abline(fit, col="red")

summary(fit) # 1) ** 2개 2) p-value : 0.006 => 이 선형모델은 우연x 데이터를 잘 설명하는 모델이며 받아들일 수 있다.
image


# ***받아들인 모델을 가지고 다음 값 추정해보기****
# 선형이므로 fit의 결과값 2개인 절편/기울기로  선형식만들어 대입한다( y = ax+b)
predict <- fit$coefficients[[2]] * (2015) + fit$coefficients[[1]]

plot(year, value,
      ylim = c(0, 20),
      xlim = c(2000, 2020))
abline(fit, col="red")


# 예측점 추가
points(2015, predict, col="blue")
image


1. 데이터 준비(dataframe)

age <- c(18, 23, 25, 35, 65,
         54, 34, 56, 72, 19,
         23, 42, 18, 39, 37)
maxHR <- c(202, 186, 187, 180, 156,
           169, 174, 172 ,153, 199,
           193, 174, 198, 183, 178)

df <- data.frame(age, maxHR)
df
##    age maxHR
## 1   18   202
## 2   23   186
## 3   25   187
## 4   35   180
## 5   65   156
## 6   54   169
## 7   34   174
## 8   56   172
## 9   72   153
## 10  19   199
## 11  23   193
## 12  42   174
## 13  18   198
## 14  39   183
## 15  37   178


2. Linear Regression model 그리기

lm()함수를 사용하는데, y ~ X : X에 따른 y값(결과값)이다.

인자는 (y칼럼 ~ X칼럼, data = df ) 형태로 들어가야한다.

그 결과로는 계수(coefficients)가 나오는데

  1. 1차함수의 절편인 (intercept)와 2) 기울기가 나온다.
lm_result <- lm(maxHR ~ age, data = df)
lm_result
## 
## Call:
## lm(formula = maxHR ~ age, data = df)
## 
## Coefficients:
## (Intercept)          age  
##    210.0485      -0.7977
print(paste("y(maxHR) =",lm_result$coefficients[2],"x(age) +" ,lm_result$coefficients[1]))
## [1] "y(maxHR) = -0.797726564933042 x(age) + 210.048458424167"

y(maxHR) = -0.7977(age) + 210.0485


3. Visualization with ggplot

ggplot(data=df, aes(X축칼럼, x축칼럼)) +

geom_그래프종류() +

xlab(“x축이름”) + ylab(“y축이름”) +

ggtitle(“그래프이름”) +

stat_smooth(method = lm, level=0.95) # 오차를 최소로 만드는 선을 linear model로 추가, 신뢰도 0.95로 지정가능

#install.packages("ggplot2")
library(ggplot2)
ggplot(df, aes(age, maxHR)) +
  geom_point() +
  xlab("AGE") +
  ylab("Maxium Heart Rate") +
  ggtitle("Relation betweeb Maxium Heart Rate and Age") +
  stat_smooth(method = lm, level = 0.95)

A <- matrix(c(1, -1, 2, 3), nrow=2)
A
#      [,1] [,2]
#[1,]    1    2
#[2,]   -1    3

#### 2by2 matrix의 determinant 구하기 ####
# A(a b,c d)  D(A) = ad-bc

# 1. 사용자 정의 함수로 det() 흉내내기
det_f <- function(A){
   d <- A[1, 1] * A[2, 2]  -  (A[1, 2] * A[2, 1])
   return(d)
}
det_f(A)

# 2. 내장함수 쓰기 det()
det(A)


#### 2by2 matrix의 역행렬(inverse) 구하기 ####
# 앞에 1/(ad-bc) 곱하기
# a와 d 바꾸기 + b와 c에 - 달아주기

# 1. 사용자 정의함수
inv_f <- function(A){
   B = matrix(, nrow=2, ncol=2) # 빈행렬이지만, 2by2 폼 만들어놓기
   B[1, 1] <- A[2, 2]
   B[2, 2] <- A[1, 1]
  
   B[1, 2] <- -(A[1, 2])
   B[2, 1] <- -(A[2, 1])
  
   # 1/ad-bc 곱해주기
   B <- (1/det(A)) * B
   return( B )
}

inv_f(A)

# 2. 검산    A  %*%  A역행렬 = I (단위행렬)
  ( A %*% inv_f(A) )

# 3. 역행렬 내장함수 solve()와 검산
# ****1.1234134214 e-16같은게 나오면, 전체를 반올림 해주면 된다.
solve(A)
A %*% solve(A)
#             [,1] [,2]
#[1,] 1.000000e+00    0
#[2,] 1.110223e-16    1

round( A %*% solve(A) , 10)
#     [,1] [,2]
#[1,]    1    0
#[2,]    0    1

R markdown

  • 패키지 설치
    image

  • 아래와 같이 생성
    -  title + HTML선택만 해준다.
    image

    image
    image


  • 아래 스크린샷 부분은 설치 방법 & 주석이므로 제거한다.
    image


  • R코드는 ```{r} 으로 시작  ```으로 끝을 낸다.
    image


  • 기본 제공되어있는 코드로 상단의 Knit - Knit to HTML를 눌러보자.
    image


  • 저장시 아무 확장자도 안주어야지 .Rmd로 저장된다. html로 하면 안됨. -. 알아서 .html도 생성된다.
    image


  • 생성된 R markdown - html양식
    - echo = FALSE 라는 인자가 들어간 부분은 -> 코드( plot(pressure) )없이 결과값만 뜬다.
    image
    image


연습해보기

연습한 Rmarkdown.html 코드 복사해넣기

Now we are going to practice matrix functions!! (그냥 글자)

글자 크게(샵 1개)

작은 제목(샵 2개)

nrow = 인자 없이 matrix 생성 -> n by 1 (1열로 나옴)

A <- matrix(c(1, -1, 2, 0, 3, 4))
A
##      [,1]
## [1,]    1
## [2,]   -1
## [3,]    2
## [4,]    0
## [5,]    3
## [6,]    4

nrow = 인자 설정한 matrix 와 단순array

byrow = TRUE 옵션을 주지 않으면, 열을 하나씩 채운다.

A <- matrix(c(1, -1, 2, 0, 3, 4), nrow = 2)
A
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]   -1    0    4
B <- array(1:3)
B
## [1] 1 2 3
is.matrix(A)
## [1] TRUE
is.matrix(B)
## [1] FALSE

array에 2번째 인자인 dimension인자 (c(n,m))을 입력하면 matrix가 된다.

2 by 3에서 모자란 것은 1열씩 차례대로 채운다. array()로 생성하는 matrix에는 byrow옵션이 없다.

A = matrix(c(1, -1, 2, 0, 3, 4), nrow = 2, byrow = TRUE)
A
##      [,1] [,2] [,3]
## [1,]    1   -1    2
## [2,]    0    3    4
C = array(1:3, c(2, 3))
C
##      [,1] [,2] [,3]
## [1,]    1    3    2
## [2,]    2    1    3
is.matrix(C)
## [1] TRUE

행렬의 합, 차, 곱(각 성분들의 곱이 되어버림.) vs 외적%*% ( 양식 맞춰줘야함!** )

A
##      [,1] [,2] [,3]
## [1,]    1   -1    2
## [2,]    0    3    4
C
##      [,1] [,2] [,3]
## [1,]    1    3    2
## [2,]    2    1    3
A+C
##      [,1] [,2] [,3]
## [1,]    2    2    4
## [2,]    2    4    7
A-C
##      [,1] [,2] [,3]
## [1,]    0   -4    0
## [2,]   -2    2    1
A*C # 각 성분들의 곱이 되어버림
##      [,1] [,2] [,3]
## [1,]    1   -3    4
## [2,]    0    3   12
#A %*% C # a by b  외적 b by c 형태여야함.

t(C) # 형태변환(대각선기준 접기!)
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    1
## [3,]    2    3
A %*% t(C)
##      [,1] [,2]
## [1,]    2    7
## [2,]   17   15
A == C # logical 결과(mask)
##       [,1]  [,2]  [,3]
## [1,]  TRUE FALSE  TRUE
## [2,] FALSE FALSE FALSE
t(t(A)) == C
##       [,1]  [,2]  [,3]
## [1,]  TRUE FALSE  TRUE
## [2,] FALSE FALSE FALSE

기본적으로 제공되는 단축키

  • Q : 블로그 관리홈 으로 전환
  • W : 글쓰기


단축키 추가 방법

  1. Q로 블로그 관리홈 으로 들어가기

  2. 꾸미기 > 스킨 편집
    image

  3. HTML코드 중 //추가 단축키 부분 찾기
    image

  4. 아래 코드 추가해주기
    key['m'] = "/admin/entry/post/?id=" + location.pathname.split('/')[1]
  5. image

#### Windows10 MySQL 설치를 위한 APMSETUP7 설치 ####
# APM : Apache, Php, MySQL을 한번에 설치해준다.----> localhost를 치면 웹서버가 보여야 정상.
# http://kldp.net/apmsetup/release/ 에서 최신버전 다운로드
# 3221-APMSETUP7_2010010300.exe
# 관련 사항 확인 : http://nittaku.tistory.com/375

#### MySQL monitor ####
참고페이지 : http://nittaku.tistory.com/375?category=764930
# cmd 켬
# database server 접속 : mysql -uroot -p
# database 확인 : show databases;
# database 사용 : use [해당 db명];
# 해당db속 table 확인 : show tables;
# 해당table속 모든칼럼(*) 가져오기 : select * from 테이블명;


#### 샘플 데이터 다운로드 ####
# cmd로 설명한 페이지
: http://mystyle1057.tistory.com/272
# sample db다운 : http://www.mysqltutorial.org/mysql-sample-database.aspx
# cmd에서 압축을 푼 뒤 해당폴더에 진입mysql monitor에 접속 : 해당폴더 > mysql -uroot -p
# cmd에서 해당폴더에 <source 파일명.sql;> 을 통해 설치 : 해당폴더 > source mysqlsampledatabase.sql
# 기본폴더에서도 목록 보이게 됨 : cmd > mysql -uroot -p > show databases;
image

# *** classicmodel 이라는 db에서 table 중 employees table을 불러올 것임 : use classicmodels; > show tables; > select * from employees;
image



#### DB 확인하기 ####
# cmd > mysql -uroot -p >
# show databases;
# use classicmodels;
# show tables;
# select * from employees;
+-#---------------+-----------+-----------+-----------+---------------------------------+------------+-----------+----------------------+
   #| employeeNumber | lastName  | firstName | extension | email                           | officeCode | reportsTo | jobTitle             |
   #+----------------+-----------+-----------+-----------+---------------------------------+------------+-----------+----------------------+
   #|           1002 | Murphy    | Diane     | x5800     | dmurphy@classicmodelcars.com    | 1          |      NULL | President            |
   #|           1056 | Patterson | Mary      | x4611     | mpatterso@classicmodelcars.com  | 1          |      1002 | VP Sales             |
   #|           1076 | Firrelli  | Jeff      | x9273     | jfirrelli@classicmodelcars.com  | 1          |      1002 | VP Marketing         |
   #|           1088 | Patterson | William   | x4871     | wpatterson@classicmodelcars.com | 6          |      1056 | Sales Manager (APAC) |
   #|           1102 | Bondur    | Gerard    | x5408     | gbondur@classicmodelcars.com    | 4          |      1056 | Sale Manager (EMEA)  |
   #|           1143 | Bow       | Anthony   | x5428     | abow@classicmodelcars.com       | 1          |      1056 | Sales Manager (NA)   |
   #|           1165 | Jennings  | Leslie    | x3291     | ljennings@classicmodelcars.com  | 1          |      1143 | Sales Rep            |
   #|           1166 | Thompson  | Leslie    | x4065     | lthompson@classicmodelcars.com  | 1          |      1143 | Sales Rep            |
   #|           1188 | Firrelli  | Julie     | x2173     | jfirrelli@classicmodelcars.com  | 2          |      1143 | Sales Rep            |
   #|           1216 | Patterson | Steve     | x4334     | spatterson@classicmodelcars.com | 2          |      1143 | Sales Rep            |
   #|           1286 | Tseng     | Foon Yue  | x2248     | ftseng@classicmodelcars.com     | 3          |      1143 | Sales Rep            |
   #|           1323 | Vanauf    | George    | x4102     | gvanauf@classicmodelcars.com    | 3          |      1143 | Sales Rep            |
   #|           1337 | Bondur    | Loui      | x6493     | lbondur@classicmodelcars.com    | 4          |      1102 | Sales Rep            |
   #|           1370 | Hernandez | Gerard    | x2028     | ghernande@classicmodelcars.com  | 4          |      1102 | Sales Rep            |
   #|           1401 | Castillo  | Pamela    | x2759     | pcastillo@classicmodelcars.com  | 4          |      1102 | Sales Rep            |
   #|           1501 | Bott      | Larry     | x2311     | lbott@classicmodelcars.com      | 7          |      1102 | Sales Rep            |
   #|           1504 | Jones     | Barry     | x102      | bjones@classicmodelcars.com     | 7          |      1102 | Sales Rep            |
   #|           1611 | Fixter    | Andy      | x101      | afixter@classicmodelcars.com    | 6          |      1088 | Sales Rep            |
   #|           1612 | Marsh     | Peter     | x102      | pmarsh@classicmodelcars.com     | 6          |      1088 | Sales Rep            |
   #|           1619 | King      | Tom       | x103      | tking@classicmodelcars.com      | 6          |      1088 | Sales Rep            |
   #|           1621 | Nishi     | Mami      | x101      | mnishi@classicmodelcars.com     | 5          |      1056 | Sales Rep            |
   #|           1625 | Kato      | Yoshimi   | x102      | ykato@classicmodelcars.com      | 5          |      1621 | Sales Rep            |
   #|           1702 | Gerard    | Martin    | x2312     | mgerard@classicmodelcars.com    | 4          |      1102 | Sales Rep            |
   #+----------------+-----------+-----------+-----------+---------------------------------+------------+-----------+----------------------+#



#### RMySQL 설치 및 사용 ####
# R은 아주 큰 DB분석에 좋지 않다. 미리 sql에서 추출해서 분석하는 용도로 사용하는게 좋다.

# 1. RMySQL 패미지 설치 및 사용
install.packages("RMySQL")
library(RMySQL)


# 2. database server에 연결하기
# - mysql server가 돌아가는 상태여야 한다.
image

mydb <- dbConnect(MySQL(), user='root', password='rkqhwk12', dbname = 'classicmodels')
mydb


# 3. 쿼리문으로 db에서 테이블들 확인하기
# - 쿼리문을 날릴 때는, 연결된 database를 첫번째 인자로 주고 날린다.

result <- dbGetQuery(mydb, 'show tables;')
result

# 4. 쿼리문으로 table속 row개수 다 세기
dbGetQuery(mydb, 'select count(*) from employees;') # 32

# 5. 쿼리문으로 db속 table 가져오기
tbl <- dbGetQuery(mydb, 'select * from employees;')
tbl


# 여기서부터는 R 문법
# 6. paste()로  2개의 문자열 컬럼을 합친 것을 새로운 칼럼으로 생성하기기***
tbl$name <- paste(tbl$firstName, tbl$lastName)

# 7. 합쳐졌던 2개 칼럼 버리기***(버릴 때는, 인덱싱에서 제외하여 새로운 df를 만들어서 버림)
# 이름을 제일 처음으로 + 2개(2, 3번칼럼) 버리기
newdf <- tbl[c( ncol(tbl), 1, 4:(ncol(tbl)-1)  )]
newdf

# 8. ***gsub(, , 칼럼명)을 이용하여 특정 문자(NA 등) 치환하기***
# NA가 문자열로 포함된 reportsTo 칼럼에서 NA을 치환해준다.
newdf$reportsTo <- gsub('NA', '', newdf$reportsTo) # 문자열 NA만 있던 경우, ''로 대체하면  <NA>의 진짜 결측값을 가진다.
newdf

# 9. nuemeric/factor가  character로 되어있다면 바꿔주기 --> *** summary()에서 통계정보가 안나오기 때문에
# factor화는 factor()도 있었는데, 칼럼단위로으로... 해주려면... as.factor()*** /
# 칼럼단위라도 a$b <- factor(a$b)사용하기도 했었다. ( ggvis - http://nittaku.tistory.com/369)
str(newdf)
summary(newdf)

newdf$officeCode <- as.factor(newdf$officeCode)
str(newdf)
summary(newdf) # office의 범주중 1이 가장 많다..

# 10. 날짜 정보(2018-1-1)같은 정보가 character로 되어있다면  as.Date()로 바꿔주자.***
# 여기에는 없음


#### 11. database 서버와 연결 끊어주기 #### ****
# mysql서버와의 연결만 끊코, db객체는 살아있다.
dbDisconnect(mydb)

MySQL을 위한 APMSETUP7 설치

http://kldp.net/apmsetup/release/ 에서 최신버전 다운로드

*2010버전이 최신이고, 홈페이지는 사라진 상태, win 32비트용(? 64bit에서졷 잘돌아간다) 각 버전은 아래와 같음


  1. 크롬창에 localhost를 쳐서 웹서버 정상 설치되었는지 확인하기
    image


  2. 설치된 폴더( C:\apm_setup)으로 가서 각 파일들 확인하기
    image
    • php.ini : php설정 파일
    • Server 폴더 > MySQL5 > data > my.ini : MySQL 설정 파일
      image


  3. MySQL 클라이언트 파일을 통한 MySQL 접속하기
    • Win + R : cmd 입력
      image

    • mysql -uroot -p   입력후 기본설정된 비밀번호 입력
      apmsetup
      image
      -u : user
      root : 기본적인 사용자계정
      -p : apmsetup 으로 기본설정 되어있다. 나중에는 변경해야한다.


    • show databases;   --> 3개의 데이터 베이스 확인
      image

workbench로 mysql 다루기


  • apmsetup으로 mysql 서버가 설치 된 상황이라면,
    아래와 같이 인식되더라. 비밀번호 기본 : apmsetup을 통해 접속하자
    image
    image



웹기반의 phpMyAdmin 으로 다루기

  • APMSETUP에서 제공되는 APMSETUP 모니터를 작업표시줄에서 확인한 뒤,
    imageimage

  • 우클릭을 통해 메뉴 > MySQL관리 (M)에 들어가면, phpMyAdmin이 확인된다.
    imageimage


  • 사용자명과 암호에는  rootapmsetup을 적어준다.
    - 이것 역시 MySQL client의 종류 중 하나이다.
    image

    Database server와  Database Client를 살펴보자.
    image

  • 데이터베이스 탭을 보자.
    3개의 기본 db들이 있고, 클릭하면 여러개의 table들이 있다.
    image


  • MySQL 서버의 root 계정 비밀번호 변경
    - apmsetup 모니터 > 우클릭 > MySQL root 패스워드 변경

    imageimage

# 데이터 준비
mtcars
str(mtcars)
head(mtcars)

# aggregate()를 이용한,  cyl칼럼에 따른, mpg칼럼의 평균값들
aggregate(mtcars$mpg, by=list(mtcars$cyl), mean)

#### ***사용자 정의함수 + if문을 이용해서 aggregate()흉내내기*** ####
# udf의 ()인자에 cyl칼럼이 들어갈 것임...
# 그값이 4, 6, 8일 때,, 그 row들을 인덱싱해서  mpg의 평균
# 만약 함수안에서 변수에 안담기고 함수식만 있다면 -> R은 알아서 return을 해주는 기능이 있다.   변수에 담그면 반드시 return()
mean_by_cyl <- function(x){
   if(x == 4){
     # aggregate로 쓸 경우 : aggregate(mtcars$mpg, by=list(mtcars$cyl), mean)  [1, 2]
     return(    mean( mtcars[ mtcars$cyl == 4, "mpg"] )    )
   }else if(x == 6){
     return(    mean( mtcars[ mtcars$cyl == 6, "mpg"] )    )
   }else if(x == 8){
     return(    mean( mtcars[ mtcars$cyl == 8, "mpg"] )    )
   } else{
     print("잘못 입력되었습니다. 4 or 6 or 8 중에 입력해주세요")
   }
} # if문 끝

mean_by_cyl(4)
mean_by_cyl(6)
mean_by_cyl(8)

mean_by_cyl(7)


# 4, 6, 8은 들어오는 값이니 x로 대체하기
# my) 4 or 6 or 8 인 경우를,,, %in% 으로 대체하기***
mean_by_cyl <- function(x){
   if(x %in% c(4, 6, 8)){
     return(    mean( mtcars[ mtcars$cyl == x, "mpg"] )    )
   }else{
     print("잘못 입력되었습니다. 4 or 6 or 8 중에 입력해주세요")
   }
} # if문 끝

mean_by_cyl(4)
mean_by_cyl(6)
mean_by_cyl(8)
mean_by_cyl(7)

#### **** if문을 써서 aggregate()를 흉내낼 때의 장점 -> 경우의 수별로 문자열 띄울 수 있다.####
# *** return( '문자열', 변수, '문자열') 처첨 섞인 경우에는
# 바로 return 안되므로 paste로 묶어서 하나로 return한다 ***
# *** round( a, 2) --> 소수점 2번째 자리**까지** 표시

mean_by_cyl <- function(x){
   if(x == 4){
     a <- round(mean( mtcars[ mtcars$cyl == 4, "mpg"] ), 2)
     return( paste0('The avg mile per gallon of ', x, ' cylinder car is ', a))
   }else if(x == 6){
     a <- round(mean( mtcars[ mtcars$cyl == 6, "mpg"] ), 2)
     return( paste('The avg mile per gallon of ', x, ' cylinder car is ', a, sep=''))
   }else if(x == 8){
     a <- round( mean( mtcars[ mtcars$cyl == 8, "mpg"] ) , 2)
     return( paste('The avg mile per gallon of ', x, ' cylinder car is ', a, sep=''))
   } else{
     print("잘못 입력되었습니다. 4 or 6 or 8 중에 입력해주세요")
   }
} # if문 끝

mean_by_cyl(4)
mean_by_cyl(6)
mean_by_cyl(8)

프로젝트 : web_scraping_study_no1
파일명 : watch_court.py

requests 패키지 설치 및 requests.get('') 이용하여 홈페이지에서  주소 가져오기

  • 어떤 사이트의 게시판에 들어갔을 때, request url이 안뜰 수 있다.
    image

    - 이럴 때는, 게시판의 2번째 페이지를 눌러서, 다시 1페이지로 오자.

    image
    image

  • 이제 파이썬 파일을 하나 만들고, bs4를 import한 뒤, reponse에다가 requests.get()의 인자에다가
    홈페이지 url을 담아주자.
    image


  • 여기서 빨간줄이 뜨는 이유는 requests.get()함수를 사용하기 위한 패키지가 필요하기 때문이다.
    설정 > interpreter > requests 를 검색해서 패키지를 설치하자.
    *** request가 아니라 requests
    image

    image


  • requests 패키지를 import하고 url은 문자열로 담아주자.
    image

  • response에서도 .text만 받아서 html 변수에 넣어준 뒤,
    html변수에 담긴 것을 print해보면 잘 나오는 것 같다.
    image


requests로 긁어온 html(문자열)을  bs4를 이용해서 정보 빼내기

  • 이전시간과 같이, soup변수에 "lxml"parser를 사용한 beautifulsoup()를 이용해서 정보를 가져오고,
  • soup에서 body만 가져와보자
    image


  • 하지만 body의 양이 방대하게 많으므로, 우리가 필요한 정보만
    해당 사이트 [ Ctrl + u ] 를 이용해서 게시판의 첫번째 글을 검색하여 위치를 찾아보자.
    image
    image

  • 이제 저 부분의 html코드 구조를 파악해야한다.
    • <td>는 한칸이다. ->  한줄을 의미하는 <tr>이 있을 것이다.
    • <tr> = 한줄 상위에는 table이 있을 것이다. 머리말이 있는 게시판이면 ->     <thead>와 <tbody>가 있을 것이다.
    • <thead>바깥에 <table>이 있을 것이다.
    • <table>바깥은 봤더니 ->   구획을 나누어주는 <div>태그 + id속성이 같이 있다.
    • id = 속성은 한 페이지당 단 1개를 특정짓는 것이므로 id = "ea_list"를 가진 <div> 집중공략할 준비를 한다.
      table(게시판)은 한 페이지에 여러개가 있을 수 있기 때문에,
      ==> ea_list라는 id를 가진 <div>태그를 먼저 찾자!


  • body.find(id=) 함수를 이용해, div태그를 적어주는 것 없이 바로 그 위치를 찾아, 그 아래구조들을 다 찾아준다.
    변수명은 div태그까지 포함시켜서 만들어 구조를 파악하기 쉽게해준다.
    image


  • id = 'ea_list'로 검색한 결과는 <div>태그 부터 시작한다.
    div -> table -> tbody 까지 내려가자. 그 안의 tr/td를 받아올 것이다.
    image


  • tbody속에는 여러개의 tr태그를 가지고 있기 때문에,
    .find_all('tr')을 통해 tr들을 다 가져온 뒤 : lines --> for문으로 한줄씩 받은 것을 print로 확인하자.
    image

  • 각 tr안에서도 여러개의 td들을 가지고 있다. ---> find_all('td')를 통해 td들을 개별적으로 다 받아오자.
    • for문 속 각 tr(line)들에 대해    여러개의 tr을 받아오고, 그 중 첫번째 칸만 출력해보자.
      - 날짜 정보는 우리가 원하는게 아니다.
      image

    • 2번째 칸을 출력해보고, 맞으면 .text를 붙혀서 텍스트 정보만 가져오자.
      image

      image


  • for문 안에서 원하는 정보를 각 루프마다 확인했다. 이것을 계속 쓸 수 있는 변수에 받기 위해 for문 전에 미리 리스트를 생성해야하고,
    각 루프속에서 append()로 넣어줘야할 것이다.
    image


  • 이 때, [ 날짜, 의안, 작성자 ]의 3개의 정보 한묶음으로 --> bill_list로 정보를  전달해주려면
    그러므로 위 처럼 1차원 리스트가 아니라 2차원의 리스트형태가 되도록
    미리 리스트형태로  append( [  1, 2, 3] )
    를 해줘야, bill_list는 2차원 리스트가 될 것이다.
    *** 2차원 리스트를 이쁘게 확인하려면, for문을 써서 확인한다.
    *** 2차원 리스트로 만들어야만 -->  pandas에 담을 수 있고 --> 엑셀로 저장할 수 있다!***

    image


  • 한가지 정보를 더 추가해보았다(5번째 칸, 진행상태)
    image


가져온 2차원 리스트의 정보--> pandas에 담고 --> 엑셀로 저장하기

  • pandas 패키지 설치 및 import
  • pandas.to_excel() -> .xlsx 저장을 위한 : openpyxl 패키지 설치
    image
  • pd.DataFrame()으로 bill_list를 df에 담기  *2차원 리스트여야 df에 담을 수 있다!
  • pd.to_excel('bill.xlsx')로 저장하기
    image

    image


  • 엑셀파일을 열어보니,, 칼럼명이 없다.
    my) table -> thead -> th(머리말 한칸)들에서 가져오자.
    그리고 받은 정보를 pandas의 df생성시 columns=[]인자를 이용해서 적어주자.
    *** 그냥 손으로 적어줘도.. 될 듯..
    image

    image

  • my) index(행 번호)도 옵션으로 주어 없애보자.
    image

    image



한 페이지가 아니라 여러 페이지를 다 해보자.

맨 처음 홈페이지 주소를 가져온 url 에서 page=1 ---> page2, 3, 4, ...로 바뀌어야할 것이다.

image

  • 이럴 때, 해야할 게, '문자열' 이므로    '  {} ' . format( i )을 이용하여 변수로 둔 다음, for문으로 돌리는 것!
    이 때 조심해야할 사항이 있다.
    image

    1. for문은 range(1, 100) --> 1page부터 시작할 것

    2. bill_list()는 page를 돌리는 for문보다 더 바깥으로 빼야한다. * 페이지를 돌면서 계속 append될 것
      image

    3. pandas에서 엑셀로 저장하는 부분은 for문 안에 안들어갈 것.
      image

  • 100page 모두 스크래핑 한 결과
    image


+ Recent posts