반응형

** 웹 요청 시 필요한 데이터

=>url: 주소

=>parameter: 서버에게 넘겨주는 데이터 - dict로 만들어서 부착

=>header: 서버에게 넘겨주는 데이터(보이지 않습니다.) - dict로 만들어서 부착

=>method: 전송방식(GET, POST, DELETE, PUT)

 

**requests 패키지

=>웹에서 데이터를 가져올 때 많이 사용하는 패키지 - 정적인 데이터만 가져올 수 있습니다.

ajax를 이용하지 않는 데이터나 프레임을 사용하지 않는 데이터만 가져올 수 있습니다.

=>이 패키지는 python의 기본 패키지가 아닙니다.

=>pip install requests 로 설치

 

1.데이터를 가져오기 위한 구문

requests.전송방식(url)을 호출하면 Response 객체가 리턴됩니다.

 

2.Response 클래스

status_code 속성: 상태 정보

text: 가져온 데이터를 문자열로 저장

content: 가져온 데이터를 바이트 배열로 저장 - 이미지나 음성 데이터

 

3.parameter heade가 존재하는 경우

requests.전송방식(url, data={파라미터}, headers={헤더})

 

4.실습

http://httpbin.org/get 사이트에 get 방식 요청

get put delete 방식으로 요청

post는 파라미터를 설정해서 요청

Kakao Open API 데이터를 가져오기

 

1)requests 설치 - anaconda를 설치했으면 할 필요가 없습니다.

pip install requests

 

2)get 요청을 위한 코드를 작성

import requests

#requests가 가지고 있는 것들을 현재 커널에 requests 라는 이름으로 가져옴

 

#get 요청을 해서 텍스트를 확인

resp = requests.get('http://httpbin.org/get')

 

#help(requests.get) #함수의 도움말 확인

 

#print(type(resp)) #리턴된 결과의 자료형을 확인

#print(dir(requests.models.Response)) #Response 자료형은 어떤 속성들을 가졌는지 확인

 

print(resp.text) #가져온 문자열을 확인

 

3)put delete 요청을 수행

=>서버에서 지원을 해야 가능

#put delete 요청

 

4)post 방식으로 요청하는 파라미터와 함께 전송

#help(requests.post)

#requests 모듈을 사용하면 파라미터 인코딩을 할 필요가 없습니다.

 

 

5)Open API를 사용하다 보면 header cookie를 이용해야 하는 경우가 있습니다.

headers 옵션이나 cookies 옵션에 dict 형태로 만들어서 추가해주면 됩니다.

 

 

#Kakao Open API 도서 검색 사용

addr = 'https://dapi.kakao.com/v3/search/book'

params = {'query':'삼국지', 'target':'title'}

headers = {'Authorization': ''}

resp = requests.get(addr, params=params, headers=headers)

print(resp.text)

 

6)읽어온 텍스트가 현재 기본 인코딩과 맞지 않아서 텍스트가 깨지는 경우

=>받아온 Response 객체의 encoding 속성에 None을 대입해서 인코딩을 유추하게 만들거나 직접 문자열로 인코딩을 설정하면 됩니다.

utf-8: 전 세계 모든 글자를 인코딩하는 방식 - 3byte 1글자

euc-kr: 예전에 웹에서 한글만을 표현하기 위한 인코딩 방식

cp949(ms949): windows에서 한글만을 표현하기 위한 인코딩 방식

 

cp949 euc-kr은 거의 비슷합니다.

 

iso-8859-1: iso-latin-1 이라고도 하는데 서유럽 문자 표시를 위한 인코딩 방식 - 한글 안됨

 

5.이미지 파일 다운로드

=>Response text 속성 대신에 content 속성을 사용

=>파일 객체를 생성해서 write content 속성의 값을 기록하면 파일로 생성

 

#이미지를 다운로드 받아서 파일로 만들기

 

#이미지를 가져올 URL을 생성

imgurl = 'http://www.onlifezone.com/files/attach/images/962811/376/321/005/2.jpg'

 

resp = requests.get(imgurl)

 

#파일 객체를 만들고 이름은 f로 사용 - close를 할 필요가 없습니다.

with open('2.jpg', 'wb') as f:

    f.write(resp.content)

   

#현재 작업디렉토리 확인

import os

print(os.getcwd())

   

**JSON Parsing

1.JSON

=>속성과 값의 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 텍스트를 사용하는 개방형 표준 포맷

=>javascript python에서 객체(dictionary) 와 배열(list)의 표현 방법을 가져와서 사용

=>최근의 프로그래밍 언어들은 내장 또는 별도의 라이브러리를 이용해서 이 데이터를 객체로 변환해서 사용합니다.

javascript python은 내장

=>최근의 Open API 그리고 스마트 기기 들의 통신은 대부분 JSON 포맷을 사용

=>[ ]: list, { }: dict

 

2.Python에서의 JSON 파싱

json.loads(json 문자열)

=>문자열을 python 객체로 변환해 줍니다.

 

3.실습

=>카카오 카테고리 검색을 이용해서 음식점 이름과 주소를 list로 만들어서 출력

 

headers = {'Authorization': ''}

 

#웹에서 정적인 데이터를 가져오기 위한 라이브러리를 import

import requests

 

#다운로드 받을 URL 만들기

 

 

#header 만들기

headers = {'Authorization': ''}

 

#데이터 가져와서 출력

resp = requests.get(addr, headers=headers)

text = resp.text

#print(text)

 

#json 파싱 모듈을 가져오기 - 내장 모듈

import json

jsondata = json.loads(text)

#print(type(jsondata)) #맨 처음 시작이 {} 이므로 dict

 

#print(jsondata['documents']) #documents 키의 데이터 가져오기 - list

li = []

#가져온 배열을 행 단위로 읽어서

for imsi in jsondata['documents']:

    #print(imsi['address_name'], ':', imsi['place_name'])

    #place_name address_name을 가지고 dict를 생성

    d = {'장소':imsi['place_name'], '주소':imsi['address_name']}

    #dict list에 추가

    li.append(d)

 

#확인

for temp in li:

    print(temp)

 

 

**HTML Parsing

=>open api가 제공되면 json 이나 xml 형태의 데이터를 받아서 파싱해서 사용하면 됩니다.

=>web site에 보여는 주지만 open api 형태로 제공되지 않는 데이터의 경우 html을 수집해서 파싱을 해서 원하는 데이터를 가져오게 됩니다.

html을 무단 수집하는 것은 법적으로 문제가 되는 경우가 있습니다.

 

1.사용되는 패키지: beatifulsoup4

=>이 패키지는 python에는 없고 anaconda에는 존재

=>이 패키지의 bs4 라는 모듈을 이용

=>bs4.BeautifulSoup(html 텍스트, 'html.parser') 를 호출하면 BeautifulSoap 객체를 리턴

이 객체는 html의 내용을 편리하게 찾을 수 있도록 메모리 트리 형태로 펼쳐놓은 객체 입니다.

 

2.태그로 찾는 경우는 find  findall 이용

find(tag, attributes, recursive, text, limit, keyword)

=>tag가 찾고자 하는 태그

=>attributes 는 태그 안에 속성이 있는 경우 속성명=값 의 형태로 대입해서 속성의 값까지 일치하는 것을 찾습니다.

 

<div id='1'></div>

<div id='2' align='center'></div>

<span id='3'></span>

 

div 다 찾기: find('div')

id 2번인 div 찾기: find('div', align='center')

=>find_all은 사용법은 같은데 find 1개만 찾고 find_all 은 전부 찾아옵니다.

 

3.선택자로 찾는 경우는 select()

=>Tag list로 리턴

 

4.찾은 데이터에서 정보를 추출

1)태그 안의 내용을 가져오기: getText()

2)속성의 값을 가져오기:get('속성명')

 

5.실습1 : https://ko.wikipedia.org/wiki/%EA%B8%B0%EA%B3%84_%ED%95%99%EC%8A%B5

에서 하이퍼링크 태그의 url과 텍스트를 수집

하이퍼링크가 /wiki/로 시작하는 것만 출력

 

 

#위키피디아에서 하이퍼링크(a) 태그의 내용 가져오기

import requests

 

addr = 'https://ko.wikipedia.org/wiki/%EA%B8%B0%EA%B3%84_%ED%95%99%EC%8A%B5'

resp = requests.get(addr)

#print(resp.text)

 

#html 파싱을 위한 라이브러리 가져오기

import bs4

 

#DOM 객체로 만들기

bs = bs4.BeautifulSoup(resp.text, 'html.parser')

#print(type(bs))

 

#a 태그의 내용 가져오기

li = bs.find_all('a')

#print(li)

 

#정규식(문자열 패턴을 조회하기 위한 식) 모듈 import

import re

for temp in li:

    #print(temp.getText()) #태그 안의 내용 가져오기

    #print(temp.attrs['href']) #key 에러 - href가 없는 경우도 있음

    if 'href' in temp.attrs: #href 속성이 temp.attrs에 있는 경우에만

        #href 속성에 /wiki/로 시작하는 링크의 텍스트와 링크만 출력

        href = temp.attrs['href']

        #정규식 생성 - /wiki/ 로 시작하는

        p = re.compile('^(/wiki/)')

        if p.search(href) != None:

            print(temp.getText(), ':', href)

   

6.실습2: https://tv.naver.com/에서 상위 항목의 제목과 링크 가져오기

=>선택자 이용

=>선택자를 찾는 방법은 소스 보기를 해서 직접 찾아도 되고 chrome의 검사 기능에서 필요한 부분을 선택하고 copy selector를 이용해서 찾아도 됩니다.

 

#네이버 tv 팟에서 하이퍼링크(a) 태그의 내용 가져오기

import requests

 

addr = 'https://tv.naver.com/'

resp = requests.get(addr)

#print(resp.text)

 

#html 파싱을 위한 라이브러리 가져오기

import bs4

 

#DOM 객체로 만들기

bs = bs4.BeautifulSoup(resp.text, 'html.parser')

#선택자를 이용해서 선택

tvlist = bs.select('dl > dt > a > tooltip')

for temp in tvlist:

    print(temp.getText())

 

7.태그 속성

태그(중복 가능 - 웹 브라우저에서의 모양) : 선택자로 사용할 때는 tag이름

클래스(중복 가능 - 태그들을 그룹화하기 위한 속성) : 선택자로 사용할 때는 .class이름

아이디(중복 불가능 - 태그를 다른 것과 구별하기 위한 속성) : 선택자로 사용할 때는 #id

 

name(중복 가능 - 서버에게 전송할 때 사용할 파라미터 이름)

xpath(중복 불가능 - 브라우저가 태그를 구분하기 위해서 사용하는 경로)

 

8.실습3

http://www.weather.go.kr/weather/observation/currentweather.jsp 에서 도시이름과 온도, 습도를 가져와서 꺽은선 그래프로 출력

=>찾고자 하는 데이터는 class 이름이 table_develop3

 

#오늘 날씨를 가져와서 그래프 그리기

import requests

 

#필요한 html 가져오기

resp = requests.get('http://www.weather.go.kr/weather/observation/currentweather.jsp')

text = resp.text

#print(text)

 

import bs4

bs = bs4.BeautifulSoup(text, 'html.parser')

#class 속성의 값이 table_develop3 인 데이터 찾아오기

table = bs.select('.table_develop3')

#print(table)

 

#도시이름, 온도, 습도를 저장할 list를 생성

loc = []

temp = []

hum = []

 

#가져온 테이블 중에서 첫번째 테이블로부터 줄(tr) 단위로 읽기

for tr in table[0].find_all('tr'):

    tds = tr.find_all('td') #tr 태그에서 td를 전부 찾아서 tds에 대입

    for td in tds:

        if td.find('a'): #a 태그가 있으면 도시이름이 있는 행입니다.

            #도시이름을 loc 추가

            loc.append(td.find('a').text)

            #온도를 temp에 추가

            temp.append(tds[5].text)

            #습도를 temp에 추가

            hum.append(tds[10].text)

 

#데이터 확인

#인덱싱은 번호1개만 작성해서 하나의 데이터만 추출

print(loc[0:5]) #0-4 번행 까지 확인 - 슬라이싱(범위를 가지고 추출)

print(temp[0:5])

print(hum[0:5])

 

#필요한 도시의 데이터만 추출

cities = ['서울', '부산', '인천', '대구', '대전', '광주', '울산', '창원', '흑산도']

#위 도시들의 온도와 습도를 저장할 list

temperatures = []

humidities = []

 

#cities에 있는 데이터만 추출해서 저장

for city in cities:

    j = 0

    for c in loc:

        if c == city:

            temperatures.append(temp[j])

            humidities.append(hum[j])

            break

        j = j + 1

 

print(cities)

print(temperatures)

print(humidities)

 

#파이썬에서 시각화를 하는 기본 패키지

import matplotlib.pyplot as plt

#한글 폰트 사용을 위한 패키지

from matplotlib import font_manager, rc, rcParams

import platform #운영체제 확인을 위한 패키지

 

#주피터 노트북에서 그래프를 셀 안에 출력해주는 설정

%matplotlib inline

 

#음수를 제대로 표현하기 위한 설정

rcParams['axes.unicode_minus'] = False #이 설정을 하지 않으면 음수가 네모로 출력

 

#한글 폰트 설정

if platform.system() == 'Windows': #윈도우즈라면

    font_name = font_manager.FontProperties(fname='c:/windows/Fonts/ahn_b.ttf').get_name()

    rc('font', family=font_name)

elif platform.system() == 'Darwin': #매킨토시라면

    rc('font', family='AppleGothic')

else:

    print('알 수 없는 운영체제')

   

   

#그래프 그리기

plt.figure(figsize=(12,4), dpi=300) #그래프 크기 설정 - 가로 12inch 세로 4인치

#꺽은선 그래프 - plot

plt.plot(temperatures, label='온도', lw=3, color='r', linestyle='-', marker='s')

#plt.plot(humidities, label='습도', lw=3, color='g', linestyle='-', marker='s')

 

#x

plt.xticks(range(0,len(cities),1), cities, rotation='vertical')

#범례

plt.legend()

plt.savefig('graph.png', dpi=300)

#출력

plt.show()

 

**XML 파싱

=>XML: 데이터를 태그 형식으로 표현하는 표준 데이터 포맷

=>예전에 거의 모든 데이터 포맷이 XML

지금은 우리나라 공공기관 Open API 와 실시간 뉴스를 전송해주는 RSS 그리고 프로젝트 설정 파일에 주로 이용

=>BeautifulSoup xml 패키지를 이용해서 파싱 가능

=>BeautifulSoup를 사용하는 경우 html.parser 대신에 lxml-xml 을 사용하면 됩니다.

 

http://www.hani.co.kr/rss/ 에서 item 태그 안의 title 만 전부 조회

 

#XML 파싱

#http://www.hani.co.kr/rss/ 에서 item 태그의 title만 추출

 

#데이터 가져오기

import requests

resp = requests.get('http://www.hani.co.kr/rss/')

text = resp.text

#print(text)

 

import bs4

#트리로 펼쳐내기

bs = bs4.BeautifulSoup(text, 'lxml-xml')

 

items = bs.find_all('item')

 

for item in items:

    title = item.find('title')

    print(title.getText())

 

 

**Selenium

=>web에서 동적으로 생성되는 데이터는 requests 모듈을 가지고 가져올 수 없습니다.

requests 모듈은 처음 접속했을 때 출력되는 데이터만 가져옵니다.

ajax 처럼 비동기적으로 데이터를 가져오거나 로그인을 한 후 보여지는 데이터들은 requests 모듈로는 가져올 수 없습니다.

이처럼 동적으로 만들어지는 데이터는 브라우저를 직접 실행시켜서 동작시키는 Selenium 이라는 웹 앱 테스트 프레임워크를 이용해야 합니다.

=>웹 애플리케이션을 테스트하기 위한 프레임워크

=>기본 패키지가 아니므로 설치를 해야 합니다.

pip install selenium

 

1.브라우저 동작

=>동작시킬 브라우저의 드라이버를 다운로드

=>브라우저를 동작시키지 않고 가져오고자 하는 경우에는 pantom.js를 이용 - Deprecated

=>크롬을 이용할 것이라서 크롬 드라이버를 다운로드

1)chrome 에서 크롬 정보 확인 - chrome 79 버전

 

2)https://chromedriver.chromium.org/downloads 에서 자신의 버전에 맞는 드라이버를 다운로드

=>압축을 해제하고 exe 파일을 찾기 쉬운곳에 배치 : c:/chromedriver.exe

 

3)브라우저 실행

selenium.webdriver.Chrome("크롬 드라이버 경로")

 

4)실습

#크롬 실행하기

from selenium import webdriver

driver = webdriver.Chrome('c:/chromedriver')

 

2.webdriver 의 메소드

=>implicitly_wait(시간): 초 단위 대기 - 여러 사이트에 데이터를 크롤링 하는 경우 또는 첫 화면에 ajax로 데이터를 호출하는 경우 일정시간 대기시켜서 데이터를 읽어옵니다.

 

=>get(url): 브라우저가 url에 접속

 

=>페이지 내의 element에 접근하는 메소드

find_element_by_name(name을 가지고 접근)

find_element_by_id(id를 가지고 접근)

find_element_by_xpath(xpath를 가지고 접근)

 

find_element_by_css_selector(선택자를 가지고 접근)

find_element_by_class_name(class name을 가지고 접근)

find_element_by_tag_name(tag를 가지고 접근)

 

=>element를 찾으면 입력도구 인 경우는 send_keys() 을 호출하면 값을 입력

=>click()을 호출하면 클릭한 효과

 

앞의 3개는 1개의 데이터를 리턴하고 뒤의 3개는 list 형태로 리턴

 

=>quit(): 브라우저 종료

 

=>execute_script(자바스크립트 코드): 자바스크립트 코드 수행

 

=>page_source 속성: html 가져오기

3.실습

1)실습1. daum 카페 페이지에 접근

 

#다음 카페 목록에 접근하기

#크롬 실행하기

from selenium import webdriver

driver = webdriver.Chrome('c:/chromedriver')

#3초대기

driver.implicitly_wait(3)

 

#다음 카페 목록에 접근 - 로그인 되어 있지 않으면 로그인 페이지로 이동

driver.get('url 주소')

 

2)다음 웹 사이트에 로그인을 한 후에 카페 목록 페이지로 이동

다음 로그인 페이지: url주소

 

#다음에 로그인을 하고 카페 목록으로 이동

from selenium import webdriver

driver = webdriver.Chrome('c:/chromedriver')

#3초대기

driver.implicitly_wait(3)

 

#다음 로그인 페이지로 이동

driver.get('url 주소')

 

#아이디와 비밀번호 입력받기

username = input('아이디를 입력하세요')

userpw = input('비밀번호를 입력하세요')

 

#다음 로그인 페이지에 아이디와 비밀번호 입력

#driver.find_element_by_id('id').send_keys(username)

driver.find_element_by_xpath('//*[@id="id"]').send_keys(username)

driver.find_element_by_xpath('//*[@id="inputPwd"]').send_keys(userpw)

 

#로그인 버튼을 클릭한 후 카페 목록 페이지로 이동

driver.find_element_by_xpath('//*[@id="loginBtn"]').click()

driver.find_element_by_xpath('//*[@id="loginBtn"]').click()

 

#여러 페이지를 이동할 때는 중간에 잠시 대기 시간을 주어야 할 필요가 있습니다.

import time

time.sleep(3) #3초 대기

 

#카페 목록으로 이동

driver.get('http://top.cafe.daum.net/_c21_/my_cafe')

 

#접속한 사이트의 html 가져오기

html = driver.page_source

 

4.frame

=>frame html 페이지 내에서 다른 html 페이지의 내용을 출력하기 위해 사용하는 객체

=>스크래핑을 하다보면 화면에 출력이 되고 페이스 소스에서도 확인이 되는데 접근이 안되는 경우가 있습니다.

이런 경우는 ajax로 나중에 불려졌거나 아니면 프레임을 이용해서 다른 파일에서 출력한 경우입니다.

ajax 의 경우는 딜레이를 주고 데이터를 읽으면 가능합니다.

프레임의 경우는 프레임에 직접 접근해서 데이터를 읽어야 합니다.

 

1)현재 페이지에서 frame 조회

변수 = driver.find_element_by_css_selector('iframe')

for 임시변수 in 변수:

           print(임시변수.get_attribute('name')

 

=>현재 페이지의 모든 iframe의 이름을 조회

 

2)프레임 이동

=>driver.switch_to_frame('프레임이름') : 프레임이름에 해당하는 곳으로 이동

=>driver.switch_to_default_content() :  상위 프레임으로 전환

 

5. 프레임 사용 실습

=>이전 것에 이어서 작성

 

#카페 목록 중에서 첫번째 페이지로 이동

#driver.find_element_by_xpath('//*[@id="mArticle"]/div/div[1]/div/div[2]/ul/li/a/div[1]/div[2]/div/div/strong').click()

 

#직접 카페로 이동 - 카페 글쓰기 페이지로 이동

driver.get('http://cafe.11111daum.net/samhak7/_memo')

 

#특정 프레임으로 이동

driver.switch_to_frame('down')

 

#글작성 란에 텍스트를 입력

driver.find_element_by_xpath('//*[@id="memoForm"]/div/table/tbody/tr[1]/td[1]/div/textarea').send_keys('파이썬에서의 매크로')

driver.find_element_by_xpath('//*[@id="memoForm"]/div/table/tbody/tr[1]/td[2]/a[1]/span[2]').click()

 

6.크롬을 화면에서 출력시키지 않고 데이터 가져오기

=>웹 드라이버를 옵션을 추가해서 생성

#크롬을 화면에 출력하지 않고 실행하기

options = webdriver.ChromeOptions()

options.add_argument('headless')

options.add_argument('window-size=1920x1080')

options.add_argument("disable-gpu")

# 혹은 options.add_argument("--disable-gpu")

 

driver = webdriver.Chrome('c:/chromedriver', chrome_options=options)

 

 

7.20번 스크롤 한 데이터 가져오기

#20번 스크롤 하기

from selenium import webdriver

import time

from selenium.webdriver.common.keys import Keys

import bs4

 

driver = webdriver.Chrome('c:/chromedriver')

 

driver.get('')

time.sleep(5)

 

body = driver.find_element_by_tag_name('body')#스크롤하기 위해 소스 추출

num_of_pagedowns = 20

#10번 밑으로 내리는 것

while num_of_pagedowns:

    body.send_keys(Keys.PAGE_DOWN)

    time.sleep(2)

    num_of_pagedowns -= 1

   

html = bs4.BeautifulSoup(driver.page_source,'html.parser')

print(html)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

'Study > 데이터 분석' 카테고리의 다른 글

데이터분석-6  (0) 2020.11.10
데이터분석-5  (0) 2020.11.09
데이터분석-4  (0) 2020.11.08
데이터분석-3  (0) 2020.11.08
데이터 분석-1  (0) 2020.11.08
반응형

** java.net. InetAddress

=>ip정보를 저장하는클래스

=>Static메소드인 HetLocalHost(),getByName(String hostname),getAllByName(String hostname)

getLocalHost():자기 컴퓨터의 ip정보를 리턴

getByName(): hostip정보 1개를 리턴

getAllByName(): host의 모든 ip정보를 리턴

 

**소켓 통신

Socket: NIC(Network Interface Card- LAN Card)를 추상화한 클래스

네트워크 프로그래밍이라는 용어 대신에 Socket Programming이라고도 합니다.

1.통신 방법

1)TCP 프로토콜을 사용하는 스트림 소켓

2)UDP 프로토콜을 사용하는 데이터그램 소켓

 

2.TCP (연결형 통신)

수신하는 쪽에서 송신하는 쪽으로 연결을 요청

송신하는 쪽에서 연결을 하고 요청하는 데이터에 대한 메타 정보(데이터에 대한 정보 - 데이터 크기 등) 를 송신

수신하는 쪽에서 그 정보를 보고 다시 요청을 합니다.

송신하는 쪽에서 데이터를 전송

수신하는 쪽에서 데이터 수신 여부를 송신하는 쪽에 전송하고 통신이 종료

신뢰성이 높지만 트래픽이 증가

http, https TCP통신

 

3.udp(비연결형 통신)

송신하는 쪽에서 수신하는 쪽으로 일방적으로 데이터를 전송하고 통신이 종료

DHCP(IP 동적 할당),DNS(DOmain ->ip)

콜 센터 ,appleapns(apple push Notification Service- 애플 제품의 알림)

수신 쪽에서 데이터를 제대로 받았는지 알 수 없음

public class IPInfo {

       public static void main(String[] args) {

              

               try {

                      //자신의 컴퓨터 ip정보 확인 - 자신의 컴퓨터 이름 (도메인) ip주소

                      InetAddress local = InetAddress.getLocalHost();

                      System.out.println(local);

                      // 구글의 ip장보 학인

                      InetAddress [] googles= InetAddress.getAllByName("www.google.com");

                      for(InetAddress imsi: googles) {

                             System.out.println(imsi);

                      }

               } catch (UnknownHostException e) {

                      System.out.println("예외:" +e.getMessage());

               }

       }

}

 

4Socket 클래스

1)생성자

Socket()

Socket(InetAddress addr, int port): addr port번호에 해당하는 서비스에 접속

Socket(String addr, int port, InetAddress addr, int port ):addrport번호에 접속을 하는데 자신의 주소르 localaddr그리고 portlocalportㄹ 설정해서 접속

 

=>addr이 잘못 되면 NullPointerException 그리고 port번호가 잘못되면 illegalAgumentException이 발생

 

 

2)메소드

void close()

InetAddress getInetAddress():접속된 상대방 ip정보

int getPort():상대방 포트 번호

InputStream getInputStream() 상대방에게서 정보를 읽어오기 위한 스트림

OutputStream getOutputStream() 상대방에게서 정보를 전송하기 위한 스트림

 

 

5. 스트림 소켓 - tcp통신을 위한 소켓

1)수신 받는 쪽의 소켓 생성과 요청

Socket 소켓변수 = new Socket(서버 ip주소 ,포트번호);//연결

//요청 전송

OutputStream 출력스트림 변수 = 소켓변수.getOutputStream();

 

//바이트 단위 전송

출력스트림변수.write(byte[] b);

//문자단위 전송

PrintWriter pw = new PrintWriter(출력스트림변수);

pw.println(String msg);

pw.flush();

 

 

//데이터 읽어오기

InputSteam 입력스트림변수 = 소켓변수.getInputStream();

//바이트 단위로 읽어오기

입력스트림변수 .read(byte[] b);

 

//문자열 단위로 읽어오기

BufferedReader br = new BufferedReader(new InputStreamRader(입력스트림변수));

String msg = br.readLine();//한줄 읽어오기

//null을 리턴할 때 까지 읽으면 전송된 모든 내용을 읽을 수 있습니다.

 

 

6.www.daum.nethtml가져오기

=>www.daum.net이 호스트이름이고 http서버는 기본 포트 번호가 80

 

public class DaumMain {

       public static void main(String[] args) {

               try {

                      //daum 주소를 생성

                      InetAddress addr = InetAddress.getByName("www.daum.net");

                      //TCP 소켓 생성

                      Socket socket = new Socket(addr, 80);

                     

                      //요청 전송

                      PrintWriter pw = new PrintWriter(socket.getOutputStream());

                      pw.println("GET http://www.daum.net");

                      pw.flush();

                     

                      //데이터 읽기 - 문자 단위

                      BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                     

                      //읽을 데이터가 없을 까지 줄단위로 읽ㅇ오기

                      while(true) {

                             String line = br.readLine();

                             if(line == null) {

                                    break;

                             }

                             System.out.println(line);

                      }

                      br.close();

                      socket.close();

               }catch (Exception e) {

                      //예외 메시지 출력

                      System.out.println("예외:" +e.getMessage());

                      //예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

7.TCP Server:정보를 제공

=>ServerSocket 사용

1)생성자

ServerSocket()

ServerSocket(int port): port 개방해서 클라이언트의 요청을 받을 있도록 서버가 생성

ServerSocket(int port, int backlog): port 개방해서 클라이언트의 요청을 받을 있도록 서버가 생성되고 최대 접속 개수를 설정

 

2)메소드

void close()

 

Socket accept():호출하면 클라이언트의 요청이 까지 대기 상태가 되고 클라이언트의 요청이 오면 클라이언트와 통신할 있는 Socket 리턴하고 다음으로 넘어갑니다.

 

3)통신과정

=>ServerSocket 생성해서 클라이언트의 요청을 기다림

=>클라이언트 쪽에서 Socket 이용해서 서버에 접속

=>Socket 스트림을 가지고 메시지를 전송

=>ServerScoket 생성할 port 사용 중이 아닌 번호로 설정 -1024보다 숫자로 설정하는 것을 권장

서버 소켓을 생성하고 예외가 발생해서 프로그램이 중단되면 이전에 사용한 포트번호를 사용하지 못할 있습니다.

자바로 실행 중인 프로세스를 찾아서 중단해야 이전 포트를 다시 사용 가능합니다.

=>현재 사용 중인 포트를 확인:netstat - ano

자신의 ip확인 :ipconfig / (config -mac)

=>다른 컴퓨터에서 자신의 컴퓨터에 접속하도록 할려면 방화벽 해제 되어 있어야 합니다.

 

public class TCPServer {

       public static void main(String[] args) {

               try {

                      //서버 소켓을 생성

                      ServerSocket ss = new ServerSocket(9000);

                      while(true) {

                             System.out.println("서버 대기  ...");

                             //클라이언트의 접속을 기다림

                             Socket socket = ss.accept();

                             //접속한 클라이언트 정보 확인

                             System.out.println("접속한 클라이언트 : " +socket.getInetAddress());

                             //클라이언트가 전송한 메시지 확인

                             BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                             String msg = br.readLine();

                             System.out.println("메시지:" +msg);

                            

                             //클라이언트에게 메시지 전송

                             PrintWriter pw= new PrintWriter(socket.getOutputStream());

                             pw.println("서버가 보내는 메시지");

                             pw.flush();

                            

                             br.close();

                             pw.close();

                             socket.close();

                      }

               }catch (Exception e) {

                      //예외 메시지 출력

                      System.out.println("예외:" +e.getMessage());

                      //예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

public class TCPClinet {

       public static void main(String[] args) {

               try {

                      //서버에 접속하는 소켓을 생성 - 127.0.0.1

                      Socket socket = new Socket(InetAddress.getByName("ip주소") , 9000);

                      //메시지 전송

                      Scanner sc = new Scanner(System.in);

                      System.out.print("전송할 메시지:");

                      String msg = sc.nextLine();

                      PrintWriter pw= new PrintWriter(socket.getOutputStream());

                      pw.println(msg);

                      pw.flush();

                     

                      //메시지 읽기

                      BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                      String str = br.readLine();

                      System.out.println(str);

                     

                      br.close();

                      pw.close();

                      socket.close();

               }catch (Exception e) {

                      //예외 메시지 출력

                      System.out.println("예외:" +e.getMessage());

                      //예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

8.UDP

=>비연결형 통신

=>보내는 쪽에서 받는 쪽으로 메시지만 전송하고 통신이 종료

1)통신방식

unicast:1:1로 통신하는 방식

multicast:그룹에 속한 모든 클라이언트와 통신

 

broadcast:자신이 ip대역과 subnet mask를 이용해서 자신의 ip대역과 같은 그룹에 속한 모든 클라이언트에게 전소

 

 

2)DatagramPacket클래스와 DataGramSocket클래스 이용

=>DataGramSocket클래스

생성자

DataGramSocket(): 전송을 하기 위한 소켓

DataGramSocket(int socket):전송을 받기 위한 소켓

 

메소드

void close();

void recieve(DatagramPacket packet): 데이터를 받는 메소드

void sen(DatagramPacket packet): 데이터를 보내는 메소드

 

 

=>DatagramPacket클래스

생성자

DatagramPacket(byte [] bif, int length):전송을 받기 위한 패킷으로 byte배열에 데이터가 저장됩니다.

DatagramPacket(byte [] bif, int length, InetAddress addr, int port) :전송을 하기 위한 패킷으로 byte 배열의 내용을 length만큼 addrport에게 전송하기 위한 패킷

 

메소드

byte[] getData(): 데이터 리턴

int getLength():길이 리턴

 

=>String byte배열 변환

String ->byte배열 :String.getBytes();

byte배열 ->String : new String(byte배열)

public class UDPReceive {

       public static void main(String[] args) {

               try {

                      //받는 소켓을 생성

                      DatagramSocket socket = new DatagramSocket(7777);

                     

                      //데이터를 저장할 패킷을 생성

                      //byte[] b = new byte[65536];

                      //DatagramPacket dp = new DatagramPacket(b, b.length);

                      //데이터를 전송받아서 읽기

                      while(true) {

                            

                             //데이터를 저장할 패킷을 생성

                             // 두개의 문장을 반복문 바깥에 만들면 통신은 되는데 메시지를 보내고 짧은 메시지를 보내면

                             //짧은 메시지 뒤에 메시지의 내용이 추가되는 형태가 됩니다.

                             //반복문 안에서 계속 사용해야 하는 데이터는 반복문에서 초기화를 해주어야 합니다.

                             byte[] b = new byte[65536];

                             DatagramPacket dp = new DatagramPacket(b, b.length);

                            

                             //대기하고 있다가 데이터를 전송받으면 동작

                             socket.receive(dp);

                             //보낸곳 확인

                             System.out.println("보낸 :" +dp.getAddress().getHostAddress());

                             //데이터 확인

                            

                             String msg = new String(b);

                             System.out.println(msg);

                            

                      }

               }catch (Exception e) {

                      //예외 메시지 출력

                      System.out.println("예외:" +e.getMessage());

                      //예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

 

public class UDPSend {

       public static void main(String[] args) {

               try {

                      // udp전송을 위한 소켓 생성

                      DatagramSocket ds = new DatagramSocket();

                      Scanner sc = new Scanner(System.in);

                      while(true) {

                             //메시지 입력

                             System.out.print("전송할 메시지:");

                             String msg = sc.nextLine();

                            

                             //전송할 패킷 생성

                             DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.getBytes().length,InetAddress.getByName("127.0.0.1"),7777);

                             ds.send(dp);

                            

                             //sc.close();

                             //ds.close();

                      }

               } catch (Exception e) {

                      // 예외 메시지 출력

                      System.out.println("예외:" + e.getMessage());

                      // 예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

 

4)multicast

=>그룹에 속한 모든 단말에게 데이터를 전송하는 방식

=>244.0.0.0 ~ 239.255.255.255사이의 주소를 이용

이 주소 대역은  D class대역으로 Multicast용으로 예약된 ip주소 대역

=>MulticastScoket을 이용해서 구현

 

=>생성자

MulticastScocket();

MulticasetSocket(int port):

 

=>메소드

joinGroup(InetAddress addr) :그룹에 참여

leaveGroup(InetAddress addr):  그룹에서 빠져나오는 메소드

 

=>데이터 전송방식은 DatagramScocket과 동일

 

=>multicast 받는 쪽

 

public class MultiReceive {

       public static void main(String[] args) {

               try {

                      MulticastSocket ms = new MulticastSocket(9999);

                      //멀티케스트에 참여

                      //224.0.0.0 to 239.255.255.255

                      ms.joinGroup(InetAddress.getByName("ip주소"));

                      System.out.println("멀티 케스트 시작");

                     

                      while(true) {

                             //전송 받은 데이터를 저장할 바이트 배열 - 크기는 8 배수로 설정

                             byte [] b = new byte[65536];

                             //패킷을 생성

                             DatagramPacket dp = new DatagramPacket(b, b.length);

                             //데이터를 받을 있도록 대기

                             ms.receive(dp);

                            

                             //데이터 읽기

                             String msg = new String(dp.getData());

                             System.out.println(ms);

                      }

                     

               }catch (Exception e) {

                      //예외 메시지 출력

                      System.out.println("예외:" +e.getMessage());

                      //예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

 

=>multicast 보내는 쪽

public class MultiSend {

       public static void main(String[] args) {

               try {

                      MulticastSocket ms = new MulticastSocket();

                      Scanner sc = new Scanner(System.in);

                     

                      System.out.print("닉네임:");

                      String nickname = sc.nextLine();

                      while(true) {

                             System.out.print("전송할 메시지(종료는 end):");

                             String msg = sc.nextLine();

                             //자바에서 문자열은 == 비교하면 참조를 비교

                             //equals 비교해야 값을 비교

                             if(msg.equals("end")) {

                                    System.out.println("종료");

                                    break;

                             }

                             msg = nickname +" : "+ msg;

                             DatagramPacket dp =  new DatagramPacket(msg.getBytes(), msg.getBytes().length,InetAddress.getByName("ip주소"),9999);

                             ms.send(dp);

                      }

               } catch (Exception e) {

                      // 예외 메시지 출력

                      System.out.println("예외:" + e.getMessage());

                      // 예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

=>채팅 처럼 동시에 주고 받는 것이 가능하도록 할려면 보내고 받는 로직을 스레드를 이용해서 작업

콘솔에서는 쉽지 않습니다.

입력창과 출력창이 같아서 콘솔을 채팅은 동시에 입출력 한계가 있습니다.

 

 

**url 통신

=>소켓 통신을 저수준의 통신방식이라고 하고 그 이외의 통신 방식들은 고수준이라고 부릅니다.

성능은 소켓 통신이 우수한데 소켓 통신은 프로그램을 별도로 설치해야만 통신이 가능합니다.

url 통시은 브라우저를 통해서 사용이 가능하고 현재는 거의 모든 운영체제가 웹 브라우저를 하나씩 가지고 있습니다.

소켓 통신 : 증권 , 게임 등 주식거래는 조금한 시간의 차가 경제적으로 문제가 발생할 수 있다. 빨리 해야 한다.

최근에는 웹에서도 소켓 방식의 통신이 가능합니다.

WebSocket APIHTML5에서 제공

 

=>ULR 구성

프로토콜 : // 도메인이나 IP :포트번호 /파일 경로?이름=&이름=...

프포토콜과 도메인은 생략 못함

포트번호는 서비스의 기본포트를 사용하는 경우에는 생략이 가능

http:80, https:443

파일경로를 생략하는 경우가 있는데 이 경우는 서버의 설정을 이용해서 파일을 찾아옵니다.

 

파일 경로 뒤에 ? parameter라고 하는데 클라이언트가 서버에게 넘겨주는 데이터로 key-value형식으로 대입

parameter 전송 방식을 가지고 get방식과 post 방식을 구분

 

파일 경로 뒤에 #이 붙는 경우는 책갈피 입니다.

페이지 내엣 이동

 

1.java.net.URL클래스

=>URL을 만들기 위한 클래스

1)생성

URL(String url)

=>없는 url을 대입하면 MalformedURLException이 발생

 

2)메소드

URLConnection openConnection():URL과 양방향 통신이 가능한 Connection 을 리턴

여기서 리턴한 Connection HttpURLConnection이나 JarURLConnection으로 형변환해서 사용해야 합니ㅏㄷ.

 

URLConnection은 추상 클래스라서 메소드가 구현되어 있지 않습니다.

 

2.HttpURLConnection

=>URL 통신을 하기 위한 클래스

=>URL 클래스의 openConnection메소드를 이용해서 생성

=>메소드

setConnectTimeout(int timeout):밀리초 단위로 타입아웃을 설정하는 메소드로 타임 아웃 동안 접속이 안되면 접속 실패

 

setUseCaches(boolean isCache):이전에 접속했던 URL에 다시 요청할 때 이전 데이터를 가져올 것인지 설정 자주 변경되는 URL의 데이터는 반드시 false로 설정을 해주어야 합니다.

 

 

setRequestProperty(String field, String value)

addRequestProperty(String field, String value)

헤더에 값을 추가하는 메소드

카카오는 헤더에 추가해야 된다.

 

setRequestMethod(String method): 전송 방식을 설정

 

int getResponseCode():서버로 부터의 상태를 리턴

200번대 정상응답

300번대 리다이렉트 중

400번대 클라이언트 오류( 404- 잘못된 url)

500번대 서버 오류

 

InputStream getInputStream(): 데이터를 읽기 위한 스트림 리턴

 

3.웹의 데이터 포맷

xml: 태그 형식으로 표현하는 포맷, 별도의 라이브러리 없이 파싱 가능

JSON: 자바스크립트 객체 표현 방법으로 데이터를 표현, 별도의 라이브러리를 추가해야 파싱 가능

 

CSV: 구분자가 있는 문자열

HTML: 뷰의 용도로 사용되는 포맷인데 사이트에서 XML이나 JSON형태로 데이터를 제공해주지 않아서 수집해서 사용

 

 

4.OPEN API

데이터를 가진 곳에서 일반 사용자들에게 데이터를 사용할 수 있도록 XML이나 JSON형식으로 제공하는 것 데이터 뿐 아니라 라이브러리나 프레임워크 등을 제공하기도 함

 

데이터는 대부분의 경우 가입을 해서 키를 받는 형태로 제공

키 값을 주소에 넣기도 하고 헤더에 하는 방법

 

http://data.go.kr/

 

 

5.동기적 다운로드

public class StringDownload {

       public static void main(String[] args) {

               try {

                      //다운로드 받을 url 생성

                      URL url= new URL("https://www.naver.com");

                      //url연결 객체 생성

                       HttpURLConnection con = (HttpURLConnection)url.openConnection();

                       //연결 옵션 설정

                       con.setConnectTimeout(30000); //30 동안 연력이 안되면 연결시도 종료

                       //캐시 사용을 하지 않음

                       con.setUseCaches(false);

                       

                       //데이터를 읽어올 스트림을 생성

                       BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));

                       //많은 양의 문자열을 읽어야 하는 경우

                       StringBuilder sb = new StringBuilder();

                       while(true) {

                              // 읽기

                              String line = br.readLine();

                              //읽은 데이터가 없으면 반복은 중단

                              if(line == null) {

                                     break;

                              }

                              //데이터가 있으며면 sb 추가

                              sb.append(line+"\n");//메모리 낭비가 줄어들 있다.

                       }

                       //StringBuilder 데이터를 STring 으로 변환

                       String msg = sb.toString();

                       System.out.println(msg);

               }catch (Exception e) {

                      //예외 메시지 출력

                      System.out.println("예외:" +e.getMessage());

                      //예외가 발생한 코드를 역추적

                      e.printStackTrace();

               }

       }

}

 

 

6.비동기 다운로드

=>위처럼 스레드를 사용하지 않고 다운로드 받는 방식을 동기식이라고 합니다.

동기식은 데이터를 다운로드 받는 동안 다른 작업을 할 수 없습니다.

데이터 다운로드와 관련없는 작업도 데이터를 다운로드 동안은 수행할 수 없습니다.

네트워크 작업은 스레드를 이용해서 비동기식으로 동작하도록 만드는 것을 권장(안드로이드는 필수)

다운로드와 관련없는 작업은 다운로드 받는 동안 수행되도록 작성한는 것이 좋습니다.

 

public class ImageDownload {

       public static void main(String[] args) {

               Thread th = new Thread() {

                      public void run() {

                             try {

                                    String addr = "https://img0.yna.co.kr/photo/yna/YH/2019/04/07/PYH2019040703010000700_P4.jpg";

                                    //파일명을 만들기 위해서 마지막/ 다음의 문자열 가져오기

                                    int len = addr.lastIndexOf("/");

                                    String filename =addr.substring(len+1);

                                    System.out.println(filename);

                                    //현제 디렉토리에 파일이 있으면 있다고 출력하고 없다면 다운로드 받아서 저장

                                    File f = new File("./"+filename);

                                    if(f.exists() == true) {

                                           System.out.println("파일이 이미 존재합니다.");

                                            return;

                                    }else {

                                            //한번에 읽어오기

                                            /*

                                            URL url = new URL(addr);

                                            HttpURLConnection con = (HttpURLConnection)url.openConnection();

                                           con.setConnectTimeout(30000);

                                           con.setUseCaches(false);

                                           

                                            //다운로드 받을 파일의 킈를 가져오기

                                            int length = con.getContentLength();

                                            //데이터 저장할 바이트 생성

                                            byte [] b = new byte[length];

                                            //바아트 단위로 데이터를 읽어옴 스트램 생성

                                           BufferedInputStream bis = new BufferedInputStream(con.getInputStream());

                                            //대이터틀 읽어서 b 저장

                                            bis.read(b);

                                            //읽어온 내용을 파일제 저장

                                            PrintStream ps = new PrintStream(new FileOutputStream("./src/java/"+filename));

                                            ps.write(b);

                                           

                                            //사용한 스트럼 닫기

                                            ps.close();

                                            bis.close();

                                            //연결 끝ㅎ기

                                            con.disconnect();

                                             */

                                           

                                            URL url = new URL(addr);

                                            HttpURLConnection con = (HttpURLConnection)url.openConnection();

                                           con.setConnectTimeout(30000);

                                           con.setUseCaches(false);

                                           

                                            //데이터 저장할 바이트 생성

                                           BufferedInputStream bis = new BufferedInputStream(con.getInputStream());

                                            //읽어온 내용을 파일제 저장

                                            PrintStream ps = new PrintStream(new FileOutputStream("./src/java/"+filename));

                                           

                                           while(true) {

                                                   //size 바이트 배열

                                                   byte [] b= new byte[512];

                                                   //내요을 읽어서 b 저장하고

                                                   //읽은 개수를 r 저장

                                                   int r = bis.read(b);

                                                   //읽은개 없으면 중닺ㄴ

                                                   if(r<= 0) {

                                                          break;

                                                   }

                                                   ///읽은 데이터가 있으면 기록

                                                   ps.write(b,0,r);

                                                   //버퍼에 내용이 남아있는 것을 방지하기 위해서 마지막에 flush 호출

                                                   ps.flush();

                                            }

                                           

                                            //사용한 스트럼 닫기

                                            ps.close();

                                            bis.close();

                                            //연결 끝ㅎ기

                                            con.disconnect();

                                           

                                    }

                             }catch(Exception e) {

                                    System.out.println("다운로드 예외:" + e.getMessage());

                                    e.printStackTrace();

                             }

                      }

               };

               th.start();

              

               //스레드 동작 쉬는 시간이 생기면 동작

               System.out.println("스레드와 상관없는 코드");

       }

}

 

 

**XML Parsing

=>RSS(Really Simple Syndication,Rich Site Summary): 빠른 속도로 변경되는 데이터를 제공하기 위한 서비스로 예전에는 xml 을 많이 사용

=>xml: 태그 형식으로 표현하는 데이터 포맷

xml으 해석은 xml상단에 dtd가 있으면 dtd가 하고 없으면 개발자가 해석

=>html은 브라우저가 해석하기 때문에 우리가 원하는 내용만 고라서 보는게 안되고 출력을 직접 하게 되면 화면 크기에 따라 원하는 모양으로 볼 수가 없습니다.

데이터를 제공해서 보고자 하는 쪽에서 원하는 것만 골라서 원하는 크기로 볼 수 있도록 해줍니다.

 

 

1.xml Parsing

=>DOM(Documnet Object Model) Parser 이용

내용을 메모리에 트리 형태로 전부 펼쳐 놓고 원하는 데이터를 찾아가는 방식

 

DocumentBuilderFactory factory  = DocumentBuilderFactory.newInstance();

DocumentBuilder bulder = factory.newDocumentBuilder():

Document document = builder.parse(String uri);

//uri 대신에 inputStream inputStream, FIle file을 대입해도 됩니다.

//Dom의 형태로 메모리에 펼칩니다.

 

//루트 찾기

Element root = document.getDocumentElement();

 

//원하는 태그 찾아오기

NodeList list = root.getElementsByTagName(String tag);

s->전체 가져오기 s없으면 하나 가져오기

//위에서 찾은 list를 가지고 반복문을 수행

int n = list.getLength();

for (int i = 0; i< n ; i++){

           Node item = list.item(i);

           Node text = item.getFirstChild();

           text.getNodeValue();//태그 안의 내용

}

 

 

 

=>http://hani.co.kr/arti/sports/sports_general/ :한겨래 스포츠 rss

위 주소에서 titlelink만 추출해서 출력

 

thread.sleep() 하면서 하면 된다.

기상층도 xml로 준다.

 

**java에서의 외부 라이브러리 사용

=>일반 java applicationjar(java압축파일)파일을 build path에 추가

=>java web applicationWEB-INF/lib 디렉토리에 jar파일을 복사

=>maver이나 gradle기반의 프로젝트는 설정 파일에 의존성을 설정

=>자바 라이브러리는 www.mvnrepository.com에서 다운로드 기능

 

 

 

 

**json parsing

1.JSON

=>자바 스크립트 객체 표현법으로 데이터를 표현

파이썬의 리스트와 DIC 표현법과도 동일

{"key":"value" ,"key":"value" ...}:객체

["data1","data2" ...]:배열

 

2.파싱을 할려면 외부 라이브러리 이용

1) www.mvnrepository.com에서 json을 검색

 

자바는 jar,war 은 자기가 풀수 있다.

python zip , tar은 자기가 풀수 있다.

 

2)다운로드한 파일을 프로젝트에 복사

 

3) 복사한 파일을 선택하고 마우스 오르쪽을 클릭해서 [Build Path]-[Add to Build Path]를 클릭

Build Path에 추가하면 실행할 때 이 파일에 있는 클래스 들을 jvm이 로드를 사용할 수 있도록 해줍니다.

 

3.파싱

1)JSONObject

=>객체를 가져올 때 사용하는 자료형

 

2)JSONArray

=>배열을 가져올 때 사용하는 자료형

 

3)파싱과정

문자열을 가지고 new JSONObject(String json)(중괄호)이나 new JSONArray(String json)(대괄호)을 호출해서 객체나 배열 생성

 

JSONObjectget자료형(String key):key 에 해당하는 데이터를 자료형으로 리턴

JSONArrayget자료형(int index): index에 해당하는 데이터를 자료형으로 리턴, 배열은 개수를 length메소드로 리턴

 

4) kakap open api사용

=>최근의 open api들은 인증키를 url에 포함시키지 않고 header에 포함시켜서 요청하도록 합니다.

=>developer.kakao.com에서 open api데이터 사용을 신청

developer.kakao.com여기에서 자기 아이디로 등록하기

 

네이티브 앱 키

REST API ->open api

JavaScript ->web

Admin

·       네이티브 앱 키: iOS, Android 앱 개발시 필요한 key

·       REST API : REST API 호출시 필요한 key

·       Javascript : Javascript 앱 개발시 필요한 key

·       Admin : Push, 앱관리 등 관리자 권한에서 필요한 key. 보안 유지 필수

 

 

자기가 어떤것으로 사용할 것인지 설정을 하셔야 합니다.

하루에 몇개 만큼 쓸 것인가?

 

도서 검색

"https://dapi.kakao.com/v3/search/book?target=title&query=검색할 도서명  

Header Authorization: KakaoAK kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk

                             (자신의 REST API 키 사용한다.)

 

 

 url은 받느시 인코딩을 해줘어야 합니다.

한글이 있으면 utf-8로 변환해서 대입해야 합니다.

java.net.Encode.encode(String str,String enctype);

java.net.Encode.encode("미움받을 용기","utf-8");

 

?뒤에 들어가는 데이터를 parameter라고 하는데 이름=&이름=..의 형태

파라미터는 순서가 없기 때문에 아무거나 먼저 입력해도 됩니다.

 

 

4.kakao 의 도서검색 api파싱

 

https://developers.kakao.com/docs/restapi/search#%EC%B1%85-%EA%B2%80%EC%83%89

참조해서 해야 한다.

 

json object ->meta

json array ->documents

 

utf-8 UTF8같다.

CP949 = MS949같다.

EUCKR euc-kr

 

 

public class KakaoOpenAPI {

       public static void main(String[] args) {

               //데이터를 다운로드 받는 부분

               String json = null;

               try {

                      //검색함 도서이름 거입력

                      System.out.print("검색함 도서명:");

                      Scanner sc = new Scanner(System.in);

                      String book = sc.nextLine();

                     

                      //book 한글로 입력할 있으므로 인코딩

                      book =URLEncoder.encode(book,"utf-8");

                      //다운 로드 받을 url생성

                      //항상 인코딩을 해야 한다. 아니면 조회가 안된다.

                      //입력 받는 것은 뒤에 하는것이 좋다.

                      URL url = new URL("https://dapi.kakao.com/v3/search/book?size=50&page=2&sort=latest&target=title&query="+book);

                     

                      //연결 객체 생성

                      HttpURLConnection con =(HttpURLConnection)url.openConnection();

                      //옵션 설정

                      con.setConnectTimeout(20000);

                      con.setUseCaches(false);

                     

                      con.addRequestProperty("Authorization", "자신의 REST API 키 사용한다");

                     

                      //문자열 읽어오기

                      BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));

                      StringBuilder sb = new StringBuilder();

                      while(true) {

                             String line = br.readLine();

                             if(line == null) {

                                    break;

                             }

                             sb.append(line+"\n");

                      }

                      //데이터를 문자열로 변환

                      json = sb.toString();

                     

                      br.close();

                      con.disconnect();

                      sc.close();

                     

                      //System.out.println(json);

               }catch (Exception e) {

                      System.out.println("다운로드 에러:" +e.getMessage());

                      e.printStackTrace();

               }

               //데이터를 파싱하는  부분

               if(json == null) {

                      System.out.println("읽어온 데이터가 없습니다.");

               }else {

                      //전체 문자열을 json 객체로 변환

                      JSONObject root = new JSONObject(json);

                      //System.out.println(root);

                      //meta 객체

                      JSONObject meta = root.getJSONObject("meta");

                      //System.out.println(meta);

                      //documents 배열

                      JSONArray documents = root.getJSONArray("documents");

                      //System.out.println(documnets);

                     

                      //배열의 데이터 개수 찾아오기

                      int len = documents.length();

                      for(int i = 0; i <len; i++) {

                             JSONObject document = documents.getJSONObject(i);

                             //System.out.println(documnet);

                             try {                       

                                    String title = document.getString("title");

                                    int price = document.getInt("price");

                                   

                                    //thumbnail

                                    String thumbnail = document.getString("thumbnail");

                                    //인코딩은 문자열을 메모리에 저장되는 코드로 변환하는 것이고

                                    //디코딩은 메모리에 저장된 코드를 원래의 문자열로 복원하는 것입니다.

                                    System.out.println(title+" : "+price+" "+URLDecoder.decode(thumbnail,"utf-8"));

                             }catch(Exception e) {}

                      }

               }

       }

}

 

 

**HTML 파싱

=>사이트에서 출력은 되어 있는데 Open API형태로 데이터를 제공하지 않는 경우 HTML을 읽어서 사용

twitteropen api있는 지 확인하고 없으면 html가져와서 해야 한다.

=>HTML가져올 때는 URL의 인코딩에 주의하고 읽어온 데이터의 인코딩에도 주의

읽어온 데이터나 싸이트 등 설정해야 한다.

=>읽어야 하는 데이터가 AJAX(비동기적으로 데이터 가져오는 기술)형태로 만들어져 있거나 로그인을 해야하는 경우 또는 자바스크립트 코드를 실행해야 하는 경우에는 selenium같은 라이브러리를 사용해야 합니다.

로그인을 해야 하는 경우도 있고 부모 경로로 가는 경우 도 잇다.

HTTPURL 스코롤 한 것은 나오지 않는다.

=>자바에서 HTML파싱에 많이 이용되는 라이버러리는 JSoup

 

 

tag :중복 될 수 있습니다. (여러개 가능하다.)

id :중복 될 수 없습니다. -개발자가 만든 것이라서 없는 태그도 있습니다.(없을 수 있다.)

class : 중복 될 수 있습니다.

xpath:중복 될 수 없습니다. -태그의 경로라서 개발자가 만드는 것이 아니고 브라우저가 위치를 찾는 개념

(이것은 무조건 있다.)

 

selector: dom객체를 선택하기 위한 문법

로그인은 xpath찾는 것이 좋다.chrom 검사할 경우 선태하실때 오른쪽 눌르시면 copy가보면 selector xpath가 있다.

xpath는 네이브 자동로그인 할 경우

 

 

 

 

반응형

'Study > Java' 카테고리의 다른 글

java-17  (0) 2020.10.10
java-16  (0) 2020.10.10
java-14  (0) 2020.10.04
java-13  (0) 2020.10.03
java-12  (0) 2020.10.02

+ Recent posts