오뚝이개발자

[사이드 프로젝트] 만개의 레시피 크롤링(한식 정보 크롤링) 본문

사이드 프로젝트

[사이드 프로젝트] 만개의 레시피 크롤링(한식 정보 크롤링)

땅어 2023. 6. 3. 16:22
728x90
300x250

 

학교 수업의 프로젝트 일환으로 외국인들에게 한식을 소개하는 어플을 제작했다. 해당 프로젝트에서 내가 담당했던 부분은 데이터 파트를 구축하는 일이었는데, 이를 위해 만개의 레시피를 크롤링하는 부분을 구현하였다.

 

식약처 API(첫번째 시도)


처음엔 식약처에 제공하는 API를 사용하였다. 해당 링크는 아래와 같다.

http://www.foodsafetykorea.go.kr/api/openApiInfo.do?menu_grp=MENU_GRP31&menu_no=661&show_cnt=10&start_idx=1&svc_no=COOKRCP01

 

데이터활용서비스

설명 속성정보 일련번호 , 메뉴명 , 조리방법 , 요리종류 , 중량(1인분) , 열량 , 탄수화물 , 단백질 , 지방 , 나트륨 , 해쉬태그 , 이미지경로(소) , 이미지경로(대) , 재료정보 , 만드는법_01 , 만드는

www.foodsafetykorea.go.kr

위 링크에 접속해보면 아래와 같은 URL 요청 방식이랑 요청 인자들에 대한 설명이 나온다. 

식약처 한식 API 요청주소 및 인자

위 API를 통해 요청하면 아래와 같은 정보들을 얻을 수 있다. 더 많으 정보들에 대한 설명은 위 링크를 통해 확인할 수 있다.

식약처 한식 API 출력항목

그런데 생각보다 식약처에서 제공하는 API에서 커버하는 한식의 종류가 다양하지 않았다. 따라서, 다른 방법을 찾아보았다. 좀 더 많은 종류의 한식 정보를 제공할 수 있는 방법으로 나는 만개의 레시피라는 한식 검색 사이트를 크롤링하여 데이터를 구축하였다.

 

만개의 레시피 크롤링


만개의 레시피는 사용자들이 레시피를 등록할 수 있는 레시피 검색 사이트이다. 여러 종류의 음식들을 다루고 있고, 확실히 식약처 API보다 많은 종류의 한식들에 대한 정보를 담고 있다.

만개의 레시피 메인 페이지

 

What to select?


다음으로 봉착한 문제는 어떤 음식을 선택해서 유저에게 보여줄 것인지였다. 가령, 김치찌개라고 하면, 참치김치찌개, 묵은지 김치찌개, 돼지고기 김치찌개와 같이 들어가는 재료에 따라 여러 종류가 있다. 이 중 우리는 가장 보편적이고 대중적인 음식을 선택해 해당 음식의 레시피와 재료들을 보여주기로 하였다. 이를 위해, "김치찌개"라고 검색하였을 때, 추천순으로 정렬한 뒤 가장 상단의 가장 첫번째 메뉴를 크롤링하였다.

음식 선정

 

What to crawl?


다음으로는 어떠한 정보들을 크롤링할 것인지를 선택하여야 하는데, 특정 음식을 클릭하면 아래와 같이 재료와 레시피에 대한 정보를 제공한다.

재료 설명
레시피 설명

우리는 재료와 레시피, 두가지 정보를 크롤링해 유저에게 보여주기로 하였다.

 

크롤링 구현


import requests, json
from bs4 import BeautifulSoup

def food_info(name):
    '''
    This function gives you food information for the given input.

    PARAMETERS
        - name(str): name of Korean food in Korean ex) food_info("김치찌개")
    RETURN
        - res(list): list of dict that containing info for some Korean food related to 'name'
            - res['name'](str): name of food
            - res['ingredients'](str): ingredients to make the food
            - res['recipe'](list[str]): contain recipe in order
    '''
    url = f"https://www.10000recipe.com/recipe/list.html?q={name}"
    response = requests.get(url)
    if response.status_code == 200:
        html = response.text
        soup = BeautifulSoup(html, 'html.parser')
    else : 
        print("HTTP response error :", response.status_code)
        return
    
    food_list = soup.find_all(attrs={'class':'common_sp_link'})
    food_id = food_list[0]['href'].split('/')[-1]
    new_url = f'https://www.10000recipe.com/recipe/{food_id}'
    new_response = requests.get(new_url)
    if new_response.status_code == 200:
        html = new_response.text
        soup = BeautifulSoup(html, 'html.parser')
    else : 
        print("HTTP response error :", response.status_code)
        return
    
    food_info = soup.find(attrs={'type':'application/ld+json'})
    result = json.loads(food_info.text)
    ingredient = ','.join(result['recipeIngredient'])
    recipe = [result['recipeInstructions'][i]['text'] for i in range(len(result['recipeInstructions']))]
    for i in range(len(recipe)):
        recipe[i] = f'{i+1}. ' + recipe[i]
    
    res = {
        'name': name,
        'ingredients': ingredient,
        'recipe': recipe
    }

    return res

위 코드는 인자로 음식명을 넘겨주었을 때, 해당 음식에 대한 정보들을 return해주는 함수이다. 구체적으로는 음식명, 재료, 레시피의 세가지 정보를 딕셔너리 타입으로 return해준다. 크롤링은 beautifulsoup 라이브러리를 통해 구현하였다.(해당 라이브러리는 pip install bs4 커맨드로 다운로드할 수 있다.) 함수에 대한 자세한 설명은 코드 내의 주석에 자세히 기록해두었으니 참고하길 바란다.

 

크롤링 결과


위 함수를 통해 "김치찌개"라는 음식에 대한 정보를 추출하면 아래와 같은 결과가 나온다.

크롤링 결과 예시

 

 

 

728x90
300x250
Comments