구글 앱스크립트(스프레드시트) 활용하여_학술논문 검색_자동화하기

소개

시도하고자 했던 것과 그 이유 👍

스프레드 시트에 논문 검색한 내용을 정리하는 과정에서 시간 절약과 노동력을 줄이기 위해
자동화하는 방법을 모색하게 됨

진행 방법

어떤 도구를 사용 : 구글 스프레드시트, 앱스크립트, 클로드, riss API Key

어떻게 활용하셨나요?

  1. 구글 스프레드 시트에서 새 파일을 하나 열고,

  2. 확장프로그램인 앱스크립트 실행 후

  3. 클로드 AI에게 앱스크립트를 자동화할 수 있는 코드를 만들어달라고 요구함.

  4. 앱스크립트 창에서 내용을 지우고 클로드가 준 코드를 복붙함

  5. riss.kr 사이트에 가서 API Key 신청하여 가져와야 함

  6. 저장, 실행 버튼 누르고 진행

클로드 프롬프트 :

너는 구글 앱스크립트의 전문가야/구글 스프레드 시트에 특정 주제를 검색하면 국내학술논문 정보를 받는 학술논문 분석 앱스크립트를 만들고 싶어

Tip: 클로드 AI 활용 내용

네, 국내 학술논문 정보를 검색하고 스프레드시트에 가져오는 앱스크립트를 만들어드리겠습니다. 국내 학술논문 데이터베이스는 주로 RISS(학술연구정보서비스), DBpia, KISS(한국학술정보) 등이 있습니다. 이 중 RISS는 API를 제공하므로 이를 활용하겠습니다.

```javascript
// RISS OpenAPI 키 설정
var API_KEY = '여기에_RISS_API_키를_입력하세요';

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('학술논문 검색')
      .addItem('국내 학술논문 검색', 'showSearchPrompt')
      .addToUi();
}

function showSearchPrompt() {
  var ui = SpreadsheetApp.getUi();
  var response = ui.prompt(
    '국내 학술논문 검색',
    '검색어를 입력하세요:',
    ui.ButtonSet.OK_CANCEL
  );

  if (response.getSelectedButton() == ui.Button.OK) {
    var searchQuery = response.getResponseText();
    searchAcademicPapers(searchQuery);
  }
}

function searchAcademicPapers(searchQuery) {
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // 시트 초기화
  sheet.clear();
  
  // 헤더 설정
  sheet.getRange('A1:I1').setValues([['논문 제목', '저자', '학술지명', '발행년도', '권호정보', '페이지', '초록', '키워드', '링크']]);
  sheet.getRange('A1:I1').setFontWeight('bold');
  
  try {
    // RISS API URL
    var searchUrl = 'http://api.riss.kr/search/search.do?' +
                   'apiKey=' + API_KEY +
                   '&query=' + encodeURIComponent(searchQuery) +
                   '&target=ARTICLE' +
                   '&start=1' +
                   '&sortby=date' +
                   '&displaycount=50' +
                   '&output=json';
    
    var options = {
      'muteHttpExceptions': true,
      'headers': {
        'Accept': 'application/json',
      }
    };
    
    var response = UrlFetchApp.fetch(searchUrl, options);
    var content = response.getContentText();
    var results = JSON.parse(content);
    
    if (!results.RESULT || !results.RESULT.items || results.RESULT.items.length === 0) {
      sheet.getRange('A2').setValue('검색 결과가 없습니다.');
      return;
    }
    
    var data = [];
    
    for (var i = 0; i < results.RESULT.items.length; i++) {
      var item = results.RESULT.items[i];
      
      // 논문 제목에서 HTML 태그 제거
      var title = item.title ? item.title.replace(/<\/?[^>]+(>|$)/g, "") : "제목 없음";
      
      // 저자 정보 처리
      var authors = item.author ? item.author.replace(/<\/?[^>]+(>|$)/g, "") : "저자 정보 없음";
      
      // 학술지 정보 처리
      var journal = item.journal ? item.journal.replace(/<\/?[^>]+(>|$)/g, "") : "학술지 정보 없음";
      
      // 발행년도
      var year = item.pubYear || "발행년도 정보 없음";
      
      // 권호정보
      var volume = item.volume || "";
      var issue = item.issue || "";
      var volumeIssue = volume + (issue ? "(" + issue + ")" : "");
      
      // 페이지
      var page = item.page || "페이지 정보 없음";
      
      // 초록
      var abstract = item.abstractDesc ? item.abstractDesc.replace(/<\/?[^>]+(>|$)/g, "") : "초록 정보 없음";
      
      // 키워드
      var keywords = item.keyword ? item.keyword.replace(/<\/?[^>]+(>|$)/g, "") : "키워드 정보 없음";
      
      // 링크
      var link = item.link_url || "링크 정보 없음";
      
      data.push([
        title,
        authors,
        journal,
        year,
        volumeIssue,
        page,
        abstract,
        keywords,
        link
      ]);
    }
    
    // 데이터 입력
    if (data.length > 0) {
      sheet.getRange(2, 1, data.length, 9).setValues(data);
      
      // 칼럼 너비 자동 조정
      sheet.autoResizeColumns(1, 9);
      
      // 초록 열 너비 제한
      sheet.setColumnWidth(7, 300);
      
      // 링크를 클릭 가능하게 만들기
      for (var i = 0; i < data.length; i++) {
        if (data[i][8] && data[i][8] != "링크 정보 없음") {
          var formula = '=HYPERLINK("' + data[i][8] + '", "논문 보기")';
          sheet.getRange(i + 2, 9).setFormula(formula);
        }
      }
    }
    
    // 정렬 설정 (발행년도 기준 내림차순)
    sheet.getRange(2, 1, data.length, 9).sort({column: 4, ascending: false});
    
  } catch (e) {
    Logger.log('오류 발생: ' + e.toString());
    SpreadsheetApp.getUi().alert('오류가 발생했습니다: ' + e.toString() + 
                                 '\n\nRISS API 키를 확인하시고, 올바른 API 키를 입력해주세요.');
  }
}

// 검색어로 학술지 정보만 검색하는 함수
function searchJournals(searchQuery) {
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // 시트 초기화
  sheet.clear();
  
  // 헤더 설정
  sheet.getRange('A1:F1').setValues([['학술지명', '발행기관', '등재정보', '발행주기', '주제분류', '링크']]);
  sheet.getRange('A1:F1').setFontWeight('bold');
  
  try {
    // RISS API URL (학술지 검색)
    var searchUrl = 'http://api.riss.kr/search/search.do?' +
                   'apiKey=' + API_KEY +
                   '&query=' + encodeURIComponent(searchQuery) +
                   '&target=JOURNAL' +
                   '&start=1' +
                   '&sortby=title' +
                   '&displaycount=50' +
                   '&output=json';
    
    var options = {
      'muteHttpExceptions': true,
      'headers': {
        'Accept': 'application/json',
      }
    };
    
    var response = UrlFetchApp.fetch(searchUrl, options);
    var content = response.getContentText();
    var results = JSON.parse(content);
    
    if (!results.RESULT || !results.RESULT.items || results.RESULT.items.length === 0) {
      sheet.getRange('A2').setValue('검색 결과가 없습니다.');
      return;
    }
    
    var data = [];
    
    for (var i = 0; i < results.RESULT.items.length; i++) {
      var item = results.RESULT.items[i];
      
      // 학술지 정보 처리
      var title = item.title ? item.title.replace(/<\/?[^>]+(>|$)/g, "") : "제목 없음";
      var publisher = item.publisher || "발행기관 정보 없음";
      var regist = item.regist || "등재정보 없음";
      var frequency = item.frequency || "발행주기 정보 없음";
      var category = item.category || "주제분류 정보 없음";
      var link = item.link_url || "링크 정보 없음";
      
      data.push([
        title,
        publisher,
        regist,
        frequency,
        category,
        link
      ]);
    }
    
    // 데이터 입력
    if (data.length > 0) {
      sheet.getRange(2, 1, data.length, 6).setValues(data);
      
      // 칼럼 너비 자동 조정
      sheet.autoResizeColumns(1, 6);
      
      // 링크를 클릭 가능하게 만들기
      for (var i = 0; i < data.length; i++) {
        if (data[i][5] && data[i][5] != "링크 정보 없음") {
          var formula = '=HYPERLINK("' + data[i][5] + '", "학술지 보기")';
          sheet.getRange(i + 2, 6).setFormula(formula);
        }
      }
    }
    
  } catch (e) {
    Logger.log('오류 발생: ' + e.toString());
    SpreadsheetApp.getUi().alert('오류가 발생했습니다: ' + e.toString());
  }
}

```

이 앱스크립트는 RISS(학술연구정보서비스) OpenAPI를 사용하여 국내 학술논문을 검색하고 결과를 스프레드시트에 표시합니다. 주요 기능은 다음과 같습니다:

1. 검색 기능:
   - 스프레드시트 메뉴에 '학술논문 검색' 옵션 추가
   - 검색어 입력 프롬프트 제공
   - 최대 50개의 검색 결과 표시

2. 수집하는 정보:
   - 논문 제목
   - 저자
   - 학술지명
   - 발행년도
   - 권호정보
   - 페이지
   - 초록
   - 키워드
   - 클릭 가능한 논문 링크

3. 데이터 정리:
   - 자동 칼럼 너비 조정
   - 발행년도 기준 내림차순 정렬
   - HTML 태그 제거 기능
   - 클릭 가능한 링크 형식

사용 방법:
1. RISS OpenAPI 키 발급 받기 (https://www.riss.kr/openapi/index.do에서 신청)
2. 스크립트 편집기에서 `API_KEY` 변수에 발급받은 키 입력
3. 스프레드시트 새로고침 후 '학술논문 검색' 메뉴 사용

주의사항:
- RISS OpenAPI 키가 필요합니다.
- 일일 검색 한도가 있을 수 있습니다.
- 검색 응답이 느릴 수 있습니다.

이 스크립트를 사용하시면 국내 학술논문을 쉽게 검색하고 스프레드시트에서 관리할 수 있습니다. 필요한 경우 다른 학술 데이터베이스(DBpia, KISS 등)도 추가하도록 수정할 수 있습니다.

코드 전문 : (코드_클로드 생성)

// RISS OpenAPI 키 설정
var API_KEY = '여기에_RISS_API_키를_입력하세요';

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('학술논문 검색')
      .addItem('국내 학술논문 검색', 'showSearchPrompt')
      .addToUi();
}

function showSearchPrompt() {
  var ui = SpreadsheetApp.getUi();
  var response = ui.prompt(
    '국내 학술논문 검색',
    '검색어를 입력하세요:',
    ui.ButtonSet.OK_CANCEL
  );

  if (response.getSelectedButton() == ui.Button.OK) {
    var searchQuery = response.getResponseText();
    searchAcademicPapers(searchQuery);
  }
}

function searchAcademicPapers(searchQuery) {
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // 시트 초기화
  sheet.clear();
  
  // 헤더 설정
  sheet.getRange('A1:I1').setValues([['논문 제목', '저자', '학술지명', '발행년도', '권호정보', '페이지', '초록', '키워드', '링크']]);
  sheet.getRange('A1:I1').setFontWeight('bold');
  
  try {
    // RISS API URL
    var searchUrl = 'http://api.riss.kr/search/search.do?' +
                   'apiKey=' + API_KEY +
                   '&query=' + encodeURIComponent(searchQuery) +
                   '&target=ARTICLE' +
                   '&start=1' +
                   '&sortby=date' +
                   '&displaycount=50' +
                   '&output=json';
    
    var options = {
      'muteHttpExceptions': true,
      'headers': {
        'Accept': 'application/json',
      }
    };
    
    var response = UrlFetchApp.fetch(searchUrl, options);
    var content = response.getContentText();
    var results = JSON.parse(content);
    
    if (!results.RESULT || !results.RESULT.items || results.RESULT.items.length === 0) {
      sheet.getRange('A2').setValue('검색 결과가 없습니다.');
      return;
    }
    
    var data = [];
    
    for (var i = 0; i < results.RESULT.items.length; i++) {
      var item = results.RESULT.items[i];
      
      // 논문 제목에서 HTML 태그 제거
      var title = item.title ? item.title.replace(/<\/?[^>]+(>|$)/g, "") : "제목 없음";
      
      // 저자 정보 처리
      var authors = item.author ? item.author.replace(/<\/?[^>]+(>|$)/g, "") : "저자 정보 없음";
      
      // 학술지 정보 처리
      var journal = item.journal ? item.journal.replace(/<\/?[^>]+(>|$)/g, "") : "학술지 정보 없음";
      
      // 발행년도
      var year = item.pubYear || "발행년도 정보 없음";
      
      // 권호정보
      var volume = item.volume || "";
      var issue = item.issue || "";
      var volumeIssue = volume + (issue ? "(" + issue + ")" : "");
      
      // 페이지
      var page = item.page || "페이지 정보 없음";
      
      // 초록
      var abstract = item.abstractDesc ? item.abstractDesc.replace(/<\/?[^>]+(>|$)/g, "") : "초록 정보 없음";
      
      // 키워드
      var keywords = item.keyword ? item.keyword.replace(/<\/?[^>]+(>|$)/g, "") : "키워드 정보 없음";
      
      // 링크
      var link = item.link_url || "링크 정보 없음";
      
      data.push([
        title,
        authors,
        journal,
        year,
        volumeIssue,
        page,
        abstract,
        keywords,
        link
      ]);
    }
    
    // 데이터 입력
    if (data.length > 0) {
      sheet.getRange(2, 1, data.length, 9).setValues(data);
      
      // 칼럼 너비 자동 조정
      sheet.autoResizeColumns(1, 9);
      
      // 초록 열 너비 제한
      sheet.setColumnWidth(7, 300);
      
      // 링크를 클릭 가능하게 만들기
      for (var i = 0; i < data.length; i++) {
        if (data[i][8] && data[i][8] != "링크 정보 없음") {
          var formula = '=HYPERLINK("' + data[i][8] + '", "논문 보기")';
          sheet.getRange(i + 2, 9).setFormula(formula);
        }
      }
    }
    
    // 정렬 설정 (발행년도 기준 내림차순)
    sheet.getRange(2, 1, data.length, 9).sort({column: 4, ascending: false});
    
  } catch (e) {
    Logger.log('오류 발생: ' + e.toString());
    SpreadsheetApp.getUi().alert('오류가 발생했습니다: ' + e.toString() + 
                                 '\n\nRISS API 키를 확인하시고, 올바른 API 키를 입력해주세요.');
  }
}

// 검색어로 학술지 정보만 검색하는 함수
function searchJournals(searchQuery) {
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // 시트 초기화
  sheet.clear();
  
  // 헤더 설정
  sheet.getRange('A1:F1').setValues([['학술지명', '발행기관', '등재정보', '발행주기', '주제분류', '링크']]);
  sheet.getRange('A1:F1').setFontWeight('bold');
  
  try {
    // RISS API URL (학술지 검색)
    var searchUrl = 'http://api.riss.kr/search/search.do?' +
                   'apiKey=' + API_KEY +
                   '&query=' + encodeURIComponent(searchQuery) +
                   '&target=JOURNAL' +
                   '&start=1' +
                   '&sortby=title' +
                   '&displaycount=50' +
                   '&output=json';
    
    var options = {
      'muteHttpExceptions': true,
      'headers': {
        'Accept': 'application/json',
      }
    };
    
    var response = UrlFetchApp.fetch(searchUrl, options);
    var content = response.getContentText();
    var results = JSON.parse(content);
    
    if (!results.RESULT || !results.RESULT.items || results.RESULT.items.length === 0) {
      sheet.getRange('A2').setValue('검색 결과가 없습니다.');
      return;
    }
    
    var data = [];
    
    for (var i = 0; i < results.RESULT.items.length; i++) {
      var item = results.RESULT.items[i];
      
      // 학술지 정보 처리
      var title = item.title ? item.title.replace(/<\/?[^>]+(>|$)/g, "") : "제목 없음";
      var publisher = item.publisher || "발행기관 정보 없음";
      var regist = item.regist || "등재정보 없음";
      var frequency = item.frequency || "발행주기 정보 없음";
      var category = item.category || "주제분류 정보 없음";
      var link = item.link_url || "링크 정보 없음";
      
      data.push([
        title,
        publisher,
        regist,
        frequency,
        category,
        link
      ]);
    }
    
    // 데이터 입력
    if (data.length > 0) {
      sheet.getRange(2, 1, data.length, 6).setValues(data);
      
      // 칼럼 너비 자동 조정
      sheet.autoResizeColumns(1, 6);
      
      // 링크를 클릭 가능하게 만들기
      for (var i = 0; i < data.length; i++) {
        if (data[i][5] && data[i][5] != "링크 정보 없음") {
          var formula = '=HYPERLINK("' + data[i][5] + '", "학술지 보기")';
          sheet.getRange(i + 2, 6).setFormula(formula);
        }
      }
    }
    
  } catch (e) {
    Logger.log('오류 발생: ' + e.toString());
    SpreadsheetApp.getUi().alert('오류가 발생했습니다: ' + e.toString());
  }
}

결과와 배운 점

Tip : riss API Key 오늘 신청했어요.
메일이 오면 실행을 해보고
이번주 토요일 오프 미팅 때 제대로 보여드리겠습니다.

3
7개의 답글

👉 이 게시글도 읽어보세요