jQuery / meta 태그의 값 가져오기

jQuery로 meta 태그 값을 가져오려면 대상 태그를 선택한 뒤 .attr("content")를 호출합니다. 예를 들어 설명문은 $('head meta[name="description"]').attr("content")로 읽습니다. Open Graph의 og:title은 name 대신 property 속성으로 선택합니다.

name·property와 읽을 속성 구분하기

meta 요소는 문서의 부가 정보인 메타데이터를 제공합니다. name="description"에서 name은 정보의 종류, content는 그 값입니다. meta는 일반 문단처럼 내부 텍스트를 가진 요소가 아니므로 .text()나 폼 입력용 .val() 대신 .attr("content")를 사용합니다.

Open Graph는 공유용 정보를 property="og:title"처럼 표시합니다. name="og:title"을 찾으면 같은 문자열이라도 속성이 달라 일치하지 않습니다. charset 선언은 content가 아닌 charset 속성 자체를 읽습니다. 모든 meta에 content가 있다고 가정하지 말고 실제 HTML을 확인합니다.

선택자는 작은따옴표로 감싼 JavaScript 문자열 안에 큰따옴표로 속성값을 지정하면 읽기 쉽습니다. #이나 콜론을 별도로 조합하는 대신 예제처럼 완성된 고정 선택자를 사용합니다. 외부 입력으로 임의의 선택자를 만들 필요가 없는 작업입니다.

브라우저에서 실행하는 전체 예제

코드를 UTF-8의 meta-demo.html로 저장해 브라우저로 엽니다. 인터넷으로 공식 jQuery 파일 4.0.0을 읽습니다. 별도 서버나 설치는 필요하지 않습니다. Windows Edge에서 jQuery 3.7.1·4.0.0으로 조회, 중복, 변경 후 재조회와 초기화를 실행했습니다.

demo-empty와 demo-no-content는 빈 값과 누락된 속성의 차이를 관찰하려고 넣은 진단용 항목입니다. content가 없는 name 메타를 정상적인 게시용 작성 예로 삼지 않습니다. og:title 하나도 완전한 Open Graph 설정 전체를 뜻하지 않습니다.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Original page summary">
  <meta property="og:title" content="Meta demo">
  <meta name="demo-empty" content="">
  <meta name="demo-no-content">
  <title>Read meta attributes</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
    button { font: inherit; margin: 4px; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Read the current document's metadata</h1>
  <button type="button" id="read">Read current DOM</button>
  <button type="button" id="update">Update existing description</button>
  <button type="button" id="duplicate">Add duplicate</button>
  <button type="button" id="remove">Remove description</button>
  <button type="button" id="reset">Reset</button>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      function descriptions() { return $('head meta[name="description"]'); }
      function report() {
        const $description = descriptions(), allValues = [];
        $description.each(function () { allValues.push($(this).attr("content")); });
        const $absent = $('head meta[name="does-not-exist"]');
        $("#result").text([
          "description=" + String($description.attr("content")),
          "description count=" + $description.length,
          "all descriptions=" + JSON.stringify(allValues),
          "og:title=" + $('head meta[property="og:title"]').attr("content"),
          "empty=" + JSON.stringify($('head meta[name="demo-empty"]').attr("content")),
          "missing content=" + String($('head meta[name="demo-no-content"]').attr("content")),
          "absent count=" + $absent.length + "; content=" + String($absent.attr("content")),
          "charset=" + $('head meta[charset]').attr("charset")
        ].join("\n"));
      }
      $("#read").on("click", report);
      $("#update").on("click", function () {
        descriptions().attr("content", "Updated <em>summary</em>"); report();
      });
      $("#duplicate").on("click", function () {
        $("<meta>").attr({ name: "description", content: "Second summary" }).appendTo("head");
        $(this).prop("disabled", true); report();
      });
      $("#remove").on("click", function () { descriptions().remove(); report(); });
      $("#reset").on("click", function () {
        descriptions().remove();
        $("<meta>").attr({ name: "description", content: "Original page summary" }).appendTo("head");
        $("#duplicate").prop("disabled", false); report();
      });
      report();
    });
  </script>
</body>
</html>

초기 출력입니다. content=""는 빈 문자열이며, content 속성이 없거나 대상 요소가 없으면 .attr()은 undefined를 반환합니다. 요소가 있는지는 length로 별도 확인합니다.

description=Original page summary
description count=1
all descriptions=["Original page summary"]
og:title=Meta demo
empty=""
missing content=undefined
absent count=0; content=undefined
charset=utf-8
  1. Read current DOM을 누르면 현재 문서의 값을 다시 읽습니다. 원래 description은 Original page summary이며 count=1입니다.
  2. Add duplicate를 누르면 description이 2개가 됩니다. 첫 getter는 여전히 Original page summary이고 전체 목록은 ["Original page summary","Second summary"]입니다.
  3. Update existing description을 누르면 현재 일치하는 description 모두가 Updated <em>summary</em>로 바뀝니다. 결과는 .text()로 표시하므로 em 요소가 생성되지 않습니다.
  4. Remove description을 누르면 count=0, description=undefined, all descriptions=[]입니다. 이 상태에서 Update existing description을 눌러도 없는 태그를 자동 생성하지 않습니다.
  5. Reset은 description만 정리해 원래 값 하나로 되돌립니다. charset·viewport·og:title 같은 다른 메타는 그대로 둡니다.

빈 값·없는 값·중복 값 처리하기

조회 결과를 단순히 if(value)로만 검사하면 빈 문자열과 undefined를 같은 경우로 처리하게 됩니다. 태그 존재 여부는 $meta.length, 속성 누락은 value === undefined, 의도적인 빈 값은 value === ""로 나누어 판단합니다. 문자열 "undefined"를 실제 데이터로 저장하지 않으며, 예제의 String() 변환은 차이를 화면에 보여 주기 위한 것입니다.

.attr("content") getter는 선택 집합의 첫 요소만 읽습니다. 문서에 중복 description이 있어도 자동으로 병합하거나 최신 값을 찾아주지 않습니다. 예제는 .each()로 각 값을 배열에 넣어 개수와 순서를 확인합니다. 중복은 원본 템플릿이나 SEO 플러그인 설정에서 원인을 찾아 정리해야 하며, 첫 값만 읽어 정상이라고 판단하지 않습니다.

setter인 .attr("content", value)는 일치하는 요소 모두를 바꿉니다. 이 글의 Update 버튼은 조회가 현재 DOM을 읽는다는 사실을 확인하기 위한 실습입니다. 값을 읽으려는 코드에 두 번째 인자를 넣지 않습니다. 실제 사이트에서는 SEO 플러그인·테마가 관리하는 메타를 임의로 덮어쓰지 않습니다.

공백을 포함한 문자열도 속성값으로 그대로 읽을 수 있습니다. 필요에 따라 공백 정리를 하더라도 원본과 빈 값의 의미를 먼저 정합니다. 조회한 문자열을 화면에 표시할 때는 예제처럼 .text()로 넣고, 다른 코드에서 HTML로 해석하지 않도록 합니다.

현재 DOM과 서버 원본을 구분하기

이 코드는 실행 중인 현재 문서의 DOM(Document Object Model)을 읽습니다. 다른 스크립트가 content를 수정한 뒤에는 수정된 값이 보이며, 서버가 처음 보낸 페이지 소스가 바뀌는 것은 아닙니다. 동적으로 정보를 추가하는 앱에서는 해당 처리가 끝난 뒤 읽거나 갱신 지점에서 다시 조회합니다. 문서 준비 시점이 모든 비동기 작업의 완료를 뜻하지는 않습니다.

개발자 도구의 Elements에서 현재 head를 확인하고, 페이지 소스 보기에서 서버 HTML을 비교하면 차이를 찾기 쉽습니다. 스크립트로 값을 읽거나 바꿨다는 사실만으로 검색 결과나 공유 미리보기가 같은 값으로 갱신됐다고 판단하지 않습니다. Google의 JavaScript SEO 문서도 크롤링·렌더링·색인 단계를 구분하므로, 실제 수집 결과는 해당 서비스의 도구로 따로 확인합니다.

현재 문서 선택자는 다른 URL의 메타를 가져오는 요청을 보내지 않습니다. 다른 페이지를 검사하려면 그 페이지의 HTML을 허용된 방식으로 가져오는 별도 절차가 필요하며, 이 예제를 그대로 실행해 임의 사이트의 정보를 읽는 기능으로 생각하지 않습니다.