2023.12.22
JSON(2)
API를 이용한다면
1) 내가 원하는 정보가 어디 있는지
2) 내가 원하는 정보를 요청하는 URL 체크
- 내가 요청할 수 있는 인자들을 바탕으로 직접 구현 → URL 완성
3) 만약 web에서 요청하고 받을 수 있다면 web에서 제대로 되는지 확인한다
4) 코드상 통신을 하기 위해서는 urllib, requests 등을 사용
5) 응답을 받아서 원하는 정보들을 추출하고 (나중에 버리더라도 최대한다 정리해서 받는걸 추천)
6) 추출한 데이터를 DataFrame 등의 형태로 잘 담어서
7) excel, csv, DB 등의 형태로 저장
실습: kobis에서 영화 데이터 불러오기
url2_p1 = 'http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieInfo.json'
key = ## key 입력
# 에러 발생시 에러 발생한 부분 따로 저장
error_moviecds= []
for i in movie_data.index:
# json 형태로 데이터 load
url2 = url2_p1 + "?key=" + key + "&movieCd=" + i
temp_res = urllib.request.urlopen(url2)
temp_data = json.loads(temp_res.read().decode("utf-8"))
if "movieInfoResult" in temp_data:
# 확인한 위치에 정보가 있을 경우 해당 정보를 불러온다.
## 영화 정보에서 배우에 대한 정보가 있을 경우 불러오는 코드:
if temp_data['movieInfoResult']['movieInfo']['actors'] != []:
movie_data.at[i,'ActNum'] = len(temp_data['movieInfoResult']['movieInfo']['actors'])
movie_data.at[i,'Actname'] = temp_data['movieInfoResult']['movieInfo']['actors'][0]['peopleNm']
movie_data.at[i,'ActCast'] = temp_data['movieInfoResult']['movieInfo']['actors'][0]['cast']
else:
movie_data.at[i,'ActNum'] = '없음!'
movie_data.at[i,'Actname'] = '없음!'
movie_data.at[i,'ActCast'] = '없음!'
else:
# 만약 에러가 발생했다면 발생한 영화에 대한 정보를 출력하고 따로 저장
print("Error Moive:", i)
error_moviecds.append(i)
print(error_moviecds)
# 에러가 발생한 부분을 다시 불러오기를 시도하려면 아래와 같이 코드 추가
for i in error_moviecds:
url = url_base +"?key="+ key + "&movieCd="+i
temp_res = urllib.request.urlopen( url )
temp_data = json.loads(temp_res.read().decode("utf-8"))
if "movieInfoResult" in temp_data:
if temp_data['movieInfoResult']['movieInfo']['actors'] != []:
movie_data.at[i,'ActNum'] = len(temp_data['movieInfoResult']['movieInfo']['actors'])
movie_data.at[i,'Actname'] = temp_data['movieInfoResult']['movieInfo']['actors'][0]['peopleNm']
movie_data.at[i,'ActCast'] = temp_data['movieInfoResult']['movieInfo']['actors'][0]['cast']
else:
movie_data.at[i,'ActNum'] = '없음!'
movie_data.at[i,'Actname'] = '없음!'
movie_data.at[i,'ActCast'] = '없음!'
else:
print("Error Moive:", i)
request 모듈 사용해보기
import requests
import pandas as pd
import json
# 1) 메뉴얼상 내가 필요한 api 내용의 base url
base_url = 'http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.json'
# 2) 실제 요청하는 파라미터들을 dict로 표현하고 설정 함
# api 메뉴얼상 요청인터페이스의 인자 : key(문자열)
# 요청 인자에 대해 요청하고자 하는 값 : value(문자, 숫자)
my_parmas = {
'key': # 키 값 입력
"itemPerPage":40 # 한 번에 몇개의 데이터를 받아올건지
}
# 3) 실제로 요청하기
res = requests.get(base_url, params=my_parmas)
# 4) 여기서 간단히 가능
if ires.ok:
result = res.json()
else:
print("Response Error!")
result
# 참고) dict 관련 병합에 대해서
d1 = {"A":1234, "B":5678}
d2 = {"B":9999, "C":9876}
# 딕셔너리 2개 새로 병합하기 : 기존 키가 있다면 갱신, 없다면 추가
{**d1, **d2}
# 1) *args: def sumrandom(*args): 리스트
# 2) **args: def sumrandom(**args): 딕셔너리
XML
API에 XML양식으로 요청하고 받아서 처리하기
# 양식 ) XML
# <태그> 값 </태그>
# <openDt/> 값이 없을 때 == <openDt></openDt>
# 데이터처리
import pandas as pd
# 통신
import urllib.request
# xml/html tag 중심의 언어들을 편하게 추출할 때
from bs4 import BeautifulSoup
# STEP1) xml양식으로 영화 목록 40개 요청
base_url = "http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.xml"
key = # key값 입력
req_url = "40"
url3 = base_url + "?key=" + key + "&itemPerPage=" + req_url
url3
# STEP2) 위에서 완성한 주소를 통신으로 요청 & BS변환
res = urllib.request.urlopen(url3)
#xml 같은 양식을 사용할 때는 BeautifulSoup을 사용한다.
#parser "html.parser", "largeXML" 등 특수 용도에 맞는 parser가 있음
# 받은 응답을 어떤 추출(parser)기로 추출할것인지
# 일반적인 웹이나 간단한 xml등은 html.parser를 사용하면 됨
# - 자세한 것들은 용도에 맞는 메뉴얼 검색
soup = BeautifulSoup(res, "html.parser")
print(soup.prettify())
find와 find_all 메서드 활용
#find: 전체 태그 중에서 내가 요청한 태그하고 일치하는 가장 먼저 1개
#find_all: 전체 태그 중에서 내가 요청한 태그와 일치하는 모든 것을 리턴 ->리스트
soup.find("movie")
soup.find_all("movie")[0]
활용예시
# 처음 영화에 대해 코드값 출력
soup.find_all("moviecd")[0] # 비추 -> 중간에 데이터 밀릴 수도 있음
soup.find_all("movie")[0].find("moviecd") #find와 find_all 은 태그를 달고 있음
# 참고) 태그 제거 후 값만 추출하는 방법
#방법1 )
soup.find_all("movie")[0].find("moviecd").text
#방법2 )
soup.find_all("movie")[0].find("moviecd").get_text()
#참고2)
soup.find_all("movie")[0].find_all("moviecd").text <- 리스트엔 해당 방식이 없어서 안됨
soup.find_all("movie")[0].find_all("moviecd")[0].get_text()/.text <- 올바른 방법
#방법3 )
soup.movie.moviecd.text
# 받은 영화 정보는 몇 개?
len(soup.find_all("movie"))
# 요청해서 받은 영화 모든 것들에 대해 영화별 정보 출력
idx = 0
tot_cnt = len(soup.find_all("movie"))
for i in range(tot_cnt):
i_movie = soup.find_all("movie")[idx]
i_movie.find("moviecd").text
i_movie.find("movienm").text
i_movie.find("movienmen").text
i_movie.find("opendt").text
if i_movie.find_all("peoplenm") != []:
print(i_movie.find("peoplenm").text)
else:
print("감독정보 X")
웹사이트에서 정보 가져오기
내가 원하는 정보가 API 형태가 아니라 일반적인 웹사이트에 있다면
실습 : Dart에 있는 공시 정보 가져오기
# 필요한 패키지들
import requests # 1) 통신: urllib, requests etc
from bs4 import BeautifulSoup # 2) html -> tag 중심 언어, html파싱을 위한 패키징 : beautifulSoup
import pandas as pd # 3) 데이터 처리
import re # 4) 필요한 데이터 처리 -> 정규식
import time # 짧은 시간에 여러번 요청은 블락당할 수 있으니 시간지연을 해줘야함
# Step1 ) 내가 요청하고자 하는 url을 직접 찾아야함
# 브라우저의 개발자 도구 -> 네트워크 쪽을 참조해서 짐작
date = "2023.12.18" # selectDate 파라미터에 사용예정
page = '1' # currentPage
url = "https://dart.fss.or.kr/dsac001/mainAll.do?selectDate={date}&sort=&series=&mdayCnt=0¤tPage={page}"
# Step2) requests패키지로 요청
res = requests.get(url)
res # 출력 결과 : <response [200]> => ok 사인
#위의 요청한 웹페이지이의 정보를 tag중심으로 찾으려고 하니
#BeautifulSoup: html의 태그 중심으로 값들을 추출하자
soup = BeautifulSoup(res.text, "html.parser")
soup
필요지식
1) 정규식에서 특정 패턴 문자 찾기: re.findall(패턴, 어디서..) => 찾아주는 역할
2) 정규식에서 특정 패턴 문자를 수정(혹은 제거) : re.sub(패턴, 변경, 어디서) => 변경/ 제거
temp = soup.find_all("div",{"class":"pageInfo"})[0].text
# Try1) 찾을 패턴: 숫자들 + 건(찾을)
temp= re.findall(r"\d+건",temp)[0]
temp= re.sub(r"건","",temp)
temp
# 페이지 계산
int(temp) // 100
# Try2) 바로 페이지수를 추출
temp = re.findall(r"/\d+\]", temp)[0]
temp = re.sub(r"\/|\]","",temp)
temp
필요한 정보들을 추출하는 샘플 체크
# 0. 1개 공시 정보에 대한 tr 테그 찾기
len(soup.find_all("tr"))
# --> 정확하게 필요한 공시 정보들이 tbody에 담겨있고,
# 개별 공시들은 tr
# ===> 모든 tr 오세요가 아니라!!
# tbody안에 있는 tr만 다 오세요1!!
len(soup.find("tbody").find_all("tr"))
# 1번 공시의 정보가....
soup.find("tbody").find_all("tr")[0]
# 1. 1번 회사의 공시 제출 시간을 출력
temp = soup.find("tbody").find_all("tr")[0]
temp.find_all("td")[0].text
#참고) 문자열의 공백문자들처리: strip()
t_str = temp.find_all("td")[0].text.strip()
#참고) 문자열의 중간 공백들은 제거를 어떻게 할까? = 정규식활용
re.sub(r"\r | \n | \t | \s","",t_str)
# 2. 1번 공시를 제출한 회사가 속한 시장을 출력
# 예) 코스닥시장, 코넥스시장 등(fullname으로 출력)
temp.find_all("td")[1].find("a").text.strip()
# 3. 1번 공시를 제출한 회사의 이름을 출력
temp.find_all("td")[1].find_all("span")[1].get("title")
# 4. 1번 공시를 제출한 회사의 코드값을 출력
re.findall(r"[0-9]{8}",temp.find_all("td")[1].find("a").get("href"))
# 5. 1번 공시의 제목 출력
t_str = temp.find_all("td")[2].find("a").text
re.sub(r"\r|\n|\t","",t_str)
# 6. 1번 공시의 rcpNo : 공시코드값을 출력 --> 4번
re.findall(r"[0-9]{14}",temp.find_all("td")[2].find("a").get("href"))
# 7. 1번 공시를 접수한 날짜.
temp.find_all("td")[4].text
for문 활용해서 반복문 만들기
tot_cnt = len(soup.find("tbody").find_all("tr"))
for idx in range(tot_cnt):
temp = soup.find("tbody").find_all("tr")[idx]
print(temp.find_all("td")[0].text.strip())
print(temp.find_all("td")[1].find("a").text.strip())
print(temp.find_all("td")[1].find_all("span")[1].get("title"))
print(re.findall(r"[0-9]{8}",temp.find_all("td")[1].find("a").get("href"))[0])
print(re.sub(r"\r|\n|\t","",temp.find_all("td")[2].find("a").text))
print(re.findall(r"[0-9]{14}",temp.find_all("td")[2].find("a").get("href"))[0])
print(temp.find_all("td")[4].text)
'ASAC 빅데이터전문가과정 > Python' 카테고리의 다른 글
ASAC 20일차 _ WebCrawling(4), Pandas(5) (0) | 2024.08.05 |
---|---|
ASAC 19일차 _ WebCrawling(3) : 웹사이트(2), Selenium(1) (0) | 2024.08.01 |
ASAC 17일차 _ 파이썬(Python) Numpy/Pandas 4일차, WebCrawling(1) : Json(1) (6) | 2024.07.24 |
ASAC 16일차 _ 파이썬(Python) Numpy/Pandas 3일차 (0) | 2024.07.08 |
ASAC 15일차 _ 파이썬(Python) Numpy/Pandas 2일차 (0) | 2024.07.03 |