vglnk 속성 값 때문에 자동으로 태그가 씌워지는(wrap) 현상을 막아보자

환경 및 선수조건

  • Jekyll
  • YAML


class 속성에 nolinks를 추가

아래처럼 class="nolinks"를 추가해주면 된다.

...
<body class="nolinks">
...

만약 HTML 구조에서 특정 부분에만 적용을 하고 싶다면 아래처럼 특정태그에 적용을 해도 된다.

  • p 태그
...
<!--속성 추가-->
<p class="nolinks">
...
  • div 태그
...
<!--속성 추가-->
<div class="nolinks">

    ...contents...

</div>
...


업데이트(2018.05.16): requests 모듈을 통해서 웹에 있는 html 가져오는 부분 추가

웹 데이터 크롤링 또는 스크래핑을 할 때 사용하는 Python 라이브러리인 Beautiful Soup의 사용법에 대해서 간단하게 알아보자.


환경 및 선수조건

  • HTML, CSS, Javascript
  • Python
  • pip


Beautiful Soup 설치

$ pip install beautifulsoup4


Beautiful Soup 사용법

기본 세팅

기본적으로 패키지 import를 통해서 가져오며 html파일을 가져오거나 urllib 혹은 requests 모듈을 통해서 직접 웹에서 소스를 가져올 수도 있습니다.

package import

from bs4 import BeautifulSoup


html 파일 열기

with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')


urllib를 통해서 웹에 있는 소스 가져오기

  • web_url에 원하는 URL을 추가
import urllib.request
import urllib.parse

# web_url에 원하는 웹의 URL을 넣어주시면 됩니다.
with urllib.request.urlopen(web_url) as response:
    html = response.read()
    soup = BeautifulSoup(html, 'html.parser')


requests를 통해서 웹에 있는 소스 가져오기

  • web_url에 원하는 URL을 추가
import requests

# web_url에 원하는 웹의 URL을 넣어주시면 됩니다.
>>> r = requests.get(web_url)
>>> r.status_code
200
>>> r.headers['content-type']
'text/html; charset=UTF-8'
>>> r.encoding
'UTF-8'
>>> r.text
<!DOCTYPE html>
<html class="client-nojs" lang="en" dir="ltr">


HTML 예제

  • 아래 html 코드를 통해서 예제를 설명

example.html

<!DOCTYPE html>
<html>
	<head>
		<title>Page title</title>
	</head>
	<body>
    	<div>
            <p>a</p>
            <p>b</p>
            <p>c</p>
        </div>
        <div class="ex_class">
            <p>d</p>
            <p>e</p>
            <p>f</p>
        </div>
        <div id="ex_id">
            <p>g</p>
            <p>h</p>
            <p>i</p>
        </div>
		<h1>This is a heading</h1>
		<p>This is a paragraph.</p>
		<p>This is another paragraph.</p>
	</body>
</html>


find() 및 find_all()함수

  • 함수 인자로는 찾고자 하는 태그의 이름, 속성 기타 등등이 들어간다.
  • find_all(name, attrs, recursive, string, limit, **kwargs)
  • find(name, attrs, recursive, string, **kwargs)

find_all

  • find_all(): 해당 조건에 맞는 모든 태그들을 가져온다.
with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')
    all_divs = soup.find_all("div")
    print(all_divs)
# 출력 결과
[<div>
<p>a</p>
<p>b</p>
<p>c</p>
</div>, <div class="ex_class">
<p>d</p>
<p>e</p>
<p>f</p>
</div>, <div id="ex_id">
<p>g</p>
<p>h</p>
<p>i</p>
</div>]

find

  • find(): 해당 조건에 맞는 하나의 태그를 가져온다. 중복이면 가장 첫 번째 태그를 가져온다.
with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')
    first_div = soup.find("div")
    print(first_div)
# 출력 결과
<div>
<p>a</p>
<p>b</p>
<p>c</p>
</div>


태그를 이용해서 가져오기

  • 예제: 모든 <p> 태그들을 가져오기
with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')
    all_ps = soup.find_all("p")
    print(all_ps)
# 출력 결과
[<p>a</p>, <p>b</p>, <p>c</p>, <p>d</p>, <p>e</p>, <p>f</p>, <p>g</p>, <p>h</p>, <p>i</p>, <p>This is a paragraph.</p>, <p>This is another paragraph.</p>]
  • 예제: 첫번째 <div>태그를 가져오기
with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')
    first_div = soup.find("div")
    print(first_div)
# 출력 결과
<div>
<p>a</p>
<p>b</p>
<p>c</p>
</div>


태그와 속성을 이용해서 가져오기

태그와 속성을 이용할 때 함수의 인자로 원하는 태그를 첫번째 인자로 그 다음에 속성:값의 형태로 dictionary 형태로 만들어서 넣어주면 된다.

  • find_all('태그명', {'속성명': '값' ...})
  • find('태그명', {'속성명': '값' ...})

  • 예제: <div> 태그에서 id속성의 값이 ex_id인거 불러오기
with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')
    ex_id_divs = soup.find('div', {'id': 'ex_id'})
    print(ex_id_divs)
# 출력 결과
<div id="ex_id">
<p>g</p>
<p>h</p>
<p>i</p>
</div>


HTML 구조를 이용해 부분부분 가져오기

  • 예제: id속성의 값이 ex_id<div> 태그에서 <p>태그들만 가져오기
with open("example.html") as fp:
    soup = BeautifulSoup(fp, 'html.parser')
    # id=ex_id인 div 태그를 가져와서
    ex_id_divs = soup.find("div", {"id":"ex_id"})
    # 그 태그들 안에서 p 태그를 가져온다.
    all_ps_in_ex_id_divs = ex_id_divs.find_all("p")
    print(all_ps_in_ex_id_divs)
# 출력 결과
[<p>g</p>, <p>h</p>, <p>i</p>]


쉘 스크립트(Shell Script)에서 pyenv와 virtualenv를 실행하는 방법을 알아보자.


환경 및 선수조건


쉘 스크립트에서 pyenv를 사용할 때

쉘 스크립트에서 아래처럼 pyenv activate [virtualenv name]을 사용하면(저의 경우에는 unopenlab이 가상환경 이름입니다.) 오류가 뜨게 되는 경우가 있습니다.

 #!/bin/bash
pyenv activate unopenlab

Error


쉘 스크립트에서 pyenv를 사용할 때 해결 방법

이 경우에 source ~/.bash_profile를 스크립트에 포함해서 사용해주면 됩니다. 환경 변수 및 다른것들을 새로 로드하기 때문에 위에 문제가 사라지게 됩니다.

  • Shell Script에 source ~/.bash_profile 한 줄 추가
#!/bin/bash
source ~/.bash_profile
pyenv activate unopenlab


업데이트(2018.03.14): 함수 사용법을 분리하여 조금 더 상세하게 작성하였습니다.

C++에서 next_permutation 함수 혹은 prev_permutation 함수를 통해서 순열을 구해보는 방법


환경 및 선수조건

  • C++ 및 STL의 사용법(iterator)


함수

STL에 algorithm 헤더파일을 추가하면(#include <algorithm>) 다음 아래 함수를 통해서 순열을 구할수가 있다.

함수에 벡터iterator 혹은 배열의 주소를 넣으면 다음 순열(1-2-3-4의 다음 순열은 1-2-4-3) 혹은 이전 순열(1-2-4-3의 이전 순열은 1-2-3-4)의 결과가 벡터나 배열에 적용된다.

  • next_permutation: 현재 나와 있는 수열에서 인자로 넘어간 범위에 해당하는 다음 순열을 구하고 true를 반환한다. 다음 순열이 없다면(다음에 나온 순열이 순서상 이전 순열보다 작다면) false를 반환.
  • prev_permutation: 현재 나와 있는 수열에서 인자로 넘어간 범위에 해당하는 이전 순열을 구하고 true를 반환한다. 이전 순열이 없다면(다음에 나온 순열이 순서상 이전 순열보다 크다면) false를 반환.


next_permutation 함수

기본 구조


// 첫번째 인자가 구하고자 하는 순열의 시작, 두번째 인자가 순열의 끝
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last);

// 아래처럼 직접 비교함수를 넣어줘도 됩니다.
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp);


사용법

순열을 구하고 싶은 1-2-3-4의 배열이 있다고 가정을 하면 next_permutation의 함수를 사용하면 배열의 값들이 다음 순열인1-2-4-3로 바뀌고 함수는 true를 반환합니다.


구현 코드

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(){

	// 1부터 4까지 저장할 벡터 선언
	// 배열도 가능!
	vector<int> v(4);

	// 1부터 4까지 벡터에 저장
	for(int i=0; i<4; i++){
		v[i] = i+1;
	}

	// next_permutation을 통해서 다음 순열 구하기
	do{

		for(int i=0; i<4; i++){
			cout << v[i] << " ";
		}

		cout << '\n';

	}while(next_permutation(v.begin(),v.end()));

	return 0;

}


구현 결과

1 2 3 4
1 2 4 3
1 3 2 4

...

4 2 3 1
4 3 1 2
4 3 2 1


prev_permutation 함수

기본 구조


// 첫번째 인자가 구하고자 하는 순열의 시작, 두번째 인자가 순열의 끝
bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last);

// 아래처럼 직접 비교함수를 넣어줘도 됩니다.
bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp);


사용법

순열을 구하고 싶은 4-3-2-1의 배열이 있다고 가정을 하면 prev_permutation의 함수를 사용하면 배열의 값들이 다음 순열인4-3-1-2로 바뀌고 함수는 true를 반환합니다.


구현 코드

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(){

	// 1부터 4까지 저장할 벡터 선언
	// 배열도 가능!
	vector<int> v(4);

	// 4부터 1까지 벡터에 저장
	for(int i=0; i<4; i++){
		v[i] = 4-i;
	}

	// prev_permutation을 통해서 이전 순열 구하기
	do{

		for(int i=0; i<4; i++){
			cout << v[i] << " ";
		}

		cout << '\n';

	}while(prev_permutation(v.begin(),v.end()));

	return 0;

}


구현 결과

4 3 2 1
4 3 1 2
4 2 3 1

...

1 3 2 4
1 2 4 3
1 2 3 4


참고자료

clipboard.js를 이용해 웹에서 클립보드에 내용을 복사해보자

내용은 공식문서를 참고하여 제작하였습니다.


환경 및 선수조건

  • HTML, CSS, Javascript에 대한 기본 이해


설치

npm을 통한 설치 or 다운로드를 통해서 설치합니다.

$ npm install clipboard --save

파일 링크: https://github.com/zenorocha/clipboard.js/archive/master.zip

설치를 하지 않고 html에 cdn을 통한 링크를 이용해서도 사용이 가능합니다:) 즉, 굳이 설치하고 싶지 않으신 분들은 상관이 없습니다.


셋업

js파일 첨부

파일이 아니라 cdn을 통해서 링크를 첨부하고 싶다면 아래 방법처럼 사용하면 됩니다. 저는 아래 방법을 사용하였으며 링크는 다음과 같습니다(CDN Link)

<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>

위에서 받은 파일을 통한 설치는 아래와 같으며(파일의 경로로 해줘야 합니다.)

<script src="dist/clipboard.min.js"></script>


Clipboard 객체 생성

자바스크립트 코드 안에 다음 아래 코드처럼 객체를 생성해야합니다.

생성을 할 때 인자로는 이벤트를 발생시키고자 하는 HTML 태그를 DOM selector,HTML element 또는 HTML element들의 list 형태로 넘겨줘야합니다. 아래 예제들은 clipboard.js에 있는 예시들 3개와 제일 아래는 제가 적용한 예제입니다.

class 지정을 통한 예제

<body>
    <!-- 1. Define some markup -->
    <button class="btn" data-clipboard-text="1">Copy</button>
    <button class="btn" data-clipboard-text="2">Copy</button>
    <button class="btn" data-clipboard-text="3">Copy</button>

    <!-- 2. Include library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>

    <!-- 3. Instantiate clipboard by passing a string selector -->
    <script>
    var clipboard = new Clipboard('.btn');
    clipboard.on('success', function(e) {
        console.log(e);
    });
    clipboard.on('error', function(e) {
        console.log(e);
    });
    </script>
</body>

id 지정을 통한 예제

<body>
    <!-- 1. Define some markup -->
    <div id="btn" data-clipboard-text="1">
        <span>Copy</span>
    </div>

    <!-- 2. Include library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>

    <!-- 3. Instantiate clipboard by passing a HTML element -->
    <script>
    var btn = document.getElementById('btn');
    var clipboard = new Clipboard(btn);
    clipboard.on('success', function(e) {
        console.log(e);
    });
    clipboard.on('error', function(e) {
        console.log(e);
    });
    </script>
</body>

tag 지정을 통한 예제

<body>
    <!-- 1. Define some markup -->
    <button data-clipboard-text="1">Copy</button>
    <button data-clipboard-text="2">Copy</button>
    <button data-clipboard-text="3">Copy</button>

    <!-- 2. Include library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>

    <!-- 3. Instantiate clipboard by passing a list of HTML elements -->
    <script>
    var btns = document.querySelectorAll('button');
    var clipboard = new Clipboard(btns);
    clipboard.on('success', function(e) {
        console.log(e);
    });
    clipboard.on('error', function(e) {
        console.log(e);
    });
    </script>
</body>

제 경우에는 웹페이지가 로드될 때 객체를 생성하기 위해서 $(document).ready()안에다가 작성하였습니다.

<script type="text/javascript" language="javascript">
...
$(document).ready(function(){
    // 모든 이미지 tag들을 list형태로 가져옴
    var imgs = document.querySelectorAll('img');

    // 위에서 가져온 list들을 Clipboard 객체를 생성할 때 넘겨줌
    var clip = new Clipboard(imgs);

    // 클립보드에 복사가 완료되었을 때 실행할 이벤트 함수
    // 성공시
    clip.on('success', function(e) {
      console.log("Success");
      ...
    });
    // 실패시
    clipboard.on('error', function(e) {
      console.log("Error");
      ...
    });
});
...
</script>


사용법

1. data-clipboard-target을 통한 사용법

복사하고자하는 값을 가지고 있는 태그에 id를 부여하고 이벤트를 발생시키고 싶은 태그에 data-clipboard-target 속성을 설정하고 거기에 값을 앞에서 설정한 id로 지정을 해줍니다.

<!-- Target -->
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git">

<!-- Trigger -->
<button class="btn" data-clipboard-target="#foo">
    <img src="assets/clippy.svg" alt="Copy to clipboard">
</button>

2. data-clipboard-text을 통한 사용법

복사하고자 하는 태그를 설정할 필요없이 현재 태그에서 이벤트를 발생시키고 값도 복사하고 싶다면 아래처럼 data-clipboard-target를 이벤트를 발생시키고 싶은 태그에 넣어서 사용하시면됩니다.

<!-- Trigger -->
<button class="btn" data-clipboard-text="Just because you can doesn't mean you should — clipboard.js">
    Copy to clipboard
</button>


이벤트

위에 이미 예제에서 나와 있었지만 생성한 Clipboard 객체를 사용해서 이벤트를 작성합니다.

// 모든 이미지 tag들을 list형태로 가져옴
var imgs = document.querySelectorAll('img');

// 위에서 가져온 list들을 Clipboard 객체를 생성할 때 넘겨줌
var clip = new Clipboard(imgs);

// 클립보드에 복사가 완료되었을 때 실행할 이벤트 함수
// 성공시
clip.on('success', function(e) {
  console.log("Success");
  ...
});
// 실패시
clipboard.on('error', function(e) {
  console.log("Error");
  ...
});


예제코드

https://github.com/TWpower/clipboard.js-example/blob/master/clipboard-js-example.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>clipboard.js simple example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>

    <!--1. clipboard.js 파일 cdn을 통해서 로드-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>

    <!--2. 스크림트 파일 작성-->
    <script>

        // 3. 웹 문서가 로드되면 클립보드 객체 생성
        $(document).ready(function(){

            var clipboard = new Clipboard('.btn');
            clipboard.on('success', function(e) {
                console.log("Success");

                /*
                아래 함수를 통해서 블록지정을 없앨 수 있습니다.
                */
                var selection = window.getSelection();
                selection.removeAllRanges();
            });
            clipboard.on('error', function(e) {
                console.log("Fail");
            });

            // 아래와 같이 button 태그만 가져오는 방법도 가능하다.
            /*
            var btns = document.querySelectorAll('button');
            var clipboard = new Clipboard(btns);
            */


        });


    </script>
</head>



<body>
    <!--data-clipboard-target 예제-->
    <input id="foo" value="This is Value">
    <button class="btn" data-clipboard-target="#foo">data-clipboard-target example</button>

    <br/>

    <!--data-clipboard-text 예제-->
    <button class="btn" data-clipboard-text="data-clipboard-text test">data-clipboard-text example</button>


</body>
</html>


참고자료