티스토리 뷰
식품의약품안전처에서 제공하는 식품 영양성분 DB의 데이터를 사용합니다.
PHP로 OPEN-API를 XML형식으로 호출하고 MySQL를 통해 저장합니다.
식품 영양성분 DB
식품의약품안전처에서 제공하는 공공데이터로 약 90,000여개의 식품들의 영양성분을 조회할 수 있습니다. 식품안전나라 사이트 내에서 API 키를 발급받아 등록 후 사용할 수 있습니다.
제공되는 영양성분은 1회 제공량당 탄수화물, 단백질, 지방, 당류, 나트륨, 콜레스테롤, 포화지방산, 트랜스지방입니다. 그외에도 칼로리와 어디서 언제 조사되었는지 등의 출처를 명시하고 있습니다.
1 | NUM | 번호 |
2 | FOOD_CD | 식품코드 |
3 | SAMPLING_REGION_NAME | 지역명 |
4 | SAMPLING_MONTH_NAME | 채취월 |
5 | SAMPLING_REGION_CD | 지역코드 |
6 | SAMPLING_MONTH_CD | 채취월코드 |
7 | GROUP_NAME | 식품군 |
8 | DESC_KOR | 식품이름 |
9 | RESEARCH_YEAR | 조사년도 |
10 | MAKER_NAME | 제조사명 |
11 | SUB_REF_NAME | 자료출처 |
12 | SERVING_SIZE | 총내용량 |
13 | NUTR_CONT1 | 열량(kcal)(1회제공량당) |
14 | NUTR_CONT2 | 탄수화물(g)(1회제공량당) |
15 | NUTR_CONT3 | 단백질(g)(1회제공량당) |
16 | NUTR_CONT4 | 지방(g)(1회제공량당) |
17 | NUTR_CONT5 | 당류(g)(1회제공량당) |
18 | NUTR_CONT6 | 나트륨(mg)(1회제공량당) |
19 | NUTR_CONT7 | 콜레스테롤(mg)(1회제공량당) |
20 | NUTR_CONT8 | 포화지방산(g)(1회제공량당) |
21 | NUTR_CONT9 | 트랜스지방(g)(1회제공량당) |
요청 주소의 기본적인 형식은 다음과 같습니다. 발급 받은 인증키를 입력하고 서비스명은 I2790입니다. 같은 API 키로 동시에 한 번만 요청할 수 있으며 한 번에 최대 1000건의 데이터를 조회할 수 있습니다. 추가적인 요청인자나 설명은 위 홈페이지를 참고하시면 됩니다.
요청주소 | URL | http://openapi.foodsafetykorea.go.kr/api/keyId/serviceId/dataType/startIdx/endIdx |
http://openapi.foodsafetykorea.go.kr/api/인증키/서비스명/요청파일타입/요청시작위치/요청종료위치 | ||
샘플 | http://openapi.foodsafetykorea.go.kr/api/sample/I2790/xml/1/5 | |
sample 이라는 인증키로 식품 영양성분 DB(I2790)를 XML 형식으로 0~4 까지 조회하겠습니다. |
MySQL
데이터를 저장하기 위한 데이터 베이스와 테이블을 생성합니다. 식품 영양성분 DB에서 제공하는 NUM 데이터는 사용하지 않고 id 라는 정수형의 새로운 열을 추가해 AUTO_INCREMENT 옵션을 설정한 뒤, 기본키로 사용하겠습니다.
CREATE DATABASE food;
use food;
CREATE TABLE food_data (
id INT(20) NOT NULL AUTO_INCREMENT,
food_cd VARCHAR(15),
sampling_region_name VARCHAR(20),
sampling_month_name VARCHAR(20),
sampling_region_cd VARCHAR(20),
sampling_month_cd VARCHAR(20),
group_name VARCHAR(30),
desc_kor VARCHAR(50),
research_year VARCHAR(5),
maker_name VARCHAR(50),
sub_ref_name VARCHAR(20),
serving_size VARCHAR(20),
nutr_cont1 VARCHAR(10),
nutr_cont2 VARCHAR(10),
nutr_cont3 VARCHAR(10),
nutr_cont4 VARCHAR(10),
nutr_cont5 VARCHAR(10),
nutr_cont6 VARCHAR(10),
nutr_cont7 VARCHAR(10),
nutr_cont8 VARCHAR(10),
nutr_cont9 VARCHAR(10),
PRIMARY KEY(id)
);
PHP 코드 작성하기
데이터 확인후 API키를 발급받고 MySQL 테이블을 생성하셨다면 PHP를 통해 데이터를 저장해 보겠습니다. 다음은 코드 전문입니다. 저장에 실패하면 오류 SQL 문장이 출력되며 잘 되었다면 빈화면이 나타납니다.
<?php
$conn = mysqli_connect(
'localhost',
'user',
'password',
'food');
$ch = curl_init();
$url = 'http://openapi.foodsafetykorea.go.kr/api';
$keyId = '/' . urlencode('key');
$serviceId = '/' . urlencode('I2790');
$dataType = '/' . urlencode('xml');
$startIdx = '/' . urlencode('1');
$endIdx = '/' . urlencode('900');
$Params = $url.$keyId.$serviceId.$dataType.$startIdx.$endIdx;
curl_setopt($ch, CURLOPT_URL, $Params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
echo "cURL Error #:" . $error;
} else {
$xml = simplexml_load_string($response);
foreach($xml->row as $row){
$sub_ref_name = addslashes($row->SUB_REF_NAME);
$sql = "
INSERT INTO food_data
(food_cd,
sampling_region_name,
sampling_month_name,
sampling_region_cd,
sampling_month_cd,
group_name,
desc_kor,
research_year,
maker_name,
sub_ref_name,
serving_size,
nutr_cont1,
nutr_cont2,
nutr_cont3,
nutr_cont4,
nutr_cont5,
nutr_cont6,
nutr_cont7,
nutr_cont8,
nutr_cont9)
VALUES(
'{$row->FOOD_CD}',
'{$row->SAMPLING_REGION_NAME}',
'{$row->SAMPLING_MONTH_NAME}',
'{$row->SAMPLING_REGION_CD}',
'{$row->SAMPLING_MONTH_CD}',
'{$row->GROUP_NAME}',
'{$row->DESC_KOR}',
'{$row->RESEARCH_YEAR}',
'{$row->MAKER_NAME}',
'{$sub_ref_name}',
'{$row->SERVING_SIZE}',
'{$row->NUTR_CONT1}',
'{$row->NUTR_CONT2}',
'{$row->NUTR_CONT3}',
'{$row->NUTR_CONT4}',
'{$row->NUTR_CONT5}',
'{$row->NUTR_CONT6}',
'{$row->NUTR_CONT7}',
'{$row->NUTR_CONT8}',
'{$row->NUTR_CONT9}')";
$result = mysqli_query($conn, $sql);
if($result === false){
echo '문제가 발생했습니다.';
echo mysqli_error($conn);
echo ($sql);
break;
}
}
}
?>
코드 분석
1. PHP와 MySQL 연결하기
PHP는 MySQL 서버에 연결할 수 있도록 드라이버를 제공하고 있습니다. 자세한 내용은 아래 첨부된 PHP 공식 홈페이지에서 확인 가능합니다.
이 글에서는 MySQLi(MySQL Improved Extension)를 사용해 서버에 접속해 보겠습니다. 지원하는 함수들 중 mysqli_connect를 이용하면 간단하게 데이터 베이스와 연결할 수 있습니다. user와 password에는 데이터베이스 사용자의 이름과 비밀번호를 database에는 사용할 데이터 베이스의 이름을 입력하면 됩니다.
<?php
$conn = mysqli_connect(
'localhost',
'user', // 사용자
'password', // 비밀번호
'food'); // 데이터베이스
?>
2. cURL로 API 호출하기
cURL을 통해 API 서버로 요청을 보내고 결과를 받아올 수 있습니다. PHP 또한 해당 기능을 라이브러리로 제공하고 있습니다. 먼저 curl_init 함수를 이용해 객체를 생성합니다.
<?php
$ch = curl_init();
?>
이어서 API 형식에 맞추어 주소 문자열을 생성합니다. (urlencode는 문자열을 url형식으로 바꾸어 주는 함수이다.)
http://openapi.foodsafetykorea.go.kr/api/인증키/서비스명/요청파일타입/요청시작위치/요청종료위치 |
<?php
$url = 'http://openapi.foodsafetykorea.go.kr/api';
$keyId = '/' . urlencode('key'); // 인증키
$serviceId = '/' . urlencode('I2790'); // 서비스명
$dataType = '/' . urlencode('xml'); // 요청 파일 타입
$startIdx = '/' . urlencode('1'); // 요청시작위치
$endIdx = '/' . urlencode('900'); // 요청종료위치
$Params = $url.$keyId.$serviceId.$dataType.$startIdx.$endIdx; // 요청주소
?>
curl_setopt 함수를 이용해 url 요청시 여러 옵션을 지정할 수 있습니다. 생성된 curl 객체와 함께 옵션명과 파라미터들을 넣어주면 됩니다. 저는 생성한 문자열을 주소로 세팅하기 위해 CURLOPT_URL 옵션을 사용하였으며 결과는 문자열로 받아 오기 위해 CURLOPT_RETURNTRANSFER 옵션을 설정하였습니다. 이외의 다른 옵션들은 아래 링크를 참고하시면 됩니다.
<?php
curl_setopt($ch, CURLOPT_URL, $Params); // 요청 url 설정
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // 결과를 문자열로 반환
?>
이제 curl_exec 함수를 통해 서버로 데이터 요청을 보냅니다. 결과는 response 변수에 저장됩니다. 이때 에러가 발생하면 curl_error 함수를 통해 error 변수에 값이 할당됩니다.
<?php
$response = curl_exec($ch); // curl 실행
$error = curl_error($ch); // 에러 검출
curl_close($ch); // curl 종료
?>
에러가 발생하지 않았다면 simplexml_load_string 함수를 통해 받아온 xml 문자열을 파싱 합니다. 해당 함수를 실행하면 문자열로 받아온 XML문서가 구조화되어 SimpleXMLElement이라는 객체로 변환되는데 이를 이용해 각 태그의 데이터로 쉽게 접근할 수 있습니다.
<?php
if ($error) {
echo "cURL Error #:" . $error; // 에러 내용 출력
} else {
$xml = simplexml_load_string($response); // xml 파싱
// 각 row에 대해 반복
foreach($xml->row as $row){
...
}
?>
3. XML 파싱후 데이터 저장하기
식품영양성분 DB의 데이터는 아래와 같은 구조를 가집니다. 영양성분은 <row id =... > 태그에 저장되어있기 때문에 xml->row로 <row> 태그에 접근하였습니다. 요청마다 여러 개의 <row> 태그가 존재하기 때문에 foreach 문을 통해 요청 시 받아온 모든 <row>에 대해 데이터 베이스 삽입 문을 실행합니다. 다른 형식의 XML 문서들을 파싱 하고자 하실 때에도 출력 결과를 살펴보고 적절한 태그로 접근해 데이터를 추출하시면 됩니다.
row 태그에서 뽑아낸 여러 값들을 sql 문에 세팅하고 mysqli_query를 실행하면 끝입니다. 저장시에 오류가 발생하면 반복문은 종료됩니다. (addslashes 함수는 작은따옴표(')로 인해 발생하는 문자열 오류를 막기 위해 백슬래시(\)를 넣어주는 함수이다.)
<?php
foreach($xml->row as $row){
$sub_ref_name = addslashes($row->SUB_REF_NAME); // ' -> \'
$sql = "
INSERT INTO food_data
(food_cd,
sampling_region_name,
sampling_month_name,
sampling_region_cd,
sampling_month_cd,
group_name,
desc_kor,
research_year,
maker_name,
sub_ref_name,
serving_size,
nutr_cont1,
nutr_cont2,
nutr_cont3,
nutr_cont4,
nutr_cont5,
nutr_cont6,
nutr_cont7,
nutr_cont8,
nutr_cont9)
VALUES(
'{$row->FOOD_CD}',
'{$row->SAMPLING_REGION_NAME}',
'{$row->SAMPLING_MONTH_NAME}',
'{$row->SAMPLING_REGION_CD}',
'{$row->SAMPLING_MONTH_CD}',
'{$row->GROUP_NAME}',
'{$row->DESC_KOR}',
'{$row->RESEARCH_YEAR}',
'{$row->MAKER_NAME}',
'{$sub_ref_name}',
'{$row->SERVING_SIZE}',
'{$row->NUTR_CONT1}',
'{$row->NUTR_CONT2}',
'{$row->NUTR_CONT3}',
'{$row->NUTR_CONT4}',
'{$row->NUTR_CONT5}',
'{$row->NUTR_CONT6}',
'{$row->NUTR_CONT7}',
'{$row->NUTR_CONT8}',
'{$row->NUTR_CONT9}')";
$result = mysqli_query($conn, $sql);
if($result === false){
echo '문제가 발생했습니다.';
echo mysqli_error($conn);
echo ($sql);
break;
}
}
?>
감사합니다.
공부한 내용을 복습/기록하기 위해 작성한 글이므로 내용에 오류가 있을 수 있습니다.
'PHP' 카테고리의 다른 글
[PHP] PHP 시작하기 (0) | 2022.12.12 |
---|