#### LikeLion 8th hackathon 출품 예정작 '공아역'에 사용
- 사용자의 검색에 맞는 문화재 이미지 및 정보 출력을 위함
import requests
search_name = '숭례문'
url_list = 'http://www.cha.go.kr/cha/SearchKindOpenapiList.do?pageUnit=30&ccbaMnm1=' + search_name
html = requests.get(url_list)
- requests를 사용하여 api 호출
- 문화재청 api는 별도의 key가 존재하지 않음
- ccbaMnm1은 문화재의 이름, 예를 들기 위하여 '숭례문'으로 설정 이름을 기준으로 문화재 검색을 위함
- pageUnit은 한 페이지에 보여줄 문화재의 수, 30으로 설정 검색 결과에 해당하는 모든 문화재를 보여주기 위해 api를 여러번 호출하는 방법 대신 적당히 보여준 후 사용자의 자세한 검색 유도
sp_html = html.text.split('<sn>')
- 호출한 값(html 형식)을 순번 태그인
<sn>
을 기준으로split
함
# 딕셔너리들이 들어갈 리스트
searched_list = []
for heritage in sp_html:
# split된 값들을 bs를 사용하여 parsing
temp_html = BeautifulSoup(heritage, 'html.parser')
# 태그들이 없는 html 선언부분등을 예외처리
try:
# 빈 딕셔너리 생성
temp_dict = {}
# 각 정보에 해당하는 key와 value 넣어줌
temp_dict['문화재명1'] = temp_html.ccbamnm1.text
temp_dict['문화재명2'] = temp_html.ccbamnm2.text
temp_dict['위치_도'] = temp_html.ccbactcdnm.text
temp_dict['위치_시'] = temp_html.ccsiname.text
temp_dict['종목코드'] = temp_html.ccbakdcd.text
temp_dict['시도코드'] = temp_html.ccbactcd.text
temp_dict['지정번호'] = temp_html.ccbaasno.text
searched_list.append(temp_dict)
except:
pass
- split된 html 내용을 기준으로 for문 수행
- 각 값들을
BeautifulSoup
을 사용하여parsing
- 필요한 내용의 이름과 값을 각 딕셔너리의 key와 value로 저장한 후
searched_list
에 추가 sp_html
에 head 태그와 같이 필요한 태그들이 존재하지 않은 요소들이 있기 때문에try
,except
를 사용하여 예외처리
for heritage in sp_html:
temp_html = BeautifulSoup(heritage, 'html.parser')
try:
temp_dict = {}
temp_dict['문화재명1'] = temp_html.ccbamnm1.text
temp_dict['문화재명2'] = temp_html.ccbamnm2.text
temp_dict['위치_도'] = temp_html.ccbactcdnm.text
temp_dict['위치_시'] = temp_html.ccsiname.text
temp_kbcd = temp_html.ccbakdcd.text
temp_dict['종목코드'] = temp_kbcd
temp_ctcd = temp_html.ccbactcd.text
temp_dict['시도코드'] = temp_ctcd
temp_anno = temp_html.ccbaasno.text
temp_dict['지정번호'] = temp_anno
temp_require = 'ccbaKdcd=' + temp_kbcd + '&ccbaCtcd=' + temp_ctcd + '&ccbaAsno=' + temp_anno
# img_url = 'http://www.cha.go.kr/cha/SearchImageOpenapi.do?' + temp_require
# img = requests.get(img_url)
# sp_img = img.text.split('<sn>')
# parsed_img = BeautifulSoup(sp_img[1], 'html.parser')
# temp_dict['이미지'] = parsed_img.imageurl.text
detail_url = 'http://www.cha.go.kr/cha/SearchKindOpenapiDt.do?' + temp_require
detail = requests.get(detail_url)
parsed_detail = BeautifulSoup(detail.text, 'html.parser')
temp_dict['이미지'] = parsed_detail.imageurl.text
temp_dict['내용'] = parsed_detail.content.text
searched_list.append(temp_dict)
except:
pass
- 문화재 이미지 검색 api와 문화재 상세정보 api를 둘 다 호출하지 않고 문화재 상세정보에 있는 대표 이미지를 사용
- 상세정보 검색에 필요한 종목, 지정, 시도 코드를 변수로 지정 > url 요첨에 필요한 문자열을 변수로 지정
- 문화재 검색과 같이 requests, BeautifulSoup를 사용
- 문화재 리스트에 존재하는 문화재 마다 api를 호출하여 시간이 오래걸리는 이슈가 있음, 어떻게 해결해야 될까?
- 문화재청 API에 총 15935개의 정보가 있음 > 검색마다 API를 호출하는 건 상당히 비효율 적이라고 생각 > 개발 환경에서 model에 저장 후 필요한 정보를 불러오는 방법을 사용해야겠음 > 장고 프로젝트에서 모델을 만들어야 함 > 기존 슬라이싱 및 파싱한 것을 토대로 모델에 저장 > 15000여개의 데이터를 모델에 저장하면서 경과치를 볼 수 있을까?
- 장고 모델에 15000여개의 데이터를 저장 > 검색은
filter
을 이용하여 구현할 예정
- 모델 저장 페이지에서 api를 호출하여 저장하는 방법 대신, 로컬에서 api에서 필요한 정보를 뺀 파일을 만들어 그것을 이용하여 저장하는 방법을 사용할 예정
f = open("heritage.txt", 'a')
... 중략
for i in searched_list:
for key, value in i.items():
txt_data = key + ':' + value
f.write(txt_data)
f.close()
- 파일 입출력을 이용하여 key와 value를 :로 나누어 저장, 이제 15000여개의 모델을 저장하면서 진행상황을 어떻게 볼지 고민중
url_list = 'http://www.cha.go.kr/cha/SearchKindOpenapiList.do?pageUnit=15944'
- api에서 가져올 요소의 수를 api에 존재하는 모든 문화재 수인 19544로 설정
progress = 1
for heritage in sp_html:
temp_html = BeautifulSoup(heritage, 'html.parser')
try:
temp_dict = {}
temp_dict['문화재명1'] = temp_html.ccbamnm1.text
... 중략
print('현재 진행상황 : ', progress)
progress += 1
except:
pass
- 반복문에 출력문을 넣어 경과정도를 확인할 수 있게 함
f.write(str(searched_list))
- 딕셔너리 자료형들로 이루어진 리스트를 문자열화하여 파일에 입력
progress = 1
for heritage in sp_html:
temp_html = BeautifulSoup(heritage, 'html.parser')
try:
temp_dict = {}
... 중략
print(str(temp_dict))
f.write(str(temp_dict)+'\n')
print('현재 진행상황 : ', progress)
progress += 1
except:
pass
- 반복문에 출력문과 더불어 파일.write를 줄바꿈과 같이 저장하는 방식으로 바꿈
heritage.txt
파일을 장고 프로젝트에 넣기 전 확인 용으로txt_reader.py
를 생성
heritage_txt = open("heritage.txt", 'r')
- 읽기 전용으로 파일 open
for _ in range(5):
line = heritage_txt.readline()
heritage_list.append(eval(line))
# [{문화재1 정보}, {문화재2 정보}, ...]
- eval을 이용하여 문자열로 저장된 딕셔너리들을 새로운 리스트에 추가
heritage_list = []
i = 0
while True:
line = heritage_txt.readline()
if not line: break
heritage_list.append(eval(line))
i += 1
if i % 100 == 0: print(i, "/ 19544")
print(heritage_list[0]['문화재명1'])
# 서울 숭례문
print('총 문화재 수 : ', len(heritage_list))
# 총 문화재 수 : 15944
heritage_txt.close()
- 무한 반복문을 이용하여 파일 끝까지 readline하여 append
- Django 프로젝트에서 기존에 저장한 .txt 파일을 이용하여 Model Heritage에 저장
if len(Heritage.objects.all()) > 10:
pass
- Heritage Model의 갯수가 10개 이하일 때만 txt 파일을 읽고 모델에 저장되도록 함
else:
module_dir = os.path.dirname(__file__)
file_path = os.path.join(module_dir, '/Users/ohyeseong/Documents/django/dino_history/dino_history/heritage/heritage.txt')
heritage_txt = open(file_path, 'r')
while True:
line = heritage_txt.readline()
if not line: break
this_heritage = eval(line)
temp_heritage = Heritage()
temp_heritage.name = this_heritage['문화재명1']
temp_heritage.location = this_heritage['위치_도'] + this_heritage['위치_시']
temp_heritage.dynasty = this_heritage['시대']
temp_heritage.img_url = this_heritage['이미지']
temp_heritage.content = this_heritage['내용']
temp_heritage.longitude = this_heritage['경도']
temp_heritage.latitude = this_heritage['위도']
temp_heritage.save()
return render(request, 'heritage/save_test.html')
- 기존
txt_reader.py
와 다르게 매 line마다 Heritage model을 생성 및 딕셔너리를 이용하여 저장