<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yena-lena.log</title>
        <link>https://velog.io/</link>
        <description>Be curious</description>
        <lastBuildDate>Sat, 23 Sep 2023 09:14:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yena-lena.log</title>
            <url>https://images.velog.io/images/yena-lena/profile/d76ba823-8d5c-4a88-b532-9b74acf570a2/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yena-lena.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yena-lena" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Flutter] svg의 객체가 표시되지 않는 경우 해결법 (그라데이션, 마스킹)]]></title>
            <link>https://velog.io/@yena-lena/Flutter-svg%EC%9D%98-%EA%B0%9D%EC%B2%B4%EA%B0%80-%ED%91%9C%EC%8B%9C%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EA%B2%BD%EC%9A%B0-%EA%B7%B8%EB%9D%BC%EB%8D%B0%EC%9D%B4%EC%85%98-%EB%A7%88%EC%8A%A4%ED%82%B9</link>
            <guid>https://velog.io/@yena-lena/Flutter-svg%EC%9D%98-%EA%B0%9D%EC%B2%B4%EA%B0%80-%ED%91%9C%EC%8B%9C%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EA%B2%BD%EC%9A%B0-%EA%B7%B8%EB%9D%BC%EB%8D%B0%EC%9D%B4%EC%85%98-%EB%A7%88%EC%8A%A4%ED%82%B9</guid>
            <pubDate>Sat, 23 Sep 2023 09:14:54 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-상황">문제 상황</h3>
<p>SVG 디자인 에셋을 사용하면서 path가 튀거나, 그라데이션이 적용되지 않는 경우가 종종 있었습니다.
그전에는 그냥 png 파일로 추출해서 사용했는데, 원인을 알아보기 위해 한번 구글링을 해보니 바로 해결책을 찾아 정리를 하겠습니다.</p>
<h3 id="해결">해결</h3>
<p>참고 블로그 : <a href="https://velog.io/@qkrtnfks128/flutter-svg-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B7%B8%EB%9D%BC%EB%8D%B0%EC%9D%B4%EC%85%98-%EC%83%89%EC%9D%B4-%EC%95%88%EB%82%98%EC%98%AC%EB%95%8C">Flutter svg 이미지 그라데이션 색이 안나올때</a></p>
<p>요약하자면, svg를 열었을 때 <code>&lt;defs&gt;</code> 태그를 <code>&lt;svg&gt;</code>태그 바로 아래로 수정하면 된다는 것입니다.</p>
<blockquote>
<p>defs 태그는 그라데이션, 마스킹 및 패턴과 같은 SVG 속성을 정의하는데 사용되는 태그</p>
</blockquote>
<h3 id="적용-예시">적용 예시</h3>
<p>svg 파일을 직접 열어 아래와 같이 <code>&lt;defs&gt; ~ &lt;/defs&gt;</code> 를 두번째줄로 옮기니 제대로 표시가 되었습니다. 😆</p>
<p><img src="https://velog.velcdn.com/images/yena-lena/post/ad6dce2a-a47a-48e1-a652-fb9a6464917a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] GetX Navigation 화면이동]]></title>
            <link>https://velog.io/@yena-lena/GetX-Navigation-%ED%99%94%EB%A9%B4%EC%9D%B4%EB%8F%99</link>
            <guid>https://velog.io/@yena-lena/GetX-Navigation-%ED%99%94%EB%A9%B4%EC%9D%B4%EB%8F%99</guid>
            <pubDate>Tue, 19 Sep 2023 12:09:27 GMT</pubDate>
            <description><![CDATA[<p>GetX를 사용하면 Flutter 앱에서 화면 간 이동을 간편하게 처리할 수 있다. GetX에서 제공하는 화면 이동 메소드를 정리한다.</p>
<h3 id="패키지-설치">패키지 설치</h3>
<p><code>$ flutter pub add get</code></p>
<h3 id="화면을-스택에-추가하면서-이동">화면을 스택에 추가하면서 이동</h3>
<p><code>Get.to(() =&gt; const MainScreen());</code>
<code>Get.toNamed(&#39;/MainScreen&#39;));</code></p>
<h3 id="화면을-스택에서-제거하면서-이동">화면을 스택에서 제거하면서 이동</h3>
<p>현재 화면을 제거하고 새로운 화면으로 이동
<code>Get.off(() =&gt; const MainScreen());</code>
<code>Get.offNamed(&quot;/MainScreen&quot;)</code></p>
<p>모든 화면을 제거하면서 이동
<code>Get.offAll(MainScreen());</code></p>
<p>특정 조건을 만족하는 화면까지 스택에서 화면을 제거하면서 이동
<code>Get.until((route) =&gt; Get.currentRoute == &#39;/home&#39;); //홈 화면까지 제거하면서 이동</code>
<code>Get.offUntil(GetPageRoute(page: () =&gt; const MainScreen()),
      ModalRoute.withName(&#39;/profile&#39;));</code></p>
<p> 메인화면까지 이동하고 profile 화면 표시
<code>Get.offNamedUntil(&#39;/MainScreen&#39;, ModalRoute.withName(&#39;/profile&#39;));</code></p>
<h3 id="기타">기타</h3>
<p>다이얼로그가 닫힐때까지 화면 이동
<code>Get.until((route) =&gt; !Get.isDialogOpen!);</code>
<code>Get.offNamedUntil(&quot;/home&quot;, (route) =&gt; Get.isOverlaysClosed);</code></p>
<h2 id="사용-예제">사용 예제</h2>
<pre><code class="language-dart">void navigateScreen() {
    Get.to(() =&gt; const MainScreen());
    Get.toNamed(&quot;/MainScreen&quot;);

    Get.off(() =&gt; const MainScreen());
        Get.offAll(MainScreen());
    Get.offNamed(&quot;/MainScreen&quot;)
    Get.until((route) =&gt; Get.currentRoute == &#39;/home&#39;);
        Get.offUntil(
      GetPageRoute(page: () =&gt; const MainScreen()), // 조건: 메인 화면까지 이동
      ModalRoute.withName(&#39;/profile&#39;), // 메인화면까지 이동 후 profile 화면 표시
    );
    Get.offNamedUntil(&#39;/MainScreen&#39;, ModalRoute.withName(&#39;/profile&#39;));


    // 기타
    // 다이얼로그가 닫힐때까지 화면 이동
    Get.until((route) =&gt; !Get.isDialogOpen!); 
    Get.offNamedUntil(&quot;/home&quot;, (route) =&gt; Get.isOverlaysClosed); // overlay = snackbar, dialog, bottomsheet
  }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] 하단 모달시트가 스크롤되는 위젯 DraggableScrollableSheetScreen]]></title>
            <link>https://velog.io/@yena-lena/Flutter-%ED%95%98%EB%8B%A8-%EB%AA%A8%EB%8B%AC%EC%8B%9C%ED%8A%B8%EA%B0%80-%EC%8A%A4%ED%81%AC%EB%A1%A4%EB%90%98%EB%8A%94-%EC%9C%84%EC%A0%AF-DraggableScrollableSheetScreen</link>
            <guid>https://velog.io/@yena-lena/Flutter-%ED%95%98%EB%8B%A8-%EB%AA%A8%EB%8B%AC%EC%8B%9C%ED%8A%B8%EA%B0%80-%EC%8A%A4%ED%81%AC%EB%A1%A4%EB%90%98%EB%8A%94-%EC%9C%84%EC%A0%AF-DraggableScrollableSheetScreen</guid>
            <pubDate>Sun, 10 Sep 2023 10:18:42 GMT</pubDate>
            <description><![CDATA[<p><code>DraggableScrollableSheet</code> 위젯을 사용하면 하단 모달시트가 스크롤되는 위젯을 만들 수 있다. 주로 지도앱에서 하단 정보를 담은 시트를 만들 때 사용한다.</p>
<p>DraggableScrollableSheet를 Stack으로 감싸서 사용할 수 있다.</p>
<h4 id="구글-지도-예시">구글 지도 예시</h4>
<img src="https://velog.velcdn.com/images/yena-lena/post/755d65b8-021e-4b85-a437-da903a20f4da/image.jpg" width="40%">


<h3 id="👉-구현">👉 구현</h3>
<p>DraggableScrollableSheet을 사용해 실제로 구현한 화면이다.
<img src="https://velog.velcdn.com/images/yena-lena/post/7c08d8c5-d8bc-4d14-b8cf-1f6b151ea446/image.png" width="40%"> </p>
<p><code>initialChlidSize</code> - 처음 높이를 설정. 부모 위젯의 비율로 조정된다.
<code>minChildSize</code>, <code>maxChildSize</code> - 콘텐츠가 표시되는 영역을 설정. </p>
<p>사용자가 드래그 하는 만큼 콘텐츠를 표시할 수 있고 ScrollController를 사용하면 더 디테일하게 설정할 수 있다.</p>
<p>사용자가 드래그 중 손을 뗄 때 위젯이 특정 크기로 스냅되도록 하려면 <code>snap</code>을 true로 설정한다.</p>
<pre><code class="language-dart">DefaultLayout(
      title: &quot;DraggableScrollableSheetScreen&quot;,
      body: Stack(
        children: [
          Container(
            color: Colors.white,
            child: Text(&quot;지도&quot;),
          ),
          DraggableScrollableSheet(
            // 화면 비율로 높이 조정
            initialChildSize: 0.4,
            minChildSize: 0.4,
            maxChildSize: 1.0,
            builder: (BuildContext context, ScrollController scrollController) {
              return SingleChildScrollView(
                controller: scrollController,
                child: Container(
                    height: 1500,
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(20),
                            topRight: Radius.circular(20)),
                        color: Colors.purpleAccent),
                    child: _buildCustomBottomSheet()),
              );
            },
          )
        ],
      ),
    );</code></pre>
<h3 id="reference">Reference</h3>
<p><a href="https://api.flutter.dev/flutter/widgets/DraggableScrollableSheet-class.html">https://api.flutter.dev/flutter/widgets/DraggableScrollableSheet-class.html</a>
<a href="https://stackoverflow.com/questions/52403709/partially-viewable-bottom-sheet-flutter">https://stackoverflow.com/questions/52403709/partially-viewable-bottom-sheet-flutter</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[포켓위키 개인정보처리방침]]></title>
            <link>https://velog.io/@yena-lena/%ED%8F%AC%EC%BC%93%EC%9C%84%ED%82%A4-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8</link>
            <guid>https://velog.io/@yena-lena/%ED%8F%AC%EC%BC%93%EC%9C%84%ED%82%A4-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8</guid>
            <pubDate>Tue, 09 May 2023 00:13:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yena-lena/post/7f3602f1-73d9-4a0c-b943-c3803eca7a66/image.png" alt=""></p>
<h3 id="개인정보처리방침">개인정보처리방침</h3>
<p>개인정보의 수집
당사는 개인정보를 수집하지 않습니다.</p>
<p>개인정보의 이용
당사는 개인정보를 수집하지 않으므로 이용에 관련된 내용은 없습니다.</p>
<p>개인정보의 제공
당사는 개인정보를 수집하지 않으므로 제공에 관련된 내용은 없습니다.</p>
<p>개인정보의 보유 및 이용기간
당사는 개인정보를 수집하지 않으므로 보유 및 이용 기간에 관련된 내용은 없습니다.</p>
<p>개인정보의 파기
당사는 개인정보를 수집하지 않으므로 파기에 관련된 내용은 없습니다.</p>
<p>개인정보 관리책임자
당사는 개인정보를 수집하지 않으므로 개인정보 관리책임자에 대한 내용은 없습니다.</p>
<p>개인정보 보호책임자
당사는 개인정보를 수집하지 않으므로 개인정보 보호책임자에 대한 내용은 없습니다.</p>
<p>개인정보 보호 관련 민원서비스
당사는 개인정보를 수집하지 않으므로 개인정보 보호 관련 민원서비스에 대한 내용은 없습니다.</p>
<p>개인정보 처리방침 변경
본 방침은 법령, 정책 및 보안기술의 변경에 따라 변경될 수 있습니다. 변경 시 이 페이지를 통해 사전 공지할 것입니다.</p>
<p>contact ✉️ <a href="mailto:dpsk2880@gmail.com">dpsk2880@gmail.com</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[쏭쏭이 개인정보처리방침]]></title>
            <link>https://velog.io/@yena-lena/%EC%8F%AD%EC%8F%AD%EC%9D%B4-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8</link>
            <guid>https://velog.io/@yena-lena/%EC%8F%AD%EC%8F%AD%EC%9D%B4-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8</guid>
            <pubDate>Sun, 09 Apr 2023 11:02:17 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>개인정보의 수집
당사는 개인정보를 수집하지 않습니다.</p>
</li>
<li><p>개인정보의 이용
당사는 개인정보를 수집하지 않으므로 이용에 관련된 내용은 없습니다.</p>
</li>
<li><p>개인정보의 제공
당사는 개인정보를 수집하지 않으므로 제공에 관련된 내용은 없습니다.</p>
</li>
<li><p>개인정보의 보유 및 이용기간
당사는 개인정보를 수집하지 않으므로 보유 및 이용 기간에 관련된 내용은 없습니다.</p>
</li>
<li><p>개인정보의 파기
당사는 개인정보를 수집하지 않으므로 파기에 관련된 내용은 없습니다.</p>
</li>
<li><p>개인정보 관리책임자
당사는 개인정보를 수집하지 않으므로 개인정보 관리책임자에 대한 내용은 없습니다.</p>
</li>
<li><p>개인정보 보호책임자
당사는 개인정보를 수집하지 않으므로 개인정보 보호책임자에 대한 내용은 없습니다.</p>
</li>
<li><p>개인정보 보호 관련 민원서비스
당사는 개인정보를 수집하지 않으므로 개인정보 보호 관련 민원서비스에 대한 내용은 없습니다.</p>
</li>
<li><p>개인정보 처리방침 변경
본 방침은 법령, 정책 및 보안기술의 변경에 따라 변경될 수 있습니다. 변경 시 이 페이지를 통해 사전 공지할 것입니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[하나의 PC에서 GitHub 여러개 계정 사용하기]]></title>
            <link>https://velog.io/@yena-lena/%ED%95%98%EB%82%98%EC%9D%98-PC%EC%97%90%EC%84%9C-GitHub-%EC%97%AC%EB%9F%AC%EA%B0%9C-%EA%B3%84%EC%A0%95-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yena-lena/%ED%95%98%EB%82%98%EC%9D%98-PC%EC%97%90%EC%84%9C-GitHub-%EC%97%AC%EB%9F%AC%EA%B0%9C-%EA%B3%84%EC%A0%95-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 07 Apr 2022 23:04:19 GMT</pubDate>
            <description><![CDATA[<p>기존에는 GitHub Desktop을 사용해서 그날그날 공부한걸 정리해서 커밋해 두었는데... 
회사 깃허브 계정이 생기고서 기존에 사용하던 계정에 로그인하는게 번거로워서 로컬에 쌓아두고 있었다</p>
<p>뭔가 방법이 없을까하고 구글링을 하던 중에 ssh key를 사용해 한 개의 컴퓨터에서 여러개의 깃허브 계정을 사용할 수 있다고해서 차근차근 정리를 해본다</p>
<p>👉 기본 원리는 <strong>한 개의 컴퓨터</strong>에서 두 개의 ssh key를 생성하고 하나는 개인 계정, 하나는 회사 계정에 연결해 사용하는 것이다</p>
<h3 id="set-up">Set Up</h3>
<p>두 개의 깃허브 계정을 준비한다
(🦋:개인계정, 🐝: 회사계정) </p>
<pre><code>무슨생각으로 계정 이름을 지었는지 알 수 없지만... 정말 헷갈리게 대충 지었다
깃허브에 연동된 이메일은 Setting → Emails 에서 확인 할 수 있다</code></pre><p>우선 ssh key는 ~/.ssh 폴더안에서 생성되어야해서 <code>cd ~/.ssh</code> 명령어를 통해 이동해준다</p>
<h3 id="ssh-key-생성하기">SSH Key 생성하기</h3>
<p>다음 명령어를 통해 ssh key를 생성한다
계정이름은 구분하기위한 용도라서 아무렇게나 설정해도 된다</p>
<pre><code class="language-shell">ssh-keygen -t rsa -C &quot;계정@gmail.com&quot; -f &quot;계정이름&quot;

## example
🦋 ssh-keygen -t rsa -C &quot;lena@gmail.com&quot; -f &quot;id_rsa_personal&quot;
🐝 ssh-keygen -t rsa -C &quot;lena@회사계정.com&quot; -f &quot;id_rsa_corp&quot;</code></pre>
<p>명령어를 입력하면 아래와 같은 문구가 나오면서 비밀번호를 설정할 수 있지만 그냥 빈칸으로 엔터를 쳐서 넘어간다</p>
<pre><code>Enter passphrase (empty for no passphrase):
Enter same passphrase again:</code></pre><p>완료되면 다음과 같은 문구가 나온다
<img src="https://velog.velcdn.com/cloudflare/yena-lena/abfde505-21eb-4dfc-8cf9-a9c94e5af2b6/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202022-04-08%20%EC%98%A4%EC%A0%84%207.45.42.png" width=60%></p>
<p><code>ls ~/.ssh</code> 명령어를 통해 생성되었는지 파악할 수 있다
생성되었다면 계정이름으로 된 파일과 계정이름.pub 파일을 각각 확인 할 수 있다</p>
<h3 id="ssh-key-등록하기">SSH Key 등록하기</h3>
<p>위에서 생성한 계정이름을 통해 SSH Key를 등록해준다</p>
<pre><code class="language-shell">ssh-add 계정이름

🦋 ssh-add id_rsa_personal
🐝 ssh-add id_rsa_corp</code></pre>
<p>이렇게 하면 ssh key가 등록된다</p>
<h3 id="ssh-key-확인하기">SSH Key 확인하기</h3>
<pre><code class="language-shell">cat ~/.ssh/{계정이름}.pub</code></pre>
<h3 id="ssh-key-적용하기">SSH Key 적용하기</h3>
<p>Github → Settings → SSH and GPG keys → New SSH key 에 이전단계에서 확인한 SSH key를 넣어준다</p>
<h3 id="sshconfig-파일-설정">~/.ssh.config 파일 설정</h3>
<p>(없다면 vi편집기를 통해 생성하기!)</p>
<p>다음내용을 config 에 적어준다</p>
<pre><code class="language-shell">## 개인계정 
Host personal-github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_personal

## 회사계정
Host corp-github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_corp</code></pre>
<p>여기서 Host 뒤에 적은 personal-github.com 여기가 중요하다!!</p>
<h3 id="깃허브에-등록되었는지-확인하기">깃허브에 등록되었는지 확인하기</h3>
<p>다음 명령어를 입력하면 연결을 계속 할거냐고 물어보는데 yes 입력하면 성공적으로 등록된다</p>
<pre><code class="language-shell">ssh -T corp-github.com
ssh -T personal-github.com</code></pre>
<h3 id="repository-클론">repository 클론</h3>
<p>이제 클론할 때 SSH를 이용해 클론하게 될텐데 ... !
<img src="https://velog.velcdn.com/cloudflare/yena-lena/e7ec31c0-1799-42a4-976c-7e4515c5d08b/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202022-04-08%20%EC%98%A4%EC%A0%84%208.01.30.png" width=60%></p>
<p><a href="mailto:git@github.com">git@github.com</a>:yena-lena/shop_app.git 에서 앞부분 github.com을 config 에서 설정한 이름으로 변경한다</p>
<pre><code class="language-kotlin">git clone git@personal-github.com:yena-lena/shop_app.git</code></pre>
<p>을 통해 연결해주면 계정관리를 편하게 할 수 있다!!!!</p>
<p>드디어 해결</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GitHub에 100MB 이상 대용량 파일 업로드하기]]></title>
            <link>https://velog.io/@yena-lena/GitHub%EC%97%90-100MB-%EC%9D%B4%EC%83%81-%EB%8C%80%EC%9A%A9%EB%9F%89-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yena-lena/GitHub%EC%97%90-100MB-%EC%9D%B4%EC%83%81-%EB%8C%80%EC%9A%A9%EB%9F%89-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 11 Feb 2022 10:29:19 GMT</pubDate>
            <description><![CDATA[<p>GitHub에 100MB 이상의 파일을 업로드하기 위해선 Git LFS를 사용해야합니다.</p>
<p>먼저 LFS를 사용하기 위해 다음 명령어로 설치를 합니다.</p>
<pre><code class="language-shell">brew install git-lfs</code></pre>
<p>이후 LFS를 사용하고자 하는 로컬 저장소로 이동하고 다음 명령어를 입력합니다.</p>
<pre><code class="language-shell">git lfs install</code></pre>
<p>Git LFS로 관리할 파일경로를 입력해 지정하면 됩니다.</p>
<pre><code class="language-shell">git lfs track &quot;파일경로&quot;</code></pre>
<p>만약 이미 커밋한 경우, <code>git rm --cache 파일경로</code> 명령어를 입력한 뒤 <code>git lfs track 파일경로</code> 명령어를 통해 관리해주면 됩니다.
<br></p>
<p>또한 lfs로 트래킹하는 파일에 대한 정보는 .gitattributes을 통해서 관리가 되어 이 변경사항을 꼭 add해주어야한다. </p>
<pre><code class="language-shell">git add .gitattributes</code></pre>
<br>

<p>이후, 커밋 후 푸쉬하면 지정된 대용량 파일은 LFS를 통해 관리가 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python] 파워링크 크롤러]]></title>
            <link>https://velog.io/@yena-lena/%ED%8C%8C%EC%9B%8C%EB%A7%81%ED%81%AC-%ED%81%AC%EB%A1%A4%EB%9F%AC</link>
            <guid>https://velog.io/@yena-lena/%ED%8C%8C%EC%9B%8C%EB%A7%81%ED%81%AC-%ED%81%AC%EB%A1%A4%EB%9F%AC</guid>
            <pubDate>Fri, 11 Feb 2022 05:16:51 GMT</pubDate>
            <description><![CDATA[<p>Beautifulsoup4를 활용한 네이버 파워링크 크롤러 개발</p>
<h3 id="배경">배경</h3>
<p>동생이 재택근무하는데 여러 키워드를 검색하며 광고 대상이 네이버 파워링크 상 순위를 조사하고, 체크하는 단순노가다를 붙잡고 짜증을 내는걸 보고 제작하게 되었습니다.</p>
<h3 id="요구사항">요구사항</h3>
<ol>
<li>복수개의 키워드는 엑셀파일로 입력</li>
<li>파워링크 검색 결과를 저장하고 타겟 브랜드의 순위를 출력</li>
<li>PC/mobile 두가지 버전 필요</li>
<li>순위 결과는 엑셀파일로 저장</li>
</ol>
<h3 id="구조">구조</h3>
<ol>
<li>키워드 목록을 불러옴 </li>
<li>파워링크 도메인에 특정 키워드를 검색하는 base url 생성</li>
<li>검색 결과 중 광고 제목( <code>class = &quot;lnk_tit&quot;</code> ) 만 크롤링해서 리스트로 저장 -&gt; beautiful soup 사용</li>
<li>제목 리스트에서 타겟 브랜드가 몇 위에 노출되었는지 출력</li>
<li>csv 파일로 저장</li>
</ol>
<h3 id="예시">예시</h3>
<p>타겟 브랜드가 디디치킨인 경우, 치킨을 검색했을 때 검색결과에서 나온 순위(현재 예시에서는 3위)를 출력하고 다음 키워드를 탐색하며 반복한다.</p>
<p><img src="https://images.velog.io/images/yena-lena/post/b4713115-2309-4e0c-8dbc-244c6608d989/1.png" alt=""></p>
<p>코드첨부</p>
<pre><code class="language-python">import csv
import requests
from urllib.request import urlopen
from urllib.parse import quote_plus
from bs4 import BeautifulSoup
import re
import pandas as pd

#cp949 에러 발생시 csv파일 인코딩을 메모장에서 ANSI로 변경
## file_name : 파워링크 검색 키워드 목록
## find : 탐색할 업체
file_name = &quot;keyword.csv&quot;
find = &quot;치킨&quot;

f = open(file_name,&#39;r&#39;, encoding=&quot;utf-8&quot;)
df = pd.read_csv(f)
keywords = df[&#39;이름&#39;]

## PC 버전 크롤링
data = []

url = &#39;https://ad.search.naver.com/search.naver?where=ad&amp;x=0&amp;y=0&amp;query=&#39;

for keyword in keywords:
    base_url = url+quote_plus(keyword)

    response = requests.get(base_url)

    if response.status_code == 200:
      soup = BeautifulSoup(response.content, &#39;html.parser&#39;)

    items = soup.find_all(attrs={&#39;class&#39;:&#39;lnk_tit&#39;})

    rank = 1
    temp = 0

    for item in items[:10]:#10위까지만 탐색
      serial = item.get_text()
      #print(serial[:10])
      if &quot;네네치킨&quot; in serial:
          temp = rank
      rank = rank+1

    data.append([keyword,temp])


# 결과 저장
result = pd.DataFrame(data, columns=[&#39;Name&#39;,&#39;Rank&#39;])
print(result)
result.to_csv(&#39;result.csv&#39;, encoding=&#39;euc-kr&#39;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] SettingWithCopyWarning]]></title>
            <link>https://velog.io/@yena-lena/Error-SettingWithCopyWarning</link>
            <guid>https://velog.io/@yena-lena/Error-SettingWithCopyWarning</guid>
            <pubDate>Tue, 25 Jan 2022 06:48:41 GMT</pubDate>
            <description><![CDATA[<p>판다스로 데이터를 정리하다가 <strong>SettingWithCopyWarning</strong> 라는 에러문구가 나왔다.</p>
<p>Warning이라 실행되길래 그냥 무시하고 넘길까 했는데 가끔씩 본 에러문구여서 제대로 알고 넘어가기로 했다.</p>
<h3 id="원인">원인</h3>
<p>해당 오류는 데이터프레임의 열의 값이 이미 메모리에 존재하고 있는데, 그 메모리에 직접적으로 접근하여 수정하는 경우 발생하는 경고문구이다. </p>
<pre><code>result_df = df[df[&quot;option&quot;].isin(select_list)]
result_df[&quot;rank&quot;][0] = match_num </code></pre><p>이런 식으로 result_df와 df가 연결되어있어 열의 값을 직접 변경하는 경우 에러가 발생한다.</p>
<h3 id="해결책">해결책</h3>
<p>copy()를 통해 result_df와 df를 분리해 해결했다.</p>
<pre><code>result_df = df[df[&quot;option&quot;].isin(select_list)].copy()</code></pre>]]></description>
        </item>
    </channel>
</rss>