<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sms114.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sms114.github.io/" rel="alternate" type="text/html" /><updated>2025-03-13T22:24:12+09:00</updated><id>https://sms114.github.io/feed.xml</id><title type="html">김경훈의 기술 블로그</title><subtitle>누리넷 게시판 DASHBOARD</subtitle><author><name>소우주(주)</name></author><entry><title type="html">[ puppeteer] puppeteer유니크이미지만들기스크립트</title><link href="https://sms114.github.io/puppeteer/chapter04-puppeteer%EC%9C%A0%EB%8B%88%ED%81%AC%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A7%8C%EB%93%A4%EA%B8%B0%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8/" rel="alternate" type="text/html" title="[ puppeteer] puppeteer유니크이미지만들기스크립트" /><published>2025-02-08T00:00:00+09:00</published><updated>2025-02-08T00:00:00+09:00</updated><id>https://sms114.github.io/puppeteer/chapter04-puppeteer%EC%9C%A0%EB%8B%88%ED%81%AC%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A7%8C%EB%93%A4%EA%B8%B0%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</id><content type="html" xml:base="https://sms114.github.io/puppeteer/chapter04-puppeteer%EC%9C%A0%EB%8B%88%ED%81%AC%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A7%8C%EB%93%A4%EA%B8%B0%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8/"><![CDATA[<h1 id="puppeteer유니크-이미지-만들기-script">puppeteer유니크 이미지 만들기 script</h1>

<p>결국, 이미지에 포함된 한글은 추출해내지 못했다. 하지만 class 요소를 지정해서 해당 유니크 이미지를 가져오는 것은 큰 문제없이 가져온다. 오랜 시간이 걸리며 학습한 퍼페티어의 라인별 지식은 큰 도움이 될 것이다. 답을 찾아나가는 것이 중요하다는 믿음을 가지자. 결국 눈에 익어야 한 줄 한 줄 검증이 가능한 것. 조바심을 내지 말고, 천천히 온전하게 나아가면 된다. 그것뿐이다.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>

<span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>    <span class="c1">// 비동기 실행 함수 ( async IIFE )</span>
    <span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">({</span>
        <span class="na">headless</span><span class="p">:</span> <span class="dl">'</span><span class="s1">new</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">executablePath</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/usr/bin/google-chrome</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">args</span><span class="p">:</span> <span class="p">[</span>
            <span class="dl">'</span><span class="s1">--no-sandbox</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-setuid-sandbox</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-web-security</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-features=IsolateOrigins,site-per-process</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-extensions</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-features=BlockInsecurePrivateNetworkRequests</span><span class="dl">'</span>
        <span class="p">]</span>
    <span class="p">});</span>

    <span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>  <span class="c1">//새로운 브라우저 탭(페이지)를 생성.</span>

    <span class="c1">// 최신 User-Agent 설정 //봇 감지를 방지하기 위해 일반 브라우저처럼 속임. Chrome/120.0.0.0 → 최신 크롬 브라우저로 위장.</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setUserAgent</span><span class="p">(</span><span class="dl">'</span><span class="s1">Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36</span><span class="dl">'</span><span class="p">);</span>

    <span class="c1">// 요청 차단 방지 </span>
<span class="nx">req</span><span class="p">.</span><span class="k">continue</span><span class="p">();</span> <span class="err">→</span> <span class="nx">Puppeteer가</span> <span class="nx">특정</span> <span class="nx">요청을</span> <span class="nx">차단하지</span> <span class="nx">않고</span> <span class="nx">계속</span> <span class="nx">진행하도록</span> <span class="nx">설정</span><span class="p">.</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setRequestInterception</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>  <span class="c1">//웹사이트가 광고 또는 크롤러 차단을 시도할 경우 모든 요청을 수동으로 처리.</span>
    <span class="nx">page</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">request</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">([</span><span class="dl">'</span><span class="s1">image</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">stylesheet</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">font</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">xhr</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">fetch</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">eventsource</span><span class="dl">'</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">resourceType</span><span class="p">()))</span> <span class="p">{</span>
            <span class="nx">req</span><span class="p">.</span><span class="k">continue</span><span class="p">();</span>  <span class="c1">// 모든 요청 허용 , Puppeteer가 특정 요청을 차단하지 않고 계속 진행하도록 설정.</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="nx">req</span><span class="p">.</span><span class="k">continue</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">});</span>

    <span class="c1">// 추가적인 헤더 설정 , Accept-Language → 웹사이트가 한국어 페이지를 제공하도록 유도.</span>
    <span class="c1">// Referer: https://www.google.com/ → 구글에서 방문한 것처럼 속이기 (크롤링 탐지 방지).</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setExtraHTTPHeaders</span><span class="p">({</span>
        <span class="dl">'</span><span class="s1">Accept-Language</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ko-KR,ko;q=0.9,en-US,en;q=0.8</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">Referer</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://www.google.com/</span><span class="dl">'</span><span class="p">,</span>
    <span class="p">});</span>

    <span class="c1">// 페이지 이동</span>
    <span class="c1">// URL에 한글이 포함될 경우 올바르게 인코딩하여 요청.</span>
    <span class="c1">// waitUntil: 'networkidle2' → 네트워크 요청이 거의 없는 상태일 때 페이지가 완전히 로드되었다고 판단.</span>
    <span class="c1">// timeout: 60000 → 최대 60초 동안 응답 대기</span>
    <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="nb">encodeURI</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://tripworldgo.net/이미지.html</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">waitUntil</span><span class="p">:</span> <span class="dl">'</span><span class="s1">networkidle2</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">timeout</span><span class="p">:</span> <span class="mi">60000</span>
    <span class="p">});</span>

    <span class="c1">// ✅ .img99 요소가 로드될 때까지 기다림</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">waitForSelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img99</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">timeout</span><span class="p">:</span> <span class="mi">10000</span> <span class="p">});</span>

    <span class="c1">// ✅ `.img99` 요소의 HTML 코드 가져오기</span>
    <span class="kd">const</span> <span class="nx">extractedHtml</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">img99Element</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img99</span><span class="dl">'</span><span class="p">);</span>
        <span class="k">return</span> <span class="nx">img99Element</span> <span class="p">?</span> <span class="nx">img99Element</span><span class="p">.</span><span class="nx">outerHTML</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">❌ .img99 요소를 찾을 수 없음</span><span class="dl">"</span><span class="p">;</span>
    <span class="p">});</span>

    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">📌 추출된 HTML 코드:</span><span class="se">\n</span><span class="dl">"</span><span class="p">,</span> <span class="nx">extractedHtml</span><span class="p">);</span>

    <span class="c1">// ✅ HTML 파일로 저장 .img99 요소의 HTML을 img99_preview.html 파일로 저장.</span>
    <span class="kd">const</span> <span class="nx">htmlFilePath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="dl">'</span><span class="s1">img99_preview.html</span><span class="dl">'</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">finalHtml</span> <span class="o">=</span> <span class="s2">`&lt;!DOCTYPE html&gt;
        &lt;html lang="ko"&gt;
        &lt;head&gt;
            &lt;meta charset="UTF-8"&gt;
            &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
            &lt;title&gt;img99 Preview&lt;/title&gt;
            &lt;style&gt;
                body { margin: 0; padding: 20px; background-color: #f5f5f5; text-align: center; }
                .container { display: flex; justify-content: center; align-items: center; height: 100vh; }
            &lt;/style&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;div class="container"&gt;
                </span><span class="p">${</span><span class="nx">extractedHtml</span><span class="p">}</span><span class="s2">
            &lt;/div&gt;
        &lt;/body&gt;
        &lt;/html&gt;`</span><span class="p">;</span>

    <span class="nx">fs</span><span class="p">.</span><span class="nx">writeFileSync</span><span class="p">(</span><span class="nx">htmlFilePath</span><span class="p">,</span> <span class="nx">finalHtml</span><span class="p">,</span> <span class="dl">'</span><span class="s1">utf8</span><span class="dl">'</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">✅ HTML 파일 저장 완료:</span><span class="dl">"</span><span class="p">,</span> <span class="nx">htmlFilePath</span><span class="p">);</span>

    <span class="c1">// ✅ 새 페이지에서 저장된 HTML 열기</span>
    <span class="kd">const</span> <span class="nx">newPage</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>
    <span class="k">await</span> <span class="nx">newPage</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="s2">`file://</span><span class="p">${</span><span class="nx">htmlFilePath</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="p">{</span> <span class="na">waitUntil</span><span class="p">:</span> <span class="dl">'</span><span class="s1">networkidle2</span><span class="dl">'</span> <span class="p">});</span>

    <span class="kd">const</span> <span class="nx">element</span> <span class="o">=</span><span class="k">await</span> <span class="nx">newPage</span><span class="p">.</span><span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img99</span><span class="dl">'</span><span class="p">);</span> <span class="c1">// .img99 요소선택</span>
    <span class="kd">const</span> <span class="nx">boundingBox</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">element</span><span class="p">.</span><span class="nx">boundingBox</span><span class="p">();</span> <span class="c1">// 요소의 위치 및 크기 가져오기</span>

    <span class="c1">// .img99 요소의 크기와 위치를 기준으로 요소만 캡처하여 element.png로 저장.</span>
    <span class="k">await</span> <span class="nx">newPage</span><span class="p">.</span><span class="nx">screenshot</span><span class="p">({</span>
        <span class="na">path</span><span class="p">:</span> <span class="dl">'</span><span class="s1">element.png</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">clip</span><span class="p">:</span> <span class="p">{</span>
            <span class="na">x</span><span class="p">:</span> <span class="nx">boundingBox</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span>
            <span class="na">y</span><span class="p">:</span> <span class="nx">boundingBox</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span>
            <span class="na">width</span><span class="p">:</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="nx">boundingBox</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span> <span class="nx">newPage</span><span class="p">.</span><span class="nx">viewport</span><span class="p">().</span><span class="nx">width</span><span class="p">),</span>
            <span class="na">height</span><span class="p">:</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="nx">boundingBox</span><span class="p">.</span><span class="nx">height</span><span class="p">,</span> <span class="nx">newPage</span><span class="p">.</span><span class="nx">viewport</span><span class="p">().</span><span class="nx">height</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">})</span> <span class="c1">// clip 옵션을 사용하여 요소의 위치 및 크기로 스크린샷 캡처</span>

    <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
<span class="p">})();</span>

</code></pre></div></div>

<h2 id="1-해석">1. 해석</h2>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>
</code></pre></div></div>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">puppeteer</code></strong>: 웹 자동화를 위한 Puppeteer 모듈을 불러옴.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">fs</code></strong>: HTML 파일을 생성하고 저장하기 위해 Node.js의 파일 시스템 모듈 사용.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">path</code></strong>: 파일 경로를 다루기 위해 Node.js의 <code class="language-plaintext highlighter-rouge">path</code> 모듈 사용.</li>
</ul>

<h2 id="2-해석">2. 해석</h2>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">({</span>
    <span class="na">headless</span><span class="p">:</span> <span class="dl">'</span><span class="s1">new</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">executablePath</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/usr/bin/google-chrome</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">args</span><span class="p">:</span> <span class="p">[</span>
        <span class="dl">'</span><span class="s1">--no-sandbox</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">--disable-setuid-sandbox</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">--disable-web-security</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">--disable-features=IsolateOrigins,site-per-process</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">--disable-extensions</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">--disable-features=BlockInsecurePrivateNetworkRequests</span><span class="dl">'</span>
    <span class="p">]</span>
<span class="p">});</span>
</code></pre></div></div>

<p><strong>Puppeteer를 실행하여 크롬 브라우저를 띄움.</strong></p>

<p><code class="language-plaintext highlighter-rouge">headless: 'new'</code> → 최신 Puppeteer의 <strong>헤드리스 모드 사용</strong> (GUI 없이 실행).</p>

<p><code class="language-plaintext highlighter-rouge">executablePath: '/usr/bin/google-chrome'</code> → <strong>리눅스/EC2 환경에서 크롬 실행 경로 지정</strong>.</p>

<p><code class="language-plaintext highlighter-rouge">args</code> 옵션 설명:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">--no-sandbox</code>, <code class="language-plaintext highlighter-rouge">--disable-setuid-sandbox</code> → <strong>보안 샌드박스를 비활성화</strong> (EC2 등 서버 환경에서 필요).</li>
  <li><code class="language-plaintext highlighter-rouge">--disable-web-security</code> → <strong>CORS 문제를 무시하고 모든 리소스를 로드</strong>.</li>
  <li><code class="language-plaintext highlighter-rouge">--disable-features=IsolateOrigins,site-per-process</code> → <strong>사이트 간 격리 기능을 비활성화</strong>.</li>
  <li><code class="language-plaintext highlighter-rouge">--disable-extensions</code> → <strong>브라우저 확장 프로그램을 비활성화</strong>.</li>
  <li><code class="language-plaintext highlighter-rouge">--disable-features=BlockInsecurePrivateNetworkRequests</code> → <strong>보안 정책에 의해 차단되는 요청을 허용</strong>.</li>
</ul>

<h2 id="결과물">결과물</h2>

<p><a href="/../../images/2025-02-08-chapter04-puppeteer유니크이미지만들기스크립트/image-20250208214354015.png">img99_preview.html</a></p>

<p><img src="/../../images/2025-02-08-chapter04-puppeteer유니크이미지만들기스크립트/image-20250208214428618.png" alt="element.png" /></p>

<h1 id="최종적-한글까지-포함된-이미지가-나오는-코드-메모">최종적, 한글까지 포함된 이미지가 나오는 코드 메모</h1>

<p>대상 타킷 이미지&gt;</p>

<p><img src="/../../images/2025-02-08-chapter04-puppeteer유니크이미지만들기스크립트/image-20250208222712263.png" alt="image-20250208222712263" /></p>

<p>위에서 처럼 잘 가지고 왔다.</p>

<p>그래서, 최종 코드는 다음과 같다.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>

<span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">({</span>
        <span class="na">headless</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
        <span class="na">executablePath</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/usr/bin/google-chrome</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">args</span><span class="p">:</span> <span class="p">[</span>
            <span class="dl">'</span><span class="s1">--no-sandbox</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-setuid-sandbox</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-web-security</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-features=IsolateOrigins,site-per-process</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-extensions</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-features=BlockInsecurePrivateNetworkRequests</span><span class="dl">'</span>
        <span class="p">]</span>
    <span class="p">});</span>

    <span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>

    <span class="c1">// 최신 User-Agent 설정</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setUserAgent</span><span class="p">(</span><span class="dl">'</span><span class="s1">Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36</span><span class="dl">'</span><span class="p">);</span>

    <span class="c1">// 요청 차단 방지</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setRequestInterception</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
    <span class="nx">page</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">request</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="nx">req</span><span class="p">.</span><span class="k">continue</span><span class="p">();</span>  <span class="c1">// 모든 요청 허용</span>
    <span class="p">});</span>

    <span class="c1">// 추가적인 헤더 설정</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setExtraHTTPHeaders</span><span class="p">({</span>
        <span class="dl">'</span><span class="s1">Accept-Language</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ko-KR,ko;q=0.9,en-US,en;q=0.8</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">Referer</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://www.google.com/</span><span class="dl">'</span><span class="p">,</span>
    <span class="p">});</span>

    <span class="c1">// 페이지 이동</span>
    <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="nb">encodeURI</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://tripworldgo.net/이미지.html</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">waitUntil</span><span class="p">:</span> <span class="dl">'</span><span class="s1">networkidle2</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">timeout</span><span class="p">:</span> <span class="mi">60000</span>
    <span class="p">});</span>

    <span class="c1">// 모든 폰트가 로드될 때까지 대기</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">await</span> <span class="nb">document</span><span class="p">.</span><span class="nx">fonts</span><span class="p">.</span><span class="nx">ready</span><span class="p">;</span>
        <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">visibility</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">visible</span><span class="dl">'</span><span class="p">;</span>
    <span class="p">});</span>

    <span class="c1">// 전체 페이지 스크린샷 찍기</span>
    <span class="kd">const</span> <span class="nx">fullScreenshotPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="dl">'</span><span class="s1">full_page.png</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">screenshot</span><span class="p">({</span> <span class="na">path</span><span class="p">:</span> <span class="nx">fullScreenshotPath</span><span class="p">,</span> <span class="na">fullPage</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`✅ 전체 페이지 캡처 완료: </span><span class="p">${</span><span class="nx">fullScreenshotPath</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>

    <span class="c1">// 특정 요소가 로드될 때까지 기다림</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">waitForSelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img2</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">timeout</span><span class="p">:</span> <span class="mi">10000</span> <span class="p">});</span>

    <span class="c1">// 특정 요소의 위치 가져오기 및 스크린샷 캡처</span>
    <span class="kd">const</span> <span class="nx">element</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img2</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">box</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">element</span><span class="p">.</span><span class="nx">boundingBox</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">box</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">const</span> <span class="nx">elementScreenshotPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="dl">'</span><span class="s1">img2_capture.png</span><span class="dl">'</span><span class="p">);</span>
            <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">screenshot</span><span class="p">({</span>
                <span class="na">path</span><span class="p">:</span> <span class="nx">elementScreenshotPath</span><span class="p">,</span>
                <span class="na">clip</span><span class="p">:</span> <span class="p">{</span>
                    <span class="na">x</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span>
                    <span class="na">y</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span>
                    <span class="na">width</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span>
                    <span class="na">height</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">height</span>
                <span class="p">}</span>
            <span class="p">});</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`✅ 특정 요소 캡처 완료: </span><span class="p">${</span><span class="nx">elementScreenshotPath</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">❌ 요소를 찾을 수 없음: .img2</span><span class="dl">"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
<span class="p">})();</span>

</code></pre></div></div>

<p>한글 코드를 맥이는 방법에서 좀 애를 먹었다.</p>

<ol>
  <li>
    <p><strong>내가 쓰는 서버는 Amazon EC2 2023 이며, 그래서 해당 서버의 기본 패키지 저장소에 한글 폰트 패키지가 포함되어 있지 않을 수 있어 나눔 폰트를 수동으로 다운로드 설치해야 했다.</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /usr/share/fonts
<span class="nb">sudo </span>wget http://cdn.naver.com/naver/NanumFont/fontfiles/NanumFont_TTF_ALL.zip
<span class="nb">sudo </span>unzip NanumFont_TTF_ALL.zip
<span class="nb">sudo rm </span>NanumFont_TTF_ALL.zip
</code></pre></div>    </div>

    <p>결과 &gt;</p>

    <p><img src="/../../images/2025-02-08-chapter04-puppeteer유니크이미지만들기스크립트/image-20250208223108538.png" alt="image-20250208223108538" /></p>
  </li>
  <li>폰트 캐시 갱신:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>fc-cache <span class="nt">-f</span> <span class="nt">-v</span>
</code></pre></div>    </div>
  </li>
  <li>최종 코드 수정 ( 파일명 : screen.js ) ( ✅ 특정 요소 캡처 완료: /var/www/html/img2_capture.png)
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>
   
<span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">({</span>
        <span class="na">headless</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
        <span class="na">executablePath</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/usr/bin/google-chrome</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">args</span><span class="p">:</span> <span class="p">[</span>
            <span class="dl">'</span><span class="s1">--no-sandbox</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-setuid-sandbox</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-web-security</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-features=IsolateOrigins,site-per-process</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-extensions</span><span class="dl">'</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">--disable-features=BlockInsecurePrivateNetworkRequests</span><span class="dl">'</span>
        <span class="p">]</span>
    <span class="p">});</span>
   
    <span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>
   
    <span class="c1">// 최신 User-Agent 설정</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setUserAgent</span><span class="p">(</span><span class="dl">'</span><span class="s1">Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36</span><span class="dl">'</span><span class="p">);</span>
   
    <span class="c1">// 요청 차단 방지</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setRequestInterception</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
    <span class="nx">page</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">request</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="nx">req</span><span class="p">.</span><span class="k">continue</span><span class="p">();</span>  <span class="c1">// 모든 요청 허용</span>
    <span class="p">});</span>
   
    <span class="c1">// 추가적인 헤더 설정</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setExtraHTTPHeaders</span><span class="p">({</span>
        <span class="dl">'</span><span class="s1">Accept-Language</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">ko-KR,ko;q=0.9,en-US,en;q=0.8</span><span class="dl">'</span><span class="p">,</span>
        <span class="dl">'</span><span class="s1">Referer</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://www.google.com/</span><span class="dl">'</span><span class="p">,</span>
    <span class="p">});</span>
   
    <span class="c1">// 페이지 이동</span>
    <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="nb">encodeURI</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://tripworldgo.net/이미지.html</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">waitUntil</span><span class="p">:</span> <span class="dl">'</span><span class="s1">networkidle2</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">timeout</span><span class="p">:</span> <span class="mi">60000</span>
    <span class="p">});</span>
   
    <span class="c1">// 모든 폰트가 로드될 때까지 대기</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">await</span> <span class="nb">document</span><span class="p">.</span><span class="nx">fonts</span><span class="p">.</span><span class="nx">ready</span><span class="p">;</span>
        <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">visibility</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">visible</span><span class="dl">'</span><span class="p">;</span>
    <span class="p">});</span>
   
    <span class="c1">// 특정 요소가 로드될 때까지 기다림</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">waitForSelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img2</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">timeout</span><span class="p">:</span> <span class="mi">10000</span> <span class="p">});</span>
   
    <span class="c1">// 특정 요소의 위치 가져오기 및 스크린샷 캡처</span>
    <span class="kd">const</span> <span class="nx">element</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.img2</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">box</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">element</span><span class="p">.</span><span class="nx">boundingBox</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">box</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">const</span> <span class="nx">elementScreenshotPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="dl">'</span><span class="s1">img2_capture.png</span><span class="dl">'</span><span class="p">);</span>
            <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">screenshot</span><span class="p">({</span>
                <span class="na">path</span><span class="p">:</span> <span class="nx">elementScreenshotPath</span><span class="p">,</span>
                <span class="na">clip</span><span class="p">:</span> <span class="p">{</span>
                    <span class="na">x</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span>
                    <span class="na">y</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span>
                    <span class="na">width</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span>
                    <span class="na">height</span><span class="p">:</span> <span class="nx">box</span><span class="p">.</span><span class="nx">height</span>
                <span class="p">}</span>
            <span class="p">});</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`✅ 특정 요소 캡처 완료: </span><span class="p">${</span><span class="nx">elementScreenshotPath</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">❌ 요소를 찾을 수 없음: .img2</span><span class="dl">"</span><span class="p">);</span>
    <span class="p">}</span>
   
    <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
<span class="p">})();</span>
   
</code></pre></div>    </div>
  </li>
</ol>]]></content><author><name>소우주(주)</name></author><category term="puppeteer" /><category term="puppeteer" /><summary type="html"><![CDATA[puppeteer유니크 이미지 만들기 script]]></summary></entry><entry><title type="html">[linux] chromium또는google-chrome을설치해야하는이유</title><link href="https://sms114.github.io/linux/chromium%EB%98%90%EB%8A%94google-chrome%EC%9D%84%EC%84%A4%EC%B9%98%ED%95%B4%EC%95%BC%ED%95%98%EB%8A%94%EC%9D%B4%EC%9C%A0/" rel="alternate" type="text/html" title="[linux] chromium또는google-chrome을설치해야하는이유" /><published>2025-02-08T00:00:00+09:00</published><updated>2025-02-08T00:00:00+09:00</updated><id>https://sms114.github.io/linux/chromium%EB%98%90%EB%8A%94google-chrome%EC%9D%84%EC%84%A4%EC%B9%98%ED%95%B4%EC%95%BC%ED%95%98%EB%8A%94%EC%9D%B4%EC%9C%A0</id><content type="html" xml:base="https://sms114.github.io/linux/chromium%EB%98%90%EB%8A%94google-chrome%EC%9D%84%EC%84%A4%EC%B9%98%ED%95%B4%EC%95%BC%ED%95%98%EB%8A%94%EC%9D%B4%EC%9C%A0/"><![CDATA[<h1 id="puppeteer--google-chrome-또는-chromium-설치-이유">Puppeteer , google-chrome 또는 chromium 설치 이유</h1>

<p>Puppeteer는 기본적으로 <strong>Chromium을 자동으로 다운로드</strong>하지만,
✅ <strong>EC2 환경에서는 기본 Chromium 다운로드가 실패하는 경우가 많아!</strong>
✅ 따라서, <strong>시스템에 직접 Chromium 또는 Google Chrome을 설치</strong>해서 사용해야 해.</p>

<p><strong>Puppeeer 실행 시 기본적으로 사용하는 명령어:</strong></p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">();</span>
</code></pre></div></div>

<p>이 코드가 실행되면 Puppeteer가 자체적으로 Chromium을 다운로드하려고 시도해.
하지만 <strong>EC2에서는 권한 문제나 네트워크 제한으로 다운로드가 실패할 가능성이 높아</strong>.</p>

<p>🔹 해결 방법 → <strong>시스템에 직접 Chromium 또는 Google Chrome을 설치한 후, <code class="language-plaintext highlighter-rouge">executablePath</code>를 명시적으로 지정</strong>하면 돼.</p>

<p>위와 같은 이유로 google-chrome 또는 chromium 을 설치해야만 하는 거다.</p>

<h2 id="-2-chromium-vs-google-chrome-비교"><strong>✅ 2. Chromium vs Google Chrome 비교</strong></h2>

<table>
  <thead>
    <tr>
      <th>항목</th>
      <th>Chromium</th>
      <th>Google Chrome</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>🏗 <strong>개발사</strong></td>
      <td>Google (오픈소스)</td>
      <td>Google (상용)</td>
    </tr>
    <tr>
      <td>🌐 <strong>사용 목적</strong></td>
      <td>Headless 브라우저 테스트</td>
      <td>일반 사용자용 브라우저</td>
    </tr>
    <tr>
      <td>⚡ <strong>성능</strong></td>
      <td>가벼움, 빠름</td>
      <td>확장 기능 및 DRM 지원</td>
    </tr>
    <tr>
      <td>📦 <strong>패키지 크기</strong></td>
      <td>작음 (~80MB)</td>
      <td>큼 (~100MB 이상)</td>
    </tr>
    <tr>
      <td>🔧 <strong>EC2에서 사용 가능?</strong></td>
      <td>🟡 (설치가 까다로움)</td>
      <td>🟢 (더 안정적)</td>
    </tr>
  </tbody>
</table>

<p>✅ <strong>결론:</strong></p>

<ul>
  <li>
    <p><strong>Chromium</strong>은 더 가볍지만, <strong>Amazon Linux 2023에서 설치가 어렵거나 패키지 충돌이 발생할 수 있음</strong></p>
  </li>
  <li>
    <p><strong>Google Chrome은 설치가 더 쉽고 안정적</strong> → EC2에서는 <strong>Google Chrome 추천!</strong> 🚀</p>
  </li>
</ul>]]></content><author><name>소우주(주)</name></author><category term="linux" /><category term="linux" /><category term="chromium" /><category term="google-chrome" /><summary type="html"><![CDATA[Puppeteer , google-chrome 또는 chromium 설치 이유]]></summary></entry><entry><title type="html">[linux] linux 서버 OOM 상황에 대한 메모</title><link href="https://sms114.github.io/linux/cpu%ED%92%80%EB%B0%8Fmemory%EA%B3%BC%EB%B6%80%ED%95%98/" rel="alternate" type="text/html" title="[linux] linux 서버 OOM 상황에 대한 메모" /><published>2025-02-08T00:00:00+09:00</published><updated>2025-02-08T00:00:00+09:00</updated><id>https://sms114.github.io/linux/cpu%ED%92%80%EB%B0%8Fmemory%EA%B3%BC%EB%B6%80%ED%95%98</id><content type="html" xml:base="https://sms114.github.io/linux/cpu%ED%92%80%EB%B0%8Fmemory%EA%B3%BC%EB%B6%80%ED%95%98/"><![CDATA[<h1 id="메모리-과부하-상태에-대한-메모랜다">메모리 과부하 상태에 대한 메모랜다</h1>

<p><img src="/../images/2025-02-08-cpu풀및memory과부하/화면 캡처 2025-02-08 084707.png" alt="화면 캡처 2025-02-08 084707" /></p>

<h2 id="-위에서처럼-swap-이라는-process가-생겼다는-것의-의미에-대한-고찰">&gt; 위에서처럼 swap 이라는 process가 생겼다는 것의 의미에 대한 고찰</h2>

<p><strong>kswapd0 는 리눅스 커널의 가상 메모리 관리 프로세스로, 시스템 메모리의 부족을 감지하면 스왑(Swap) 영역을 적극적으로 활용하여 페이지를 디스크로 내보내는 역할을 한다. 위 상태에서 kswap0 가 CPU를 99.9% 사용하고 있다는 것은 메모리 부족(Out of Memory, OOM) 상태이거나 페이지 스왑이 과도하게 발생하고 있다는 신호로 여겨도 좋다.</strong></p>

<hr />

<h3 id="-kswapd0-과부하-원인">🔍 <code class="language-plaintext highlighter-rouge">kswapd0</code> 과부하 원인</h3>

<ol>
  <li><strong>물리 메모리 부족</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">free -m</code> 명령어로 메모리 상태 확인 (<code class="language-plaintext highlighter-rouge">available</code> 값이 거의 0에 가까우면 위험)</li>
      <li><code class="language-plaintext highlighter-rouge">top</code> 또는 <code class="language-plaintext highlighter-rouge">htop</code>으로 메모리를 많이 사용하는 프로세스 찾기</li>
    </ul>
  </li>
  <li><strong>스왑 과다 사용</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">swapon -s</code> 또는 <code class="language-plaintext highlighter-rouge">free -m</code>에서 Swap 사용량 확인</li>
      <li><code class="language-plaintext highlighter-rouge">vmstat 1</code>을 실행하여 <code class="language-plaintext highlighter-rouge">si</code>(Swap-in) 및 <code class="language-plaintext highlighter-rouge">so</code>(Swap-out) 값이 높으면 스왑 과부하</li>
    </ul>
  </li>
  <li><strong>Page Cache 또는 Buffer 과다 사용</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">cat /proc/meminfo | grep -E 'Dirty|Writeback|Mapped'</code> 확인</li>
      <li>캐시된 데이터가 많아 swap이 증가했을 가능성</li>
    </ul>
  </li>
  <li><strong>swappiness 값이 너무 높음</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">cat /proc/sys/vm/swappiness</code> 확인</li>
      <li>기본값(60)이 높아 swap을 너무 적극적으로 사용하고 있을 가능성</li>
    </ul>
  </li>
</ol>

<h3 id="-해결-방법">🛠 해결 방법</h3>

<p>✅ <strong>메모리 사용량 줄이기</strong></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">ps aux --sort=-%mem | head -10</code> 으로 메모리 많이 쓰는 프로세스 정리</li>
  <li>불필요한 서비스 종료 (<code class="language-plaintext highlighter-rouge">systemctl stop {service_name}</code>)</li>
</ul>

<p>✅ <strong>스왑 최적화</strong></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">sysctl -w vm.swappiness=10</code> 로 swappiness 값 낮추기</li>
  <li>필요하면 <code class="language-plaintext highlighter-rouge">/etc/sysctl.conf</code>에 <code class="language-plaintext highlighter-rouge">vm.swappiness=10</code> 추가</li>
</ul>

<p>✅ <strong>캐시 메모리 정리 (일시적 해결)</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bash


복사편집
sync; echo 3 &gt; /proc/sys/vm/drop_caches
</code></pre></div></div>

<p>✅ <strong>RAM 증설 또는 OOM Killer 설정</strong></p>

<ul>
  <li>물리 RAM이 부족하면 증설 고려</li>
  <li>OOM Killer가 적절히 동작하는지 확인 (<code class="language-plaintext highlighter-rouge">dmesg | grep -i oom</code>)</li>
</ul>

<hr />

<h2 id="amazon-ec2-2023-에서-인스턴의-메모리-증설-및-cpu-확인">Amazon EC2 2023 에서 인스턴의 메모리 증설 및 CPU 확인</h2>]]></content><author><name>소우주(주)</name></author><category term="linux" /><category term="linux" /><category term="swap" /><category term="memory" /><category term="cpu" /><category term="과부하" /><summary type="html"><![CDATA[메모리 과부하 상태에 대한 메모랜다]]></summary></entry><entry><title type="html">[ puppeteer] puppeteer 마스터하기</title><link href="https://sms114.github.io/puppeteer/chapter04-puppeteer-summary-01/" rel="alternate" type="text/html" title="[ puppeteer] puppeteer 마스터하기" /><published>2025-02-07T00:00:00+09:00</published><updated>2025-02-07T00:00:00+09:00</updated><id>https://sms114.github.io/puppeteer/chapter04-puppeteer-summary-01</id><content type="html" xml:base="https://sms114.github.io/puppeteer/chapter04-puppeteer-summary-01/"><![CDATA[<h1 id="puppeteer-및-nodejs-설치-및-기본">puppeteer 및 nodejs 설치 및 기본</h1>

<h2 id="1-nodejs-설치">1. Node.js 설치</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>yum <span class="nb">install</span> <span class="nt">-y</span> nodejs
</code></pre></div></div>

<h2 id="2-nodejs-버전-확인">2. Node.js 버전 확인</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node <span class="nt">-v</span>
npm <span class="nt">-v</span>  // npm<span class="o">(</span>Node Package Manager<span class="o">)</span>은 nodejs 설치를 관리해 주는 프로그램
</code></pre></div></div>

<h2 id="3-puppeteer-설치기본">3. Puppeteer 설치(기본)</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo ls </span>npm <span class="nb">install </span>puppeteer
</code></pre></div></div>

<blockquote>
  <p>puppeteer 설치 후 설치 확인 하는 방법</p>

  <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm list puppeteer
</code></pre></div>  </div>

  <p>결과</p>

  <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>ec2-user@ip-172-31-42-115 html]<span class="nv">$ </span>npm list puppeteer
html@ /var/www/html
└── puppeteer@24.2.0
</code></pre></div>  </div>

</blockquote>]]></content><author><name>소우주(주)</name></author><category term="puppeteer" /><category term="puppeteer" /><summary type="html"><![CDATA[puppeteer 및 nodejs 설치 및 기본]]></summary></entry><entry><title type="html">[linux] wordpress API 로 글 써보기</title><link href="https://sms114.github.io/wordpress/chapter03-summary-02/" rel="alternate" type="text/html" title="[linux] wordpress API 로 글 써보기" /><published>2025-02-06T00:00:00+09:00</published><updated>2025-02-06T00:00:00+09:00</updated><id>https://sms114.github.io/wordpress/chapter03-summary-02</id><content type="html" xml:base="https://sms114.github.io/wordpress/chapter03-summary-02/"><![CDATA[<h2 id="auto_postphp">auto_post.php</h2>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="c1">// 워드프레스 코어 파일 로드</span>
<span class="k">require_once</span><span class="p">(</span> <span class="s1">'wp-load.php'</span> <span class="p">);</span>


<span class="nv">$sample</span> <span class="o">=</span> <span class="s1">'&lt;div class="style1"&gt;
        &lt;h1&gt;큰제목 - 홍콩의 가성비 좋은 고급호텔 top5&lt;/h1&gt;
        &lt;p&gt;인사말 안녕하세요. 날씨가 좋네요&lt;/p&gt;
        &lt;br&gt;&lt;br&gt;&lt;br&gt;
        &lt;div class="hotelbox"&gt;
            &lt;h3&gt;중제목 - 호텔명&lt;/h3&gt;
            &lt;img src="https://q-xx.bstatic.com/xdata/images/hotel/max1024x768/95628270.jpg?k=757503ac22849096d9d5c5a6f97fa897ac8c979e55197fa0c18f3d32f355382f&amp;o=&amp;s=1024x" alt="이미지의 설명"&gt;
            &lt;p&gt;호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.&lt;/p&gt;
            &lt;h5&gt;소제목 - 주위 가볼만한 곳&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt; 
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;

            &lt;h5&gt;소제목 - 호텔 시설, 특징, 교통&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class="hotelbox"&gt;
            &lt;h3&gt;중제목 - 호텔명&lt;/h3&gt;
            &lt;img src="https://pix8.agoda.net/hotelImages/6362202/0/b79106a8152061339505252638b5b6c0.jpg?ca=9&amp;ce=1&amp;s=1024x" alt="이미지의 설명"&gt;
            &lt;p&gt;호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.&lt;/p&gt;
            &lt;h5&gt;소제목 - 주위 가볼만한 곳&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;

            &lt;h5&gt;소제목 - 호텔 시설, 특징, 교통&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class="hotelbox"&gt;
            &lt;h3&gt;중제목 - 호텔명&lt;/h3&gt;
            &lt;img src="https://pix8.agoda.net/property/22879516/766855982/0d0ef4a797b8d0ff7289fd1f7c0490b9.jpeg?ce=0&amp;s=1024x" alt="이미지의 설명"&gt;
            &lt;p&gt;호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.&lt;/p&gt;
            &lt;h5&gt;소제목 - 주위 가볼만한 곳&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;

            &lt;h5&gt;소제목 - 호텔 시설, 특징, 교통&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class="hotelbox"&gt;
            &lt;h3&gt;중제목 - 호텔명&lt;/h3&gt;
            &lt;img src="https://pix8.agoda.net/property/22879516/766855982/0d0ef4a797b8d0ff7289fd1f7c0490b9.jpeg?ce=0&amp;s=1024x" alt="이미지의 설명"&gt;
            &lt;p&gt;호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.&lt;/p&gt;
            &lt;h5&gt;소제목 - 주위 가볼만한 곳&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;

            &lt;h5&gt;소제목 - 호텔 시설, 특징, 교통&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
        &lt;div class="hotelbox"&gt;
            &lt;h3&gt;중제목 - 호텔명&lt;/h3&gt;
            &lt;img src="https://pix8.agoda.net/property/22879516/766855982/0d0ef4a797b8d0ff7289fd1f7c0490b9.jpeg?ce=0&amp;s=1024x" alt="이미지의 설명"&gt;
            &lt;p&gt;호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.&lt;/p&gt;
            &lt;h5&gt;소제목 - 주위 가볼만한 곳&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;

            &lt;h5&gt;소제목 - 호텔 시설, 특징, 교통&lt;/h5&gt;
            &lt;ul&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
                &lt;li&gt;항목 - 장소&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;'</span><span class="p">;</span>



<span class="c1">// 글 정보</span>
<span class="nv">$new_post</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
    <span class="s1">'post_title'</span>    <span class="o">=&gt;</span> <span class="s1">'test'</span><span class="p">,</span> <span class="c1">//제목</span>
    <span class="s1">'post_content'</span>  <span class="o">=&gt;</span> <span class="nv">$sample</span><span class="p">,</span> <span class="c1">//본문</span>
    <span class="s1">'post_status'</span>   <span class="o">=&gt;</span> <span class="s1">'publish'</span><span class="p">,</span> <span class="c1">//발행상태</span>
    <span class="s1">'post_author'</span>   <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span> <span class="c1">// 작성자 ID</span>
    <span class="s1">'post_type'</span>     <span class="o">=&gt;</span> <span class="s1">'post'</span> <span class="c1">//포스트타입</span>
<span class="p">);</span>

<span class="c1">// 글 작성</span>
<span class="nv">$post_id</span> <span class="o">=</span> <span class="nf">wp_insert_post</span><span class="p">(</span> <span class="nv">$new_post</span> <span class="p">);</span>

<span class="c1">// 글이 성공적으로 작성되었는지 확인</span>
<span class="k">if</span><span class="p">(</span> <span class="nv">$post_id</span> <span class="p">)</span> <span class="p">{</span>
    <span class="k">echo</span> <span class="s2">"포스트가 성공적으로 작성되었습니다. 포스트 ID: "</span> <span class="mf">.</span> <span class="nv">$post_id</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">echo</span> <span class="s2">"포스트 작성에 실패하였습니다."</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">?&gt;</span>

</code></pre></div></div>

<p><img src="/../../images/2025-02-06-chapter03-summary-02/image-20250206122709124.png" alt="image-20250206122709124" /></p>

<p><img src="/../../images/2025-02-06-chapter03-summary-02/image-20250206122748925.png" alt="image-20250206122748925" /></p>

<p>처리된 wordpress 화면을 확인할 수 있다. 이렇게 워드프레스에 자동 글쓰기의 기본 php를 작성하고, 만들어 보았다.</p>

<h2 id="2-amazon-linux-ec2-에-nodejs-부터-peppeteer-설치-방법">2. Amazon linux EC2 에 nodejs 부터 peppeteer 설치 방법</h2>

<h3 id="1-nodejs-설치">1. Node.js 설치</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1️⃣ Node.js 18 (권장 버전) 설치</span>
<span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> nodejs18

<span class="c"># 2️⃣ 설치 확인</span>
node <span class="nt">-v</span>
npm <span class="nt">-v</span>
</code></pre></div></div>

<h3 id="2-puppeteer-설치">2. Puppeteer 설치</h3>

<p>퍼펫티어는 Chrome 브라우저를 자동화하는 Node.js 라이브러리다. 설치하려면 아래 방법으로 설치하자.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1️⃣ 프로젝트 폴더 생성 및 이동 (선택사항)</span>
<span class="nb">mkdir </span>my-project <span class="o">&amp;&amp;</span> <span class="nb">cd </span>my-project

<span class="c"># 2️⃣ Puppeteer 설치</span>
npm <span class="nb">install </span>puppeteer

</code></pre></div></div>

<p>Amazon Linux 2023에서 <strong>Node.js 및 Puppeteer</strong>를 설치하는 방법을 단계별로 알려줄게! 🚀</p>

<hr />

<h2 id="-1-nodejs-설치">✅ <strong>1. Node.js 설치</strong></h2>

<p>Amazon Linux 2023에서는 최신 Node.js를 설치하려면 <strong>NodeSource 저장소</strong>를 사용해야 해!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sh복사편집# 1️⃣ Node.js 18 (권장 버전) 설치
sudo dnf install -y nodejs18

# 2️⃣ 설치 확인
node -v
npm -v
</code></pre></div></div>

<p><strong>출력 예시:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>복사편집v18.17.0
9.6.7  // npm 은 node package Manager 도구이다. node 기반의 프로그램 설치 manager 임., yum 이랑 비슷.
</code></pre></div></div>

<p>nodejs 기반의 프로그램을 설치하기 위해 반드시 npm 도구가 설치되어 있어야한다. 이후 퍼펫티어 설치를 위해 반드시 설치해야 하는 도구 메니져이다.</p>

<p>✅ Node.js와 npm이 정상적으로 설치되었으면 다음 단계로!</p>

<hr />

<h2 id="-2-puppeteer-설치">✅ <strong>2. Puppeteer 설치</strong></h2>

<p>Puppeteer는 <strong>Chrome 브라우저를 자동화</strong>하는 Node.js 라이브러리야! 설치하려면:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sh복사편집# 1️⃣ 프로젝트 폴더 생성 및 이동 (선택사항)
mkdir my-project &amp;&amp; cd my-project

# 2️⃣ Puppeteer 설치
npm install puppeteer
</code></pre></div></div>

<p>📌 Puppeteer는 기본적으로 <strong>헤드리스(Headless) Chrome</strong>을 함께 설치하기 때문에 용량이 크다.
(💡 <strong>EC2에서 용량이 부족하면 <code class="language-plaintext highlighter-rouge">--no-bin-links</code> 옵션 사용 가능</strong>)</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install </span>puppeteer <span class="nt">--no-bin-links</span>
</code></pre></div></div>

<h3 id="-3-puppeteer-실행-테스트">✅ <strong>3. Puppeteer 실행 테스트</strong></h3>

<p>설치 후 Puppeteer 가 제대로 작동하는지 테스트  해 보기 바람.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'const puppeteer = require("puppeteer");
(async () =&gt; {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto("https://example.com");
    console.log("Page loaded!");
    await browser.close();
})();'</span> <span class="o">&gt;</span> test.js

node test.js
</code></pre></div></div>

<h3 id="-4-추가-패키지-설치-필요-시">✅ <strong>4. 추가 패키지 설치 (필요 시)</strong></h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Error: Failed to launch the browser process!
</code></pre></div></div>

<p>위와 같은 오류가 발생한다면, 아래 필요한 라이브러리를 설치해줘야 한다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\</span>
    libXcomposite libXcursor libXdamage libXext libXi <span class="se">\</span>
    libXtst cups-libs libXScrnSaver libXrandr GConf2 <span class="se">\</span>
    alsa-lib gtk3 libdrm libgbm pango at-spi2-atk <span class="se">\</span>
    xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi <span class="se">\</span>
    xorg-x11-utils xorg-x11-fonts-Type1 xorg-x11-server-Xvfb

</code></pre></div></div>

<p>📌 <strong>Amazon Linux 2023에서는 <code class="language-plaintext highlighter-rouge">xorg-x11-fonts-100dpi</code>가 기본 패키지가 아니라 추가 설치 필요할 수 있음!</strong></p>

<p>✅ 이후 다시 <code class="language-plaintext highlighter-rouge">node test.js</code> 실행하면 제대로 작동할 것. 혹시 또 오류가 생긴다면, 다시 필요한 라이브러리 설치 진행.</p>]]></content><author><name>소우주(주)</name></author><category term="wordpress" /><category term="nodejs" /><category term="wordpress" /><category term="api" /><summary type="html"><![CDATA[auto_post.php]]></summary></entry><entry><title type="html">[ puppeteer, Xvfb ] X 서버(X11)란 그리고 GUI 기반 애플리케이션 실행 시스템의 이해</title><link href="https://sms114.github.io/xvfb/chapter03-xvfb-X11-GUI%EC%8B%A4%ED%96%89%EB%B2%95/" rel="alternate" type="text/html" title="[ puppeteer, Xvfb ] X 서버(X11)란 그리고 GUI 기반 애플리케이션 실행 시스템의 이해" /><published>2025-02-06T00:00:00+09:00</published><updated>2025-02-06T00:00:00+09:00</updated><id>https://sms114.github.io/xvfb/chapter03-xvfb-X11-GUI%EC%8B%A4%ED%96%89%EB%B2%95</id><content type="html" xml:base="https://sms114.github.io/xvfb/chapter03-xvfb-X11-GUI%EC%8B%A4%ED%96%89%EB%B2%95/"><![CDATA[<blockquote>
  <p>기본적으로 X11은 <strong>모니터, 키보드, 마우스 입력을 관리</strong>하는 역할을 한다.</p>

  <p>🔹 Linux 데스크톱 환경(GNOME, KDE 등)은 <strong>X 서버 위에서 실행됨</strong>
🔹 Google Chrome 같은 <strong>GUI 기반 애플리케이션도 X 서버가 필요</strong></p>

  <p>하지만 <strong>서버 환경(Linux 서버)</strong>에서는 X 서버가 없다. 따라서, GUI 기반 프로그램(예: Chrome, Firefox 등)이 실행되지 않는다.</p>
</blockquote>

<h2 id="1-가상-x-서버xvfb의-역할">1. 가상 X 서버(Xvfb)의 역할</h2>

<p><strong>Xvfb(X Virtual Frame Buffer)</strong>는 X 서버가 없는 환경에서도
<strong>가상의 프레임 버퍼를 제공하여 GUI 기반 애플리케이션을 실행할 수 있도록 도와준다.</strong></p>

<p>즉, Xvfb는 <strong>“눈에 보이지 않는 가짜 모니터”</strong>라고 생각하자.
🔹 실제 화면이 없지만 <strong>GUI 애플리케이션이 실행될 수 있도록 환경을 제공</strong>
🔹 X 서버가 없어도 <strong>Chrome(또는 Puppeteer)이 정상 실행되도록 해줌</strong>
🔹 <strong>서버 환경에서 X11이 없어도 Chrome을 사용할 수 있음</strong></p>

<h2 id="2-puppeteer와-xvfb가-필요한-이유">2. Puppeteer와 Xvfb가 필요한 이유</h2>

<p>🎯 <strong>문제: Linux 서버에서 GUI 없는 환경</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Error: Failed to launch the browser process! 
Missing X server or <span class="nv">$DISPLAY</span>
</code></pre></div></div>

<p>위와 같은 <strong>“Missing X server”</strong> 오류가 발생하는 이유:</p>

<ul>
  <li>Puppeteer는 Chrome을 실행하는데, Chrome은 기본적으로 <strong>X 서버(X11)가 필요하다</strong></li>
  <li>서버 환경에서는 <strong>GUI가 없기 때문에 실행 불가능</strong></li>
  <li><strong>해결 방법:</strong> Xvfb를 사용하여 <strong>가상의 X 서버 환경을 제공</strong>하면 Chrome 실행 가능</li>
</ul>

<h2 id="3-xvfb-동작-방식">3. Xvfb 동작 방식</h2>

<ol>
  <li>
    <p>Xvfb는 <strong>가상의 X 서버</strong>를 생성 (실제 모니터 없음)</p>
  </li>
  <li>
    <p>X 서버가 필요한 Chrome과 같은 프로그램을 <strong>이 가상 환경에서 실행</strong></p>
  </li>
  <li>Puppeteer(또는 Chrome)가 이 가상의 X 서버를 사용하여 렌더링 수행4</li>
  <li>Puppeteer는 정상적으로 <strong>웹 페이지를 열고, 스크린샷을 찍을 수 있음</strong></li>
</ol>

<h2 id="4-xvfb-설치-및-실행-방법">4. Xvfb 설치 및 실행 방법</h2>

<h3 id="1️⃣-xvfb-설치">1️⃣ <strong>Xvfb 설치</strong></h3>

<p>🔹 Ubuntu / Debian:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> xvfb
</code></pre></div></div>

<p>🔹 Amazon Linux / CentOS:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> xorg-x11-server-Xvfb
</code></pre></div></div>

<h3 id="2️⃣-xvfb-실행">2️⃣ <strong>Xvfb 실행</strong></h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Xvfb :99 <span class="nt">-screen</span> 0 1920x1080x24 &amp; <span class="nb">export </span><span class="nv">DISPLAY</span><span class="o">=</span>:99
</code></pre></div></div>

<p>🔹 <code class="language-plaintext highlighter-rouge">:99</code> → X 서버의 가상 디스플레이 번호
🔹 <code class="language-plaintext highlighter-rouge">1920x1080x24</code> → 해상도 및 색상 비트 설정
🔹 <code class="language-plaintext highlighter-rouge">export DISPLAY=:99</code> → Chrome이 이 가상 디스플레이를 사용하도록 설정</p>

<h3 id="3️⃣-puppeteer-실행">3️⃣ <strong>Puppeteer 실행</strong></h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xvfb-run node screen3.js
</code></pre></div></div>

<p>🔹 <code class="language-plaintext highlighter-rouge">xvfb-run</code>을 사용하면 Xvfb를 백그라운드에서 실행한 후 Puppeteer 실행</p>

<h3 id="-xvfb가-필요한-이유">🎯 <strong>Xvfb가 필요한 이유</strong></h3>

<ul>
  <li><strong>GUI 기반 프로그램(Chrome, Puppeteer 등)을 실행하기 위해 X 서버(X11)가 필요</strong></li>
  <li><strong>Linux 서버 환경에는 X 서버가 없어서 실행 불가능</strong></li>
  <li><strong>Xvfb가 가상의 X 서버 역할을 해서 Chrome 실행 가능하게 해줌</strong></li>
</ul>

<h3 id="-xvfb-없이-실행하는-방법">🎯 <strong>Xvfb 없이 실행하는 방법</strong></h3>

<ul>
  <li><strong>Puppeteer에서 완전한 헤드리스 모드(<code class="language-plaintext highlighter-rouge">headless: 'new'</code> + <code class="language-plaintext highlighter-rouge">--disable-gpu</code>) 사용</strong></li>
  <li><strong>이렇게 하면 X 서버 없이도 Puppeteer 실행 가능</strong></li>
</ul>

<p>✅ <strong>서버 환경이라면?</strong>
➡️ <strong>Xvfb를 설치하고 사용 (<code class="language-plaintext highlighter-rouge">xvfb-run node screen3.js</code>)</strong>
✅ <strong>완전한 Headless 모드 실행?</strong>
➡️ <strong>Xvfb 없이 실행 (<code class="language-plaintext highlighter-rouge">headless: 'new'</code>)</strong></p>]]></content><author><name>소우주(주)</name></author><category term="Xvfb" /><category term="puppeteer" /><category term="node" /><category term="Xvfb" /><summary type="html"><![CDATA[기본적으로 X11은 모니터, 키보드, 마우스 입력을 관리하는 역할을 한다. 🔹 Linux 데스크톱 환경(GNOME, KDE 등)은 X 서버 위에서 실행됨 🔹 Google Chrome 같은 GUI 기반 애플리케이션도 X 서버가 필요 하지만 서버 환경(Linux 서버)에서는 X 서버가 없다. 따라서, GUI 기반 프로그램(예: Chrome, Firefox 등)이 실행되지 않는다.]]></summary></entry><entry><title type="html">[ puppeteer, nodejs] Amazon 2023 에 Google Chrome 새로 수동 설치</title><link href="https://sms114.github.io/nodejs/chapter03-%EA%B5%AC%EA%B8%80%ED%81%AC%EB%A1%AC%EC%88%98%EB%8F%99%EC%84%A4%EC%B9%98/" rel="alternate" type="text/html" title="[ puppeteer, nodejs] Amazon 2023 에 Google Chrome 새로 수동 설치" /><published>2025-02-06T00:00:00+09:00</published><updated>2025-02-06T00:00:00+09:00</updated><id>https://sms114.github.io/nodejs/chapter03-%EA%B5%AC%EA%B8%80%ED%81%AC%EB%A1%AC%EC%88%98%EB%8F%99%EC%84%A4%EC%B9%98</id><content type="html" xml:base="https://sms114.github.io/nodejs/chapter03-%EA%B5%AC%EA%B8%80%ED%81%AC%EB%A1%AC%EC%88%98%EB%8F%99%EC%84%A4%EC%B9%98/"><![CDATA[<h2 id="1--chrome을-수동으로-설치하는-방법-amazon-linux-2023">1.  Chrome을 수동으로 설치하는 방법 (Amazon Linux 2023)</h2>

<p><strong>AL2023에서는 <code class="language-plaintext highlighter-rouge">dnf</code> 저장소에 <code class="language-plaintext highlighter-rouge">google-chrome-stable</code> 패키지가 없다. 해서, 그래서 직접 Google에서 최신 Chrome을 다운로드해서 설치해야 한다.</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /tmp
wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
<span class="nb">sudo </span>dnf <span class="nb">install</span> <span class="nt">-y</span> ./google-chrome-stable_current_x86_64.rpm

//설치확인
google-chrome <span class="nt">--version</span>
<span class="o">=&gt;</span> Google Chrome 133.0.6943.53


</code></pre></div></div>

<h2 id="2-puppeteer-실행할-때-executablepath-수정">2. Puppeteer 실행할 때 <code class="language-plaintext highlighter-rouge">executablePath</code> 수정</h2>

<h3 id="설치된-chrome-경로를-젇ㅇ확히--puppeteer-스크립트screen4js-에-추가해야-함">설치된 Chrome 경로를 젇ㅇ확히 ** Puppeteer 스크립트(screen4.js)** 에 추가해야 함.</h3>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer-core</span><span class="dl">'</span><span class="p">);</span>

<span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">({</span>
        <span class="na">headless</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>  <span class="c1">// 창을 띄우려면 false, 백그라운드 실행은 true</span>
        <span class="na">executablePath</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/usr/bin/google-chrome</span><span class="dl">'</span><span class="p">,</span>  <span class="c1">// 여기 Chrome 경로 설정!</span>
        <span class="na">args</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">--no-sandbox</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">--disable-setuid-sandbox</span><span class="dl">'</span><span class="p">]</span>
    <span class="p">});</span>

    <span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://www.google.com</span><span class="dl">'</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">페이지 로드 완료!</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
<span class="p">})();</span>

</code></pre></div></div>

<p>💡 만약 <code class="language-plaintext highlighter-rouge">which google-chrome</code>을 실행했는데 <code class="language-plaintext highlighter-rouge">/usr/bin/google-chrome</code>이 아니라 다른 경로가 나온다면,
그걸 <code class="language-plaintext highlighter-rouge">executablePath</code>에 넣어주면 된다.!</p>]]></content><author><name>소우주(주)</name></author><category term="nodejs" /><category term="nodejs" /><category term="Puppeteer" /><summary type="html"><![CDATA[1. Chrome을 수동으로 설치하는 방법 (Amazon Linux 2023)]]></summary></entry><entry><title type="html">[Summary-01] html, css 로 다양한 샘플 만들기</title><link href="https://sms114.github.io/wordpress/chapter03-summary-01/" rel="alternate" type="text/html" title="[Summary-01] html, css 로 다양한 샘플 만들기" /><published>2025-02-05T00:00:00+09:00</published><updated>2025-02-05T00:00:00+09:00</updated><id>https://sms114.github.io/wordpress/chapter03-summary-01</id><content type="html" xml:base="https://sms114.github.io/wordpress/chapter03-summary-01/"><![CDATA[<h2 id="vscode-에서-설치하는-extensions">VSCODE 에서 설치하는 EXTENSIONS</h2>

<p>live Server 플러그인 설치</p>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205095716685.png" alt="image-20250205095716685" /></p>

<ol>
  <li>
    <p>VSCODE 에서 NEW FILE 생성.</p>
  </li>
  <li>
    <p>본문.html 생성</p>
  </li>
  <li>! 탭 처리
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>   // html5 생성
</code></pre></div>    </div>
  </li>
  <li>
    <p>하단 오른쪽 ‘GO LIVE’  클릭</p>
  </li>
  <li><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205100545219.png" alt="image-20250205100545219" /></li>
</ol>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205100528025.png" alt="image-20250205100528025" /></p>

<p>본문.html</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"ko"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">name=</span><span class="s">"viewport"</span> <span class="na">content=</span><span class="s">"width=device-width, initial-scale=1.0"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;title&gt;</span>본문<span class="nt">&lt;/title&gt;</span>
    <span class="nt">&lt;style&gt;</span>
        <span class="nc">.style1</span> <span class="nc">.hotelbox</span><span class="p">{</span><span class="nl">border</span><span class="p">:</span><span class="nb">solid</span> <span class="m">#aaa</span> <span class="m">10px</span><span class="p">;</span><span class="nl">padding</span><span class="p">:</span><span class="m">20px</span><span class="p">;</span><span class="nl">margin-bottom</span><span class="p">:</span><span class="m">30px</span> <span class="p">;}</span>
        <span class="nc">.style1</span> <span class="nt">img</span><span class="p">{</span><span class="nl">width</span><span class="p">:</span><span class="m">600px</span><span class="p">;</span><span class="nl">height</span><span class="p">:</span><span class="nb">auto</span><span class="p">;}</span>
        <span class="nc">.style1</span> <span class="nt">h1</span><span class="p">{</span><span class="nl">text-align</span><span class="p">:</span><span class="nb">center</span><span class="p">;</span><span class="nl">font-size</span><span class="p">:</span><span class="m">35px</span><span class="p">;</span><span class="nl">color</span><span class="p">:</span><span class="m">#3d02c9</span><span class="p">}</span>
        <span class="nc">.style1</span> <span class="nt">p</span><span class="p">{</span><span class="nl">text-align</span><span class="p">:</span><span class="nb">center</span><span class="p">;}</span>
        <span class="nc">.style1</span> <span class="nt">h3</span><span class="p">{</span><span class="nl">color</span><span class="p">:</span><span class="nb">rgb</span><span class="p">(</span><span class="m">2</span><span class="p">,</span> <span class="m">22</span><span class="p">,</span> <span class="m">201</span><span class="p">);</span><span class="nl">font-size</span><span class="p">:</span> <span class="m">30px</span><span class="p">;}</span>
        <span class="nc">.style1</span> <span class="nt">h5</span><span class="p">{</span><span class="nl">font-size</span><span class="p">:</span><span class="m">16px</span><span class="p">;}</span>
        <span class="nc">.style1</span><span class="p">{</span><span class="nl">font-size</span><span class="p">:</span><span class="m">14px</span><span class="p">;}</span>

    <span class="nt">&lt;/style&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"style1"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;h1&gt;</span>큰제목 - 홍콩의 가성비 좋은 고급호텔 top5<span class="nt">&lt;/h1&gt;</span>
        <span class="nt">&lt;p&gt;</span>인사말 안녕하세요. 날씨가 좋네요<span class="nt">&lt;/p&gt;</span>
        <span class="nt">&lt;br&gt;&lt;br&gt;&lt;br&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"hotelbox"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h3&gt;</span>중제목 - 호텔명<span class="nt">&lt;/h3&gt;</span>
            <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://q-xx.bstatic.com/xdata/images/hotel/max1024x768/95628270.jpg?k=757503ac22849096d9d5c5a6f97fa897ac8c979e55197fa0c18f3d32f355382f&amp;o=&amp;s=1024x"</span> <span class="na">alt=</span><span class="s">"이미지의 설명"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;p&gt;</span>호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.<span class="nt">&lt;/p&gt;</span>
            <span class="nt">&lt;h5&gt;</span>소제목 - 주위 가볼만한 곳<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span> 
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>

            <span class="nt">&lt;h5&gt;</span>소제목 - 호텔 시설, 특징, 교통<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"hotelbox"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h3&gt;</span>중제목 - 호텔명<span class="nt">&lt;/h3&gt;</span>
            <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/hotelImages/6362202/0/b79106a8152061339505252638b5b6c0.jpg?ca=9&amp;ce=1&amp;s=1024x"</span> <span class="na">alt=</span><span class="s">"이미지의 설명"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;p&gt;</span>호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.<span class="nt">&lt;/p&gt;</span>
            <span class="nt">&lt;h5&gt;</span>소제목 - 주위 가볼만한 곳<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>

            <span class="nt">&lt;h5&gt;</span>소제목 - 호텔 시설, 특징, 교통<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"hotelbox"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h3&gt;</span>중제목 - 호텔명<span class="nt">&lt;/h3&gt;</span>
            <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/22879516/766855982/0d0ef4a797b8d0ff7289fd1f7c0490b9.jpeg?ce=0&amp;s=1024x"</span> <span class="na">alt=</span><span class="s">"이미지의 설명"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;p&gt;</span>호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.<span class="nt">&lt;/p&gt;</span>
            <span class="nt">&lt;h5&gt;</span>소제목 - 주위 가볼만한 곳<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>

            <span class="nt">&lt;h5&gt;</span>소제목 - 호텔 시설, 특징, 교통<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"hotelbox"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h3&gt;</span>중제목 - 호텔명<span class="nt">&lt;/h3&gt;</span>
            <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/22879516/766855982/0d0ef4a797b8d0ff7289fd1f7c0490b9.jpeg?ce=0&amp;s=1024x"</span> <span class="na">alt=</span><span class="s">"이미지의 설명"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;p&gt;</span>호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.<span class="nt">&lt;/p&gt;</span>
            <span class="nt">&lt;h5&gt;</span>소제목 - 주위 가볼만한 곳<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>

            <span class="nt">&lt;h5&gt;</span>소제목 - 호텔 시설, 특징, 교통<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"hotelbox"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h3&gt;</span>중제목 - 호텔명<span class="nt">&lt;/h3&gt;</span>
            <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/22879516/766855982/0d0ef4a797b8d0ff7289fd1f7c0490b9.jpeg?ce=0&amp;s=1024x"</span> <span class="na">alt=</span><span class="s">"이미지의 설명"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;p&gt;</span>호텔설명 좋은 호텔입니다. 진짜 좋은 호텔입니다.<span class="nt">&lt;/p&gt;</span>
            <span class="nt">&lt;h5&gt;</span>소제목 - 주위 가볼만한 곳<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>

            <span class="nt">&lt;h5&gt;</span>소제목 - 호텔 시설, 특징, 교통<span class="nt">&lt;/h5&gt;</span>
            <span class="nt">&lt;ul&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
                <span class="nt">&lt;li&gt;</span>항목 - 장소<span class="nt">&lt;/li&gt;</span>
            <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<h3 id="이미지-html-에-익숙해-지기-위한-방법">이미지 html 에 익숙해 지기 위한 방법</h3>

<h4 id="예제1">예제1</h4>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205211922823.png" alt="image-20250205211922823" /></p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">"width:500px;height:400px;position:relative;overflow:idden;"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:49%;height:200px;bottom:0;right:0px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/hotelImages/686641/-1/f16ce90659bbdaac260cfbb759241021.png?ce=0&amp;s=800x"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:49%;height:200px;top:100px;bottom:100px;right:100px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/24074586/452498572/f47c582061edc91538aea9c0ed996b74.jpg?ca=23&amp;ce=0&amp;s=1024x"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:49%;height:200px;bottom:0;right:0px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/hotelImages/686641/-1/f16ce90659bbdaac260cfbb759241021.png?ce=0&amp;s=800x"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:49%;height:200px;top:100px;bottom:100px;right:100px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/24074586/452498572/f47c582061edc91538aea9c0ed996b74.jpg?ca=23&amp;ce=0&amp;s=1024x"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<h4 id="예제2">예제2</h4>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205212039576.png" alt="image-20250205212039576" /></p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">"width:500px;height:400px;position:relative;"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:70%;height:auto;position:absolute;top:0;left:0px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/60959266/0/32eb716488b029fbb52a8382bc662b3c.jpeg?ce=0&amp;s=600x"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:70%;height:auto;position:absolute;bottom:0;right:0px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/hotelImages/686641/-1/f16ce90659bbdaac260cfbb759241021.png?ce=0&amp;s=800x"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width:70%;height:auto;position:absolute;top:100px;bottom:100px;right:100px;"</span> <span class="na">src=</span><span class="s">"https://pix8.agoda.net/property/24074586/452498572/f47c582061edc91538aea9c0ed996b74.jpg?ca=23&amp;ce=0&amp;s=1024x"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<h4 id="예3">예3</h4>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205212108397.png" alt="image-20250205212108397" /></p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">"position:relative;width:100%;height:250px;
    background:url(https://pix8.agoda.net/property/24074586/452498572/f47c582061edc91538aea9c0ed996b74.jpg?ca=23&amp;ce=0&amp;s=1024x);
    background-size:cover;
    background-position: 50%;
    color: #fff;
    font-size:20px;
    font-weight:bold;
    "</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">"position:absolute;
        z-index:2;
        color:#fff;
        width:100%;
        text-align:center;
        top:100px;
        font-size:20px;
        font-weight:bold;"</span><span class="nt">&gt;</span>
            럭셔리한 아름다운 콘래드 호텔 로비
        <span class="nt">&lt;/div&gt;</span>
        
        <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">"position:absolute;
            z-index:1;
            top:0px;
            left:0px;
            width:100%;
            height:250px;
            background:rgba(0,0,0,0.5)"</span><span class="nt">&gt;</span>

        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<h4 id="예4">예4</h4>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205212239694.png" alt="image-20250205212239694" /></p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"img6"</span> <span class="na">style=</span><span class="s">"width:350px;height:350px;
        background:url(https://pix8.agoda.net/hotelImages/297968/-1/44236157a18c8243a66e557193355bd7.jpg?ce=0&amp;s=1024x);
        border-radius:50%;
        background-position:50%;
        background-size:30cm;
        text-align:center;
        padding-top:150px;
        box-sizing:border-box;
        font-size:26px;
        color: #fff;
        font-weight: bold;
        text-shadow: 2px 2px 2px #000;"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div&gt;</span>
            럭셔리한 콘래드 마카오 후기2222
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>   
</code></pre></div></div>

<h4 id="예5">예5</h4>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205212356893.png" alt="image-20250205212356893" /></p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nt">&lt;style&gt;</span>
        <span class="nt">html</span><span class="p">{</span><span class="nl">box-sizing</span><span class="p">:</span> <span class="n">border-box</span><span class="p">;}</span>
        <span class="nc">.img5</span> <span class="p">{</span>
    <span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span>
    <span class="nl">height</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span> <span class="c">/* 원형을 유지하려면 width = height */</span>
    <span class="nl">background</span><span class="p">:</span> <span class="sx">url(https://pix8.agoda.net/hotelImages/297968/-1/44236157a18c8243a66e557193355bd7.jpg?ce=0&amp;s=1024x)</span><span class="p">;</span>
    <span class="nl">background-position</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
    <span class="nl">background-size</span><span class="p">:</span> <span class="n">cover</span><span class="p">;</span>
    <span class="nl">border-radius</span><span class="p">:</span> <span class="m">50%</span><span class="p">;</span>
    <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="c">/* flexbox 사용 */</span>
    <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="c">/* 세로 중앙 정렬 */</span>
    <span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="c">/* 가로 중앙 정렬 */</span>
    <span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
    <span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span> <span class="c">/* 가독성을 위해 텍스트 색상 추가 */</span>
    <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
    <span class="nl">font-size</span><span class="p">:</span> <span class="m">16px</span><span class="p">;</span>
    <span class="nl">text-shadow</span><span class="p">:</span> <span class="m">1px</span> <span class="m">1px</span> <span class="m">5px</span> <span class="n">rgba</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">0</span><span class="p">,</span><span class="m">0.5</span><span class="p">);</span> <span class="c">/* 텍스트 가독성 향상 */</span>
<span class="p">}</span>

    <span class="nt">&lt;/style&gt;</span>


    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"img5"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div&gt;</span>
            럭셔리한 콘래드 마카오 후기 1111
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>


</code></pre></div></div>

<blockquote>
  <p><strong>이후, 유니크한 이미지 생성을 위해 “노드 스크린샷 캡쳐” 를 통해 .png 파일을 내려 받기 한 후, 해당 이미지를 사용한다.</strong></p>

</blockquote>

<p><img src="/../../images/2025-02-05-chapter03-summary-01/image-20250205212425936.png" alt="image-20250205212425936" /><a href=""></a></p>]]></content><author><name>소우주(주)</name></author><category term="wordpress" /><category term="wordpress" /><summary type="html"><![CDATA[VSCODE 에서 설치하는 EXTENSIONS]]></summary></entry><entry><title type="html">[문자발송] 쉽고 빠른 문자 발송, 지금 시작하세요!</title><link href="https://sms114.github.io/%EB%AC%B8%EC%9E%90%EB%B0%9C%EC%86%A1/message-hongbo-080002/" rel="alternate" type="text/html" title="[문자발송] 쉽고 빠른 문자 발송, 지금 시작하세요!" /><published>2025-02-02T00:00:00+09:00</published><updated>2025-02-02T00:00:00+09:00</updated><id>https://sms114.github.io/%EB%AC%B8%EC%9E%90%EB%B0%9C%EC%86%A1/message-hongbo-080002</id><content type="html" xml:base="https://sms114.github.io/%EB%AC%B8%EC%9E%90%EB%B0%9C%EC%86%A1/message-hongbo-080002/"><![CDATA[<p><img src="https://pixabay.com/get/gcd65e60a85758b9211b9b10d0da042d9ec64d8cca1864c50662e83314cc56f3f7708597cd3e25d55fdfb6e3608fcc5017e21166ef306b07b28771e92e1bca069_640.jpg" alt="대표 이미지" /> 출처: Pixabay <!-- Markdown 이미지 삽입 --></p>

<h3 id="와우-어머나-오늘은-정말-멋진-정보를-들려줄게-들었던-정보로-말하자면-가성비-좋고-사용하기-쉬운-문자-발송-사이트가-있다고-하더라구-그게-바로-sms114cokr-이야-진짜진짜-간편하게-문자-발송을-할-수-있는-사이트라고-하더라구">와우, 어머나! 오늘은 정말 멋진 정보를 들려줄게! 들었던 정보로 말하자면, 가성비 좋고 사용하기 쉬운 문자 발송 사이트가 있다고 하더라구! 그게 바로 sms114.co.kr 이야. 진짜진짜 간편하게 문자 발송을 할 수 있는 사이트라고 하더라구.</h3>

<h4 id="이거-알아-sms114cokr은-치환문자-단체문자-광고문자-선거문자-등-다양한-종류의-문자를-보낼-수-있어-그리고-엑셀로-주소록을-간편하게-등록할-수-있어서-정말-편리하대">이거 알아? sms114.co.kr은 치환문자, 단체문자, 광고문자, 선거문자 등 다양한 종류의 문자를 보낼 수 있어. 그리고 엑셀로 주소록을 간편하게 등록할 수 있어서 정말 편리하대!</h4>

<p>이거 아시나요? 가격 정책도 가끔 올라간다던데, 가격은 단문이 10원, 장문이 27원이래. 그래서 가성비가 정말 좋다고 하더라구!</p>

<h3 id="얼마-전에-sms114cokr을-이용해서-신년문자를-보냈는데-받는-사람들이-정말-좋아했어-감사답례-인사-부고조문-동창회모임-안내-이벤트행사초대장-선거문자-등-다양한-종류의-문자를-보낼-수-있어서-정말-편리했어">얼마 전에 sms114.co.kr을 이용해서 신년문자를 보냈는데, 받는 사람들이 정말 좋아했어! 감사/답례 인사, 부고/조문, 동창회/모임 안내, 이벤트/행사/초대장, 선거문자 등 다양한 종류의 문자를 보낼 수 있어서 정말 편리했어.</h3>

<h4 id="그리고-이모지를-넣을-수-있어서-더욱-다양한-표현이-가능하다고-하더라구-">그리고 이모지를 넣을 수 있어서 더욱 다양한 표현이 가능하다고 하더라구! 😊🎉📱</h4>

<p>어휴, 정말 편리한 서비스인 것 같아. sms114.co.kr을 이용하면 누구나 손쉽게 문자 발송을 할 수 있으니까, 꼭 한 번 이용해봐야겠어! 후아, 정말 편리하고 간편한 서비스를 제공하는 sms114.co.kr을 이용해보면 정말 대만족할 거야.</p>

<h3 id="그래서-여러분들도-sms114cokr을-이용해서-다양한-메시지를-보내보면-어때-진짜로-쉽고-편리해서-꼭-한-번-경험해봐야-할-것-같아-오예-이제는-sms114cokr을-이용해서-다양한-메시지를-손쉽게-보내보세요-그럼-행복한-문자-송신되길-바래ㅋㅋㅋ">그래서, 여러분들도 sms114.co.kr을 이용해서 다양한 메시지를 보내보면 어때? 진짜로 쉽고 편리해서 꼭 한 번 경험해봐야 할 것 같아! 오예, 이제는 sms114.co.kr을 이용해서 다양한 메시지를 손쉽게 보내보세요. 그럼, 행복한 문자 송신되길 바래!ㅋㅋㅋ</h3>]]></content><author><name>소우주(주)</name></author><category term="문자발송" /><category term="문자발송" /><summary type="html"><![CDATA[출처: Pixabay]]></summary></entry><entry><title type="html">[문자발송] 문자 예약 발송으로 효율성 극대화!</title><link href="https://sms114.github.io/%EB%AC%B8%EC%9E%90%EB%B0%9C%EC%86%A1/message-hongbo-080002/" rel="alternate" type="text/html" title="[문자발송] 문자 예약 발송으로 효율성 극대화!" /><published>2025-02-01T00:00:00+09:00</published><updated>2025-02-01T00:00:00+09:00</updated><id>https://sms114.github.io/%EB%AC%B8%EC%9E%90%EB%B0%9C%EC%86%A1/message-hongbo-080002</id><content type="html" xml:base="https://sms114.github.io/%EB%AC%B8%EC%9E%90%EB%B0%9C%EC%86%A1/message-hongbo-080002/"><![CDATA[<p><img src="https://pixabay.com/get/gd880e9c1c20c772e419e85c580e1e0bda4b09cd9d4e6073fa5eba11fdd1a4f4e6c3fe7b95b0248ca8419287ee8fb3f30788b5fbc46b6d3654e2808b1aafb9e0b_640.jpg" alt="대표 이미지" /> 출처: Pixabay <!-- Markdown 이미지 삽입 --></p>

<h3 id="와우-어서오세요-">와우, 어서오세요! 🌟</h3>

<h4 id="여러분들을-위해-최고의-문자-발송-사이트를-소개할게요-바로-sms114cokr-">여러분들을 위해 최고의 문자 발송 사이트를 소개할게요. 바로 sms114.co.kr! 📱</h4>

<p>이 사이트는 가성비가 정말 대박이에요. 가격 정책도 가끔 올려주면서도, 단문은 10원, 장문은 27원으로 정말 합리적이에요. 😲</p>

<h3 id="사용하기도-정말-쉬워요-엑셀로-주소록을-간편하게-등록하고-예약-발송도-손쉽게-할-수-있어요-이렇게-편리한-기능들이-있어서-진짜진짜-편리하답니다-">사용하기도 정말 쉬워요. 엑셀로 주소록을 간편하게 등록하고, 예약 발송도 손쉽게 할 수 있어요. 이렇게 편리한 기능들이 있어서 진짜진짜 편리하답니다. 😁</h3>

<h4 id="그리고-다양한-문자-종류도-지원해요-감사답례-인사-부고조문-동창회모임-안내-이벤트행사초대장-선거문자까지-어떤-상황에도-적합한-메시지를-보낼-수-있어요-">그리고 다양한 문자 종류도 지원해요. 감사/답례 인사, 부고/조문, 동창회/모임 안내, 이벤트/행사/초대장, 선거문자까지! 어떤 상황에도 적합한 메시지를 보낼 수 있어요. 💌</h4>

<p>아, 그리고 sms114.co.kr은 치환문자도 가능하답니다. 개인별로 다른 내용을 보내고 싶을 때 정말 유용하죠. 😊</p>

<h3 id="또한-주소록-관리도-편리하게-할-수-있고-문자연동도-가능해요-이렇게-다양한-기능들을-제공하면서도-가격은-합리적이라니-정말-대단해요-">또한, 주소록 관리도 편리하게 할 수 있고, 문자연동도 가능해요. 이렇게 다양한 기능들을 제공하면서도, 가격은 합리적이라니 정말 대단해요! 😎</h3>

<h4 id="신년문자-발송-신년인사도-손쉽게-할-수-있어요-이제는-sms114cokr이-없으면-안된다고-하네요-">신년문자 발송, 신년인사도 손쉽게 할 수 있어요. 이제는 sms114.co.kr이 없으면 안된다고 하네요~ 😄</h4>

<p>그러니까, 어서 sms114.co.kr로 들어가서 가성비 좋은 문자 발송 서비스를 경험해보세요! 후아, 정말 편리하고 효율적일 거예요. 🚀</p>

<h3 id="그럼-이만큼으로-sms114cokr을-소개해드렸어요-궁금한-점이-있으시면-언제든지-물어봐주세요--ㅋㅋㅋ">그럼 이만큼으로 sms114.co.kr을 소개해드렸어요. 궁금한 점이 있으시면 언제든지 물어봐주세요! 😉 ㅋㅋㅋ</h3>]]></content><author><name>소우주(주)</name></author><category term="문자발송" /><category term="문자발송" /><summary type="html"><![CDATA[출처: Pixabay]]></summary></entry></feed>