상세 컨텐츠

본문 제목

블로그 자동화 : 단일 페이지 웹앱 만들기 위한 가이드

IT/블로그 자동화

by 심장과영혼 2023. 2. 15. 00:00

본문

728x90
반응형

블로그 작성의 새로운 세상이 열릴 것 같습니다. 

 


단일 페이지 웹앱 만들기

 
 

Bing 뉴스 검색 API를 사용하면 웹을 검색하고 검색 쿼리와 관련된 뉴스 유형의 결과를 얻을 수 있습니다. 이 자습서에서는 Bing 뉴스 검색 API를 사용하여 페이지에 검색 결과를 표시하는 단일 페이지 웹 응용 프로그램을 빌드합니다. 응용 프로그램에는 HTML, CSS 및 자바 스크립트 구성 요소가 포함되어 있습니다. 이 샘플의 소스 코드는 GitHub에서 사용할 수 있습니다.

 참고

클릭하면 페이지 하단의 JSON 및 HTTP 제목에 JSON 응답 및 HTTP 요청 정보가 표시됩니다. 이러한 세부 정보는 서비스를 탐색할 때 유용할 수 있습니다.

자습서 앱은 다음 방법을 보여 줍니다.

  • 자바 스크립트에서 Bing 뉴스 검색 API 호출을 수행 합니다.
  • 검색 옵션을 Bing 뉴스 검색 API에 전달합니다.
  • 뉴스 검색 결과를 모든 유형, 비즈니스, 건강 또는 정치의 네 가지 범주에서 24시간, 지난 주, 월 또는 사용 가능한 모든 시간부터 표시합니다.
  • 검색결과 페이지를 넘깁니다.
  • Bing 클라이언트 ID 및 API 구독 키를 처리합니다.
  • 발생할 수 있는 오류를 처리합니다.

튜토리얼 페이지는 완전히 독립적입니다. 외부 프레임워크, 스타일시트 또는 이미지 파일을 사용하지 않습니다. 널리 지원되는 JavaScript 언어 기능만 사용하며 모든 주요 웹 브라우저의 현재 버전에서 작동합니다.

 

필수 구성 요소

자습서를 따라 하려면 Bing 검색 API에 대한 구독 키가 필요합니다. 이러한 항목이 없는 경우 만들어야 합니다.

 

앱 구성 요소

다른 단일 페이지 웹 응용 프로그램과 마찬가지로 이 자습서 응용 프로그램에는 다음 세 부분이 포함됩니다.

  • HTML - 페이지의 구조와 내용을 정의합니다.
  • CSS - 페이지의 모양을 정의합니다.
  • 자바 스크립트 - 페이지의 동작을 정의합니다.

대부분의 HTML과 CSS는 일반적이므로 튜토리얼에서는 이에 대해 논의하지 않습니다. HTML에는 사용자가 쿼리를 입력하고 검색 옵션을 선택하는 검색 양식이 포함되어 있습니다. 양식은 태그의 속성을 사용하여 실제로 검색을 수행하는 JavaScript에 연결됩니다.onsubmit<form>

.HTML복사
<form name="bing" onsubmit="return newBingNewsSearch(this)">

처리기는 폼이 서버로 전송되지 않도록 하는 를 반환합니다. JavaScript 코드는 양식에서 필요한 정보를 수집하고 검색을 수행하는 작업을 수행합니다.onsubmitfalse

HTML에는 검색 결과가 표시되는 부서(HTML 태그)도 포함되어 있습니다.<div>

 

구독 키 관리

코드에 Bing Search API 구독 키를 포함할 필요가 없도록 브라우저의 영구 저장소를 사용하여 키를 저장합니다. 키가 저장되기 전에 사용자의 키를 묻는 메시지가 표시됩니다. 나중에 API에서 키를 거부하면 저장된 키가 무효화되어 사용자에게 다시 메시지가 표시됩니다.

우리는 객체 (모든 브라우저가 지원하는 것은 아님) 또는 쿠키를 사용하는 함수를 정의합니다. 이 함수는 이러한 함수를 사용하여 사용자의 키를 저장하고 검색합니다.storeValueretrieveValuelocalStoragegetSubscriptionKey()

 
 
자바 스크립트
// Cookie names for data we store
API_KEY_COOKIE   = "bing-search-api-key";
CLIENT_ID_COOKIE = "bing-search-client-id";

// Bing Search API endpoint
BING_ENDPOINT = "https://api.bing.microsoft.com/v7.0/news";

// ... omitted definitions of storeValue() and retrieveValue()
// Browsers differ in their support for persistent storage by 
// local HTML files. See the source code for browser-specific
// options.

// Get stored API subscription key, or 
// prompt if it's not found.
function getSubscriptionKey() {
    var key = retrieveValue(API_KEY_COOKIE);
    while (key.length !== 32) {
        key = prompt("Enter Bing Search API subscription key:", "").trim();
    }
    // always set the cookie in order to update the expiration date
    storeValue(API_KEY_COOKIE, key);
    return key;
}

HTML 태그는 함수를 호출하여 검색 결과를 반환합니다. 각 쿼리를 인증하는 데 사용합니다. 이전 정의에 표시된 것처럼 키를 입력하지 않은 경우 사용자에게 키를 묻는 메시지를 표시합니다. 그런 다음 응용 프로그램에서 계속 사용할 수 있도록 키가 저장됩니다.<form>onsubmitbingWebSearchbingWebSearchgetSubscriptionKey()getSubscriptionKey

.HTML복사
<form name="bing" onsubmit="this.offset.value = 0; return bingWebSearch(this.query.value, 
    bingSearchOptions(this), getSubscriptionKey())">

검색 옵션 선택

다음 그림에서는 학교 기금에 대한 뉴스 검색을 정의하는 쿼리 텍스트 상자와 옵션을 보여 줍니다.

HTML 양식에는 다음과 같은 이름의 요소가 포함되어 있습니다.

요소묘사
where 검색에 사용되는 시장(위치 및 언어)을 선택하기 위한 드롭다운 메뉴입니다.
query 검색어를 입력할 텍스트 필드입니다.
category 특정 종류의 결과를 홍보하기 위한 확인란입니다. 예를 들어, 건강 증진은 건강 뉴스의 순위를 높입니다.
when 선택적으로 검색을 가장 최근의 일, 주 또는 월로 제한하기 위한 드롭다운 메뉴입니다.
safe Bing 세이프서치 기능을 사용하여 "성인" 결과를 필터링할지 여부를 나타내는 확인란입니다.
count 숨겨진 필드. 각 요청에 대해 반환할 검색 결과의 수입니다. 페이지당 더 적거나 더 많은 결과를 표시하려면 변경합니다.
offset 숨겨진 필드. 요청에서 첫 번째 검색 결과의 오프셋입니다. 페이징에 사용됩니다. 새 요청 시 다시 설정됩니다.0

 

참고

Bing 웹 검색은 다른 쿼리 매개 변수를 제공합니다. 우리는 그 중 몇 가지만 사용하고 있습니다.

 
자바 스크립트
// build query options from the HTML form
function bingSearchOptions(form) {

    var options = [];
    options.push("mkt=" + form.where.value);
    options.push("SafeSearch=" + (form.safe.checked ? "strict" : "off"));
    if (form.when.value.length) options.push("freshness=" + form.when.value);

    for (var i = 0; i < form.category.length; i++) {
        if (form.category[i].checked) {
            category = form.category[i].value;
            break;
        }
    }
    if (category.valueOf() != "all".valueOf()) { 
        options.push("category=" + category); 
        }
    options.push("count=" + form.count.value);
    options.push("offset=" + form.offset.value);
    return options.join("&");
}

예를 들어 실제 API 호출의 매개 변수는 , 또는 , 일 수 있으며 기본값은 입니다. 그러나 양식에서는 두 가지 상태만 있는 확인란을 사용합니다. 자바 스크립트 코드는이 설정을 또는 (사용되지 않음)로 변환합니다.SafeSearchstrictmoderateoffmoderatestrictoffmoderate

요청 수행

쿼리, 옵션 문자열 및 API 키가 지정된 경우 함수는 개체를 사용하여 Bing 뉴스 검색 끝점에 요청합니다.BingNewsSearchXMLHttpRequest

자바 스크립트
// perform a search given query, options string, and API key
function bingNewsSearch(query, options, key) {

    // scroll to top of window
    window.scrollTo(0, 0);
    if (!query.trim().length) return false;     // empty query, do nothing

    showDiv("noresults", "Working. Please wait.");
    hideDivs("results", "related", "_json", "_http", "paging1", "paging2", "error");

    var request = new XMLHttpRequest();
     if (category.valueOf() != "all".valueOf()) {
        var queryurl = BING_ENDPOINT + "/search?" + "?q=" + encodeURIComponent(query) + "&" + options;
    }
    else
    {
        if (query){
        var queryurl = BING_ENDPOINT + "?q=" + encodeURIComponent(query) + "&" + options;
        }
        else {
            var queryurl = BING_ENDPOINT + "?" + options;
        }
    }

    // open the request
    try {
        request.open("GET", queryurl);
    } 
    catch (e) {
        renderErrorMessage("Bad request (invalid URL)\n" + queryurl);
        return false;
    }

    // add request headers
    request.setRequestHeader("Ocp-Apim-Subscription-Key", key);
    request.setRequestHeader("Accept", "application/json");
    var clientid = retrieveValue(CLIENT_ID_COOKIE);
    if (clientid) request.setRequestHeader("X-MSEdge-ClientID", clientid);

    // event handler for successful response
    request.addEventListener("load", handleBingResponse);

    // event handler for erorrs
    request.addEventListener("error", function() {
        renderErrorMessage("Error completing request");
    });

    // event handler for aborted request
    request.addEventListener("abort", function() {
        renderErrorMessage("Request aborted");
    });

    // send the request
    request.send();
    return false;
}

HTTP 요청이 성공적으로 완료되면 자바스크립트는 이벤트 핸들러인 함수를 호출하여 API에 대한 성공적인 HTTP GET 요청을 처리합니다.loadhandleBingResponse()

 
자바 스크립트
// handle Bing search request results
function handleBingResponse() {
    hideDivs("noresults");

    var json = this.responseText.trim();
    var jsobj = {};

    // try to parse JSON results
    try {
        if (json.length) jsobj = JSON.parse(json);
    } catch(e) {
        renderErrorMessage("Invalid JSON response");
    }

    // show raw JSON and HTTP request
    showDiv("json", preFormat(JSON.stringify(jsobj, null, 2)));
    showDiv("http", preFormat("GET " + this.responseURL + "\n\nStatus: " + this.status + " " + 
        this.statusText + "\n" + this.getAllResponseHeaders()));

    // if HTTP response is 200 OK, try to render search results
    if (this.status === 200) {
        var clientid = this.getResponseHeader("X-MSEdge-ClientID");
        if (clientid) retrieveValue(CLIENT_ID_COOKIE, clientid);
        if (json.length) {
            if (jsobj._type === "News") {
                renderSearchResults(jsobj);
            } else {
                renderErrorMessage("No search results in JSON response");
            }
        } else {
            renderErrorMessage("Empty response (are you sending too many requests too quickly?)");
        }
    }

    // Any other HTTP response is an error
    else {
        // 401 is unauthorized; force re-prompt for API key for next request
        if (this.status === 401) invalidateSubscriptionKey();

        // some error responses don't have a top-level errors object, so gin one up
        var errors = jsobj.errors || [jsobj];
        var errmsg = [];

        // display HTTP status code
        errmsg.push("HTTP Status " + this.status + " " + this.statusText + "\n");

        // add all fields from all error responses
        for (var i = 0; i < errors.length; i++) {
            if (i) errmsg.push("\n");
            for (var k in errors[i]) errmsg.push(k + ": " + errors[i][k]);
        }

        // also display Bing Trace ID if it isn't blocked by CORS
        var traceid = this.getResponseHeader("BingAPIs-TraceId");
        if (traceid) errmsg.push("\nTrace ID " + traceid);

        // and display the error message
        renderErrorMessage(errmsg.join("\n"));
    }
}

 

중요

 

HTTP 요청이 성공했다고 해서 반드시 검색 자체가 성공한 것은 아닙니다. 검색 작업에서 오류가 발생하면 Bing 뉴스 검색 API는 200이 아닌 HTTP 상태 코드를 반환하고 JSON 응답에 오류 정보를 포함합니다. 또한 요청의 속도가 제한된 경우 API는 빈 응답을 반환합니다.

위의 두 함수에 있는 대부분의 코드는 오류 처리 전용입니다. 오류는 다음 단계에서 발생할 수 있습니다.

무대                                                           잠재적 오류                                                   처리자

 

자바스크립트 요청 객체 빌드하기 잘못된 URL try/catch 차단
요청하기 네트워크 오류, 중단된 연결 error 및 이벤트 처리기abort
검색 수행 잘못된 요청, 잘못된 JSON, 속도 제한 이벤트 처리기에서 테스트load

오류는 오류에 대해 알려진 세부 정보를 사용하여 호출하여 처리됩니다. 응답이 오류 테스트의 전체 건틀릿을 통과하면 페이지에 검색 결과를 표시하기 위해 호출합니다.renderErrorMessage()renderSearchResults()

검색 결과 표시

검색 결과를 표시하는 주요 기능은 입니다. 이 함수는 Bing 뉴스 검색 서비스에서 반환된 JSON을 가져와 뉴스 결과 및 관련 검색(있는 경우)을 렌더링합니다.renderSearchResults()

 
자바 스크립트
// render the search results given the parsed JSON response
    function renderSearchResults(results) {

    // add Prev / Next links with result count
    var pagingLinks = renderPagingLinks(results);
    showDiv("paging1", pagingLinks);
    showDiv("paging2", pagingLinks);

    showDiv("results", renderResults(results.value));
    if (results.relatedSearches)
        showDiv("sidebar", renderRelatedItems(results.relatedSearches));
}

기본 검색 결과는 JSON 응답에서 최상위 개체로 반환됩니다. 우리는 그것들을 우리의 함수에 전달하고, 함수는이를 반복하고 별도의 함수를 호출하여 각 항목을 HTML로 렌더링합니다. 결과 HTML은 로 반환되며, 여기서 페이지의 분할에 삽입됩니다.valuerenderResults()renderSearchResults()results

 
자바 스크립트
function renderResults(items) {
    var len = items.length;
    var html = [];
    if (!len) {
        showDiv("noresults", "No results.");
        hideDivs("paging1", "paging2");
        return "";
    }
    for (var i = 0; i < len; i++) {
        html.push(searchItemRenderers.news(items[i], i, len));
    }
    return html.join("\n\n");
}

 

Bing 뉴스 검색 API는 각각 고유한 최상위 개체에 있는 최대 4가지 종류의 관련 결과를 반환합니다. 

 

관련묘사
pivotSuggestions 원래 검색의 피벗 단어를 다른 단어로 바꾸는 쿼리입니다. 예를 들어 "빨간색 꽃"을 검색하는 경우 피벗 단어는 "빨간색"이고 피벗 제안은 "노란색 꽃"일 수 있습니다.
queryExpansions 더 많은 용어를 추가하여 원래 검색의 범위를 좁히는 쿼리입니다. 예를 들어 "Microsoft Surface"를 검색하는 경우 쿼리 확장은 "Microsoft Surface Pro"일 수 있습니다.
relatedSearches 원래 검색을 입력한 다른 사용자도 입력한 쿼리입니다. 예를 들어 "레이니어 산"을 검색하는 경우 관련 검색은 "세인트 헬렌스 산"일 수 있습니다.
similarTerms 원래 검색과 의미가 비슷한 쿼리입니다. 예를 들어 "학교"를 검색하는 경우 유사한 용어가 "교육"일 수 있습니다.

앞에서 볼 수 있듯이 제안만 렌더링하고 결과 링크를 페이지의 사이드바에 배치합니다.renderSearchResults()relatedItems

 

렌더링 결과 항목

JavaScript 코드에서 개체 인 에는 각 종류의 검색 결과에 대해 HTML을 생성하는 함수 인 렌더러가 포함되어 있습니다.searchItemRenderers

자바 스크립트
searchItemRenderers = {
    news: function(item) { ... },
    webPages: function (item) { ... }, 
    images: function(item, index, count) { ... },
    relatedSearches: function(item) { ... }
}

렌더러 함수는 다음 매개 변수를 사용할 수 있습니다.

매개 변수묘사
item URL 및 설명과 같은 항목의 속성을 포함하는 JavaScript 개체입니다.
index 컬렉션 내에 있는 결과 항목의 인덱스입니다.
count 검색 결과 항목의 컬렉션에 있는 항목 수입니다.

및 매개 변수를 사용하여 결과에 번호를 매기고, 컬렉션의 시작 또는 끝에 대한 특수 HTML을 생성하고, 특정 수의 항목 뒤에 줄 바꿈을 삽입하는 등의 작업을 수행할 수 있습니다. 렌더러에 이 기능이 필요하지 않은 경우 이 두 매개 변수를 허용할 필요가 없습니다.indexcount

렌더러는 다음 JavaScript 발췌문에 나와 있습니다.news

 
자바 스크립트
    // render news story
    news: function (item) {
        var html = [];
        html.push("<p class='news'>");
        if (item.image) {
            width = 60;
            height = Math.round(width * item.image.thumbnail.height / item.image.thumbnail.width);
            html.push("<img src='" + item.image.thumbnail.contentUrl +
                "&h=" + height + "&w=" + width + "' width=" + width + " height=" + height + ">");
        }
        html.push("<a href='" + item.url + "'>" + item.name + "</a>");
        if (item.category) html.push(" - " + item.category);
        if (item.contractualRules) {    // MUST display source attributions
            html.push(" (");
            var rules = [];
            for (var i = 0; i < item.contractualRules.length; i++)
                rules.push(item.contractualRules[i].text);
                html.push(rules.join(", "));
                html.push(")");
            }
        html.push(" (" + getHost(item.url) + ")");
        html.push("<br>" + item.description);
        return html.join("");
    },

뉴스 렌더러 함수:

  • 단락 태그를 만들어 클래스에 할당하고 html 배열에 푸시합니다.news
  • 이미지 축소판 크기를 계산합니다(너비는 60픽셀로 고정, 높이는 비례적으로 계산됨).
  • HTML 태그를 작성하여 이미지 축소판을 표시합니다.<img>
  • 이미지와 이미지가 포함된 페이지에 연결되는 HTML 태그를 작성합니다.<a>
  • 이미지 및 이미지가 있는 사이트에 대한 정보를 표시하는 설명을 작성합니다.

썸네일 크기는 태그와 썸네일 URL의 및 필드 모두에 사용됩니다. 그런 다음 Bing 미리 보기 서비스는 정확히 해당 크기의 미리 보기를 제공합니다.

 

클라이언트 ID 유지

Bing 검색 API의 응답에는 연속적인 요청과 함께 API로 다시 보내야 하는 헤더가 포함될 수 있습니다. 여러 Bing 검색 API를 사용하는 경우 가능하면 모든 API에 동일한 클라이언트 ID를 사용해야 합니다.X-MSEdge-ClientID

헤더를 제공하면 Bing API가 사용자의 모든 검색을 연결할 수 있으므로 두 가지 중요한 이점이 있습니다.X-MSEdge-ClientID

첫째, Bing 검색 엔진이 검색에 과거 컨텍스트를 적용하여 사용자를 더 만족시키는 결과를 찾을 수 있습니다. 예를 들어, 사용자가 이전에 항해와 관련된 용어를 검색한 적이 있는 경우, 나중에 "노트"를 검색하면 항해에 사용된 노트에 대한 정보가 우선적으로 반환될 수 있습니다.

둘째, Bing은 새로운 기능이 널리 보급되기 전에 경험할 사용자를 임의로 선택할 수 있습니다. 각 요청에 동일한 클라이언트 ID를 제공하면 기능을 보는 사용자가 항상 해당 기능을 볼 수 있습니다. 클라이언트 ID가 없으면 사용자는 검색 결과에서 무작위로 보이는 기능이 나타나고 사라질 수 있습니다.

브라우저 보안 정책(CORS)으로 인해 자바스크립트에서 헤더를 사용하지 못할 수 있습니다. 이 제한은 검색 응답의 출처가 요청한 페이지와 다른 경우에 발생합니다. 프로덕션 환경에서는 웹 페이지와 동일한 도메인에서 API 호출을 수행하는 서버 쪽 스크립트를 호스팅하여 이 정책을 해결해야 합니다. 스크립트의 출처가 웹 페이지와 동일하므로 JavaScript에서 헤더를 사용할 수 있습니다.X-MSEdge-ClientIDX-MSEdge-ClientID

 참고

프로덕션 웹 응용 프로그램에서는 서버 쪽에서 요청을 수행해야 합니다. 그렇지 않으면 Bing 검색 API 키가 소스를 보는 모든 사용자가 사용할 수 있는 웹 페이지에 포함되어야 합니다. 권한이 없는 당사자의 요청을 포함하여 API 구독 키에 따른 모든 사용량에 대해 요금이 청구되므로 키를 노출하지 않는 것이 중요합니다.

개발 목적으로 CORS 프록시를 통해 Bing 웹 검색 API 요청을 수행할 수 있습니다. 이러한 프록시의 응답에는 응답 헤더를 허용하고 JavaScript에서 사용할 수 있도록 하는 헤더가 있습니다.Access-Control-Expose-Headers

CORS 프록시를 설치하여 자습서 앱이 클라이언트 ID 헤더에 액세스할 수 있도록 하는 것은 쉽습니다. 먼저 아직 없는 경우 Node.js를 설치합니다. 그런 후 명령 창에서 다음 명령을 실행하십시오.

콘솔복사
npm install -g cors-proxy-server

그런 다음 HTML 파일에서 Bing 웹 검색 끝점을 다음으로 변경합니다.
http://localhost:9090/https://api.bing.microsoft.com/v7.0/search

마지막으로 다음 명령을 사용하여 CORS 프록시를 시작합니다.

 
콘솔
cors-proxy-server

튜토리얼 앱을 사용하는 동안 명령 창을 열어 두십시오. 창을 닫으면 프록시가 중지됩니다. 검색 결과 아래의 확장 가능한 HTTP 헤더 섹션에서 이제 헤더를 보고 각 요청에 대해 동일한지 확인할 수 있습니다.X-MSEdge-ClientID

다음 단계


  • 뉴스 검색 API에서 사용하는 쿼리 매개 변수 - Bing 서비스

    Bing 뉴스 검색 API 요청의 결과에 영향을 주는 데 사용할 수 있는 쿼리 매개 변수에 대해 설명합니다.

  • 빙 뉴스 검색 API 빠른 시작 - 빙 검색 서비스

    이러한 빠른 시작을 사용하여 몇 분 만에 첫 번째 뉴스 검색 API 호출을 수행할 수 있습니다.

  • 웹 검색 API 응답 구조 및 답변 유형 - Bing 검색 서비스

    Bing 웹 검색 API는 검색 결과를 포함하는 응답 본문에 SearchResponse 개체를 반환합니다.

  • 빙 웹 검색 API v7 응답 개체 - 빙 서비스

    Bing 웹 검색 API가 JSON 응답에서 반환할 수 있는 응답 개체에 대해 설명합니다.

  • 빙 웹 검색 API v7 참조 - 빙 서비스

    Bing 웹 검색 API의 프로그래밍 요소에 대해 설명합니다.

  • Bing 뉴스 검색 API를 사용하여 뉴스 검색 - Bing 검색 서비스

    일반 뉴스, 인기 주제 및 헤드라인에 대한 검색어를 보내는 방법을 알아보세요.

  • Bing 검색 API 제품군 - Bing 검색 서비스

    Bing 검색 API 제품군과 앱 및 서비스에서 인터넷 검색을 사용하도록 설정하는 방법에 대해 알아봅니다.

  • Bing 웹 검색 샘플 - Bing 검색 서비스

    Bing 웹 검색 샘플을 사용하여 Python, 노드.js, C# 또는 Java 응용 프로그램에 검색 기능을 추가하는 방법을 알아봅니다.

 
728x90
반응형

관련글 더보기