2023.08.01 - [분류 전체보기] - 파이썬 OPEN API 가져오기

 

파이썬 OPEN API 가져오기

새로운 레시피를 추가하기 위해 식품의약품안전처에서 제공하는 공공데이터를 가져와야 한다. 1. 개인 KEY 받아오기 import json import requests API_KEY = '개인 KEY를 받아옴' URL = 'http://openapi.foodsafetykorea.

bpeach.tistory.com

 

위에서 가져온 OPEN API에서 RCP_PARTS_DTLS 부분 재료와 양 부분하여 정리하려고 한다.

 

1. 데이터 프레임을 딕셔너리로 변경

# 딕셔너리로 변경
data_dict = data.to_dict('records')
data_dict[:3]

 

위에 결과물을 보면 RCP_PARTS_DTLS 부분에 해당하는 것들이 정리 되지 않고 다양한 형태로 나와있다. 이부분을 먼저 정리하기 위해 정규 표현식를 사용하려고 한다. 

 

2. 정규 표현식을 사용하고 튜플로 추출

# 재료(양g), ... 이런 식으로 된 거 분류
def extract_ingredients(recipe):
    parts = recipe['RCP_PARTS_DTLS']
    
    # 정규 표현식을 사용하여 재료와 양 튜플로 추출
    # ([\w\s]+) : 재료 이름 그룹(알파벳과 숫자, 공백, + 패턴 한 번 이상 반복)
    # \( : 괄호 
    # ([\d\.]+[k]? : 재료 양 그룹(숫자.소숫점, k분자가 있을 경우 고려_kg)
    # g)\) : 'g' 다음 괄호 ) 
    ingredients = re.findall(r'([\w\s]+)\(([\d\.]+[k]?g)\)', str(parts))
    
    # 재료 이름 - 튜플의 첫번째요소(재료)에서 앞 뒤 공백 제거
    ingredient_names = [ingredient[0].strip() for ingredient in ingredients]
    # 재료 양 - 튜플의 두번째요소 양 저장
    ingredient_amount = [ingredient[1] for ingredient in ingredients]
    
    return ingredient_names, ingredient_amount

이 함수는 재료 중에서 재료명(양g) 형태로 저장된 것을 재료명과 양 따로 저장하기 위해 구현된 함수이다.

- finadall(pattern, text) : 은 문자열 내에 특정 패턴을 만족하는 모든 문자열 반환

- \w : 알파벳(문자) 또는 숫자

- \s : 공백

- + : 패턴 한 번 이상 반복

- \(  : 괄호

- \d\. : 숫자. (소수)

- k? : 'k' 있을 경우 k 출력

- g)\ : 'g' 다음 괄호

 

튜플로 저장된 ingredients를 반복 읽어서 앞 뒤 공백 제거한 ingredient[0]을 재료명에 저장

 

 

3. 정리된 레시피 제목과 정보 추출해서 받아온거 데이터 목록에 추가

def get_recipe_data(recipe_name, data_dict):
    for recipe in data_dict:
        if recipe['RCP_NM'] == recipe_name:
            ingredient_names, ingredient_amount = extract_ingredients(recipe)
            
            # 딕셔너리로 구성하여 정리된 데이터 목록에 추가
            recipe_data = {
                'menu': recipe['RCP_NM'],
                'rcp': ingredient_names,
                'amount': ingredient_amount,
                'eng': recipe['INFO_ENG'],
                'car': recipe['INFO_CAR'],
                'pro': recipe['INFO_PRO'],
                'fat': recipe['INFO_FAT']
            }
            
            return recipe_data
    
    # 정규 표현식으로 한 거 중에 없으면 None
    return None

레시피명과 data 딕셔너리 정보를 받아와 RCP_NM와 레시피명이 같으면 위 언급한 함수에서 반환된 재료명과 재료양을  저장한다. 데이터를 딕셔너리로 구성하여 정리된 데이터 목록에 추가

 

food_name = []
result = []

# 제목만 추출
for i in data_dict:
    name = i.get('RCP_NM')
    food_name.append(name)
    
for recipe_name in food_name :
    # 정리된 레시피 제목과 정보 추출
    result_data = get_recipe_data(recipe_name, data_dict)
    result.append(result_data)
    
print(result[:3])

 

 

4. 정규 표현식 사용

cleaned_data  = []

for item in data_dict:
    parts_details = item['RCP_PARTS_DTLS']
    dish_name = item['RCP_NM']

    # 정규 표현식을 사용하여 재료와 양 추출
    # \b\w+ : 단어 앞뒤 지정으로 단어 의미
    # \b\s\d+ : 단어앞뒤 지정하고 공백과 한 개 이상 숫자
    # g(?:\(\d/\d\))? : g 포함해서 숫자/숫자와 형식 가능
    ingredients_info = re.findall(r'\b\w+\b\s\d+g(?:\(\d/\d\))?', str(parts_details))
    ingredient_name_list = []
    amount_list = []
    
    #print(ingredients_info) 
    # 재료와 양 추출해서 재료와 양 리스트에 넣기
    for ingredient_info in ingredients_info:
        # 단어 앞뒤+ 경계
        ingredient_name, amount = re.findall(r'\b\w+\b', ingredient_info)[:2]
        ingredient_name_list.append(ingredient_name+ ' ')
        amount_list.append(amount+ ' ')
        #print(ingredient_info)
        
    # 영양 정보 추출
    eng_info = item['INFO_ENG']
    car_info = item['INFO_CAR']
    pro_info = item['INFO_PRO']
    fat_info = item['INFO_FAT']

    # 딕셔너리로 구성하여 정리된 데이터 목록에 추가
    dish_dict = {
        'menu': dish_name,
        'rcp': ingredient_name_list,
        'amount' : amount_list,
        'eng': eng_info,
        'car': car_info,
        'pro': pro_info,
        'fat': fat_info
    }
    cleaned_data.append(dish_dict)

칵테일새우 20g(5마리) 처럼 저장된 데이터들을 분류하기 위해 정규 표현식 사용!

 

 

5. 나온 딕셔너리 결과 2개 합치기

total_data = cleanded_data + result
total_data[:3]

 

 

6. [] 빈칸으로 나온 데이터 채우기

merged_data = {}

for num in total_data : 
	menu_name = num['menu']
    
    # menu_name에 merged_data의 키가 존재하지 않으면
    if menu_name not in merged_data:
    	# merged 데이터 추가
        merged_data[menu_name] = {'menu' : menu_name, 'rcp' : [], 'amount' : [], 'eng' : num['eng'], 'car' : num['car'], 'pro' : num['pro'], 'fat' : num['fat']}
        
    # 키가 존재하면 리스트에 재료, 양 추가 
    merged_data[menu_name]['rcp'].extend(num['rcp'])
    merged_dtat[menu_name]['amount'].extend(num['amount']
    
    # 앞에 '재료'라는 단어가 들어가 있으면 제거
    merged_data[menu_name]['rcp'] = [item.replace('재료 ', '') for item in merged_data[menu_name]['rcp']]
    
# merged_data에 저장된 값만 추출
merged_list = list(merged_data.values())

 

 

7. 재료명에서 끝에 오는 해당 단어를 가지고 카테고리별 분류

for item in data_dict:
    menu_name = item['menu'].strip() # 공백 제거
    last_word = menu_name.split()[-1] # 단어 하나씩 구분해서 마지막 문자만 
    
    if last_word.endswith('찜'): #찜으로 끝나는지
        item['category'] = '찜류'
    elif last_word == '소박이':
        item['category'] = '김치류'
    elif last_word.endswith('국') :
        item['category'] = '국 및 탕류'
    elif last_word.endswith('탕') :
        item['category'] = '국 및 탕류'
    elif last_word.endswith('찌개') :
        item['category'] = '찌개 및 전골류'
    elif last_word.endswith('전골') :
        item['category'] = '찌개 및 전골류'
    elif last_word.endswith('밥'):
        item['category'] = '밥류'
    elif last_word.endswith('샐러드'):
        item['category'] = '샐러드'
    elif last_word.endswith('죽'):
        item['category'] = '죽'
    # 메인메뉴에 돼지, 소고기, 닭, 오리가 있는지 확인하고 있으면 any() 에서 True 반환
    elif any(word in menu_name
             for word in ['돼지', '소고기', '닭', '오리']):
        item['category'] = '메인메뉴'
    else :
        item['category'] = '서브메뉴3'
        
print(data_dict[:5])

 

 

8. 리스트 형태로 출력된 값에서 [] 제거, 'g'도 제거

rcp_remove = result['rcp'].str.replace(pat = r'[^\w,]', repl=r'', regex=True)
g_remove = result['amount'].str.replace(pat = r'[^\w,]', repl=r'', regex=True)
result['rcp'] = rcp_remove
result['remove_g'] = g_remove
result['amount'] = result['remove_g'].str.replace('g', '')

result[['menu', 'rcp', 'amount', 'eng', 'car', 'pro', 'fat', 'category']].head()

rcp에서 [] 제거 ^는 반대를 뜻한다.

- pat : 찾고자 하는 정규 표현식

- repl : 대체할 문자 입력

- regex : 정규표현식인지 결정 True : 정규화, False : 문자열

+ Recent posts