본문 바로가기
Database & Bigdata/공공 빅데이터 청년 인턴십

[ DAY 7 ] 데이터 저장/스크래핑 프로세스

by jionee 2020. 9. 1.
SMALL

3. 데이터 저장

[ CSV형식으로 저장 ]

- CSV(Comma-Seprated Values)란?

하나의 레코드를 한 라인에 저장하는 텍스트 포맷 파일

각 라인의 컬럼값은 쉼표(콤마) 등의 구분자를 사용

데이터 내에 쉼표 등의 구분자 사용하는 문자가 포함되어 있다면 파싱 시 문제가 발생

(데이터 내에 쉼표 등의 문자가 포함되어 있는 경우 TSV(Tab-Saperated Values) 형식 사용 필요)

 

- CSV 형식 저장

import csv

# file open, newline=''으로 개행문자 지정
with open('top_cities.csv', 'w', newline='',encoding='utf-8') as f:

    # 첫 번째 매개변수에 파일 객체
    # 두 번째 매개변수에 필드명 리스트를 지정
    writer = csv.DictWriter(f,['rank','city','population'])  
    
    # 첫 번째 줄에는 헤더 입력
    writer.writeheader()
    
    # writerows()로 여러 개의 데이터를 딕셔너리 형태로 작성
    writer.writerows([
        {'rank' : 1, 'city' : '상하이', 'population': 24150000},
        {'rank' : 2, 'city' : '카라치', 'population': 23500000},
        {'rank' : 3, 'city' : '베이징', 'population': 21516000},
        {'rank' : 4, 'city' : '텐진', 'population' : 14722100},
        {'rank' : 5, 'city' : '이스탄불', 'population' : 14160467},
    ])
  • with 블록을 통해 명시적으로 close() 메소드를 호출하지 않고도 파일을 닫을 수 있음
  • wirter 변수에 DictWriter 함수를 이용해 딕셔너리 형태로 데이터를 쓰기
  • writerow() 함수로 list 데이터를 한 딕셔너리{} 씩 추가
import chardet

char_dic = chardet.detect(open('top_cities.csv', 'rb').read())
char_dic ['encoding']

 

'utf-8'

top_cities.csv의 인코딩 감지 후 출력

 

 

[ JSON 형식으로 저장 ]

- JSON(JavaScript Object Notation) 이란?

key-value 형식의 데이터 객체를 저장/전달하기 위해 텍스트 형식의 개방형 표준 포맷

플랫폼 및 프로그래밍 언어 독립적 데이터 포맷

사람과 컴퓨터 모두 이해하기 쉬움 

 

JSON 데이터타입

  • 문자열(string)
  • 숫자(number)
  • 객체(JSON object) - JSON안에 JSON이 들어있다고 보면됨
  • 배열(array) - ["A","B"] 형식 표시
  • 불리언(Boolean)
  • null

- JSON 형식 저장

import json

cities = [
    {'rank' : 1, 'city' : '상하이', 'population' : 24150000 },
    {'rank' : 2, 'city' : '카라치', 'population' : 23500000 },
    {'rank' : 3, 'city' : '베이징', 'population' : 21516000 },
    {'rank' : 4, 'city' : '텐진', 'population' :  14722100 },
    {'rank' : 5, 'city' : '이스탄불', 'population' :  14160467 },
]

cities는 리스트 타입(대괄호)에 딕셔너리(중괄호) 엘리먼트를 가짐

 

괄호구분

  • 리스트 (List) : [ ] 대괄호를 사용해 작성       ex) a = [1,2,3,4,5]
  • 튜플 (Tuple) : () 소괄호를 사용해 작성 (괄호 없어도 생성 가능)     ex) a = (1,2,3,4,5)
  • 딕셔너리 (Dictionary) : 중괄호를 사용해 작성. 콜론과 콤마를 사용함   ex) a = { "가격" : 20000, "제품명" : "드라이기" }
  • 세트 (Set) : 중괄호를 사용해 작성      ex) a = {1,2,3,4,5}

 

with open('top_cities.json','w') as fw:
    json.dump(cities,fw)

JSON 파일 쓰기

dumps() 함수: Python 객체를 JSON 문자열로 변환

 

with open('top_cities.json','r') as fr:
    json_file = json.load(fr)
    print(json_file)

JSON 파일 읽기

loads() 함수: JSON 문자열을 Paython 객체로 변환

 

 

[ SQLite3 DBMS로 저장 ]

- SQLite3 DBMS란?

파일시스템 기반의 경량 관계형 DBMS

경량 관계형 DBMS로 스마트폰 등의 embedded 환경에서 널리 사용

파이썬에서는 SQLite3가 기본 모듈로 제공

대용량 데이터 및 트랜잭션 처리 부적합

경량 데이터 및 트랜잭션 처리, 교육용 목적 등으로 사용

 

- SQLite 3 DB 저장

import pandas as pd
import sqlite3
from pandas.io import sql
import os

pandas, sqlite3, os, sql  import

 

DB_NAME = 'top_cities.db'
TABLE_NAME = 'TOP_CITIES'

DB와 테이블 이름을 변수에 정의

 

def db_save(df, db_name, table_name):
    with sqlite3.connect(db_name) as con:
        try:
            df.to_sql(name = table_name, con = con, index = False, if_exists='append') 
            #if_exists : {'fail', 'replace', 'append'} default : fail
        except Exception as e:
            print(str(e))
        print(len(df), '건 저장완료..')

데이터베이스 저장 함수

sqlite3.connect 메소드로 DB 연결 

이름과 연결 정의

if_exists = 'append' 는 이미 데이터가 존재하면 밑에 데이터를 계속 추가한다는 옵션 ( default값은 fail )

except exception as e는 예외 변수 -> print(strr(e))로 오류를 잡아 출력

* replace 옵션은 기존값을 대체하고 새로 넣음

len(df)로 길이를 체크해 몇건 저장했는지 출력

 

def db_select(db_name, table_name):
    with sqlite3.connect(db_name) as con: 
        try:
            query = 'SELECT * FROM {}'.format(table_name)
            df = pd.read_sql(query, con = con)
        except Exception as e:
            print(str(e)) 
        return df  

데이터베이스 읽기 함수

첫번째 파라미터엔 쿼리문 두번째 파리미터엔 커넥션 객체

except exception as e는 예외 변수 -> print(strr(e))로 오류를 잡아 출력

최종적으로 df출력(데이터베이스 읽기)

 

 

def db_delete(db_name, table_name):
    with sqlite3.connect(db_name) as con: 
        try:
            cur = con.cursor()
            sql = 'DELETE FROM {}'.format(table_name)
            cur.execute(sql)
        except Exception as e:
            print(str(e)) 

데이터베이스 삭제 함수

cursor 함수 호출

sql 에 쿼리문 입력 -> 현재 쿼리문은 테이블의 데이터를 모두 삭제함 Where 조건문을 사용하면 삭제할 데이터 지정 가능

execute 함수로 sql 실행

except exception as e는 예외 변수 -> print(strr(e))로 오류를 잡아 출력

 

 

top_cites = pd.read_csv('top_cities.csv')
db_save(top_cites, DB_NAME, TABLE_NAME)

5 건 저장완료..

db_save 함수를 사용해 데이터베이스 저장

 

 

df = db_select(DB_NAME, TABLE_NAME)
df

db_select 함수를 사용해 데이터 베이스 출력

 

4. 스크래핑 프로세스

[ 파이썬 스크래핑 프로세스 ] 

1.  웹 페이지 크롤링 : fetch(url)

매개변수로 지정한 URL의 웹 페이지를 추출

 

2. 스크래핑 : scrape(html)

매개변수로 html을 받고, 정규 표현식을 사용해 HTML에서 도서 정보 추출

 

3. 데이터 저장 : save(dp_path,books)

매개변수로 books라는 도서 목록을 받고, db_path로 지정된 SQLite DB에 저장

 

[ HTML 스크래핑 ] 

HTML 스크래핑을 위한 파이썬 라이브러리로 lxml, Beautiful Soup, pyquery 등이 존재

 

- lxml

C언어로 작성된 XML 처리와 관련된 라이브러리인 libxml2와 libxslt의 파이썬 바인딩

libxml2와 libxslt는 C언어로 작성되어 있으므로 빠르게 동작

파이선에서 사용이 용이하도록 API 구현

 

- Beautiful Soup

간단하고 이해하기 쉬운 직관적인 API를 활용해 데이터 추출 가능

내부적으로 사용되는 파서를 목적에 맞게 변형 가능

 

* 스크래핑을 위한 라이브러리는 모두 XPath CSS selector를 이용해 스크래핑 수행

 

XPath : XML 문서의 특정 요소나 속성에 접근하기 위한 경로를 지정하는 언어

ex ) //*[@id="prj_2019"]/tr[1]/td[1]

 

CSS selector : CSS 선택 문법을 이용하여 태그 검색 (크롬의 개발자 도구 등 이용)

ex) #prj_2019 > tr:nth-child(1) > td:nth-child(1)

 

 

[ lxml을 이용한 스크래핑 ] 

lxml의 여러 API 중 HTML을 파싱할 떄는 lxml.html을 사용

- lxml.etree : ElementTree를 확장한 API를 가진 XML 파서

- lxml.html : xml.etree를 기반으로 invalid HTML도 다룰 수 있게 해주는 HTML 파서

- lxml.objectify : 트리를 객체 계층으로 다룰 수 있께 해주는 XML 파서

- lxml.sax : SAX 형식의 XML 파서

 

- lxml 스크래핑 실습 

!pip install lxml
!pip install cssselect

import lxml.html

# HTML 파일을 읽어 들이고, getroot() 메서드로 HtmlElement 객체 생성
tree = lxml.html.parse('dp.html')
html = tree.getroot()

 

 

# cssselect() 메서드로 a 요소의 리스트를 추출 및 반복 수행
for a in html.cssselect('a'):
    # href 속성과 글자를 추출합니다.
    print(a.get('href'), a.text)

 

 

 

 

[ Beautiful Soup를 이용한 스크래핑 ] 

Beutiful Soup은 단순한 API로 구성된 스크래핑 라이브러리

목적에 따라 파서를 선택 및 사용가능

파서 매개변수 특징
표준 라이브러리의 html.parser "html.parser" 추가 라이브러리 불필요
lxml의 HTML 파서  lxml' 빠른 처리가 가능
lxml의 XML 파서 lxml-xml' 또는 'xml' XML에 대해 빠른 처리가 가능
html5lib 'html5lib' html5lib (https://pypi.python.org/pypi/html5llib)을
사용해 HTML5의 사양에 맞게 파싱 가능

 

 

[ URL 기초 지식 ]

- URL 구조 

Schema(Protocol) : http 또는 https와 같은 프로토콜

Authoruty(Domain) : 도메인명 - 포트번호

Path : 호스트 내부에서의 리소스 경로

Query : ? 뒤에 나오는 경로와는 다른 방법으로 리소스를 표현하는 방법

Flagment : # 뒤에 나오는 리소스 내부의 특정 부분

 

 

[ 절대 URL과 상대 URL ]

절대 URL : https:// 등의 스키마로 시작하는 URL을 절대 URL

상대 URL : 절대 URL을 기준으로 상대적인 경로를 잡는 URL

  • //로 시작하는 절대 URL

  • /로 시작하는 상대 URL

  • 그 밖의 상대 경로 형식을 사용하는 상대 URL

 

[ 상대 URL을  절대 URL로 변환 ]

상대 URL을 절대 URL로의 변환은 표준 라이브러리의 urllib.parse 모듈에 포함되어 있는 urljoin()함수를 사용

 

- urljoin() 함수

첫 번째 매개변수에 기준이 되는 URL을 지정, 두 번째 매개변수에 상대 URL을 지정

from urllib.parse import urljoin

base_url = 'http://example.com/books/top.html'
urljoin(base_url,'//cdn.example.coml/logo.png')

'http://cdn.example.coml/logo.png'

 

from urllib.parse import urljoin

base_url = 'http://example.com/books/top.html'
urljoin(base_url,'/articles')

'http://example.com/articles'

 

 

[ 퍼머링크와 링크 구조 패턴 ]

퍼머링크란?

불변(Permanent) + 링크(Link)를 조합

최근의 웹사이트는 하나의 콘텐츠가 하나의 URI에 대응

하나의 콘텐츠에 대응되며, 시간이 흘러도 대응되는 콘텐츠가 변하지 않는 URL

퍼머링크를 가진 웹사이트는 구글 등의 검색 엔진의 크롤러가 콘텐츠 인식 용이

ex) 페이스북과 트위터 등의 소셜 미디어에 콘텐츠를 공유할 때 사용가능, 기사

 

 

[ 목록/상세 패턴 ]

퍼머링크를 사용하는 웹 사이트는 대부분 퍼머링크를 가진 페이지로 연결되는 링크가 목록으로 존재

목록 페이지와 상세 페이지의 조합으로 구성된 웹 사이트의 링크 구조 패턴

각각의 목록에 하이퍼링크로 연결된 상세페이지를 열 수 있음

댓글