호쌤
호쌤 Just For Fun

[Python 데이터 수집] BeautifulSoup 활용시의 CSS 선택자 정리

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Python 데이터 수집] BeautifulSoup 활용시의 CSS 선택자 정리≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

[Python 데이터 수집] BeautifulSoup 활용시의 CSS 선택자 정리

BeautilfulSoupbs4 패키지에 포함된 클래스로서 requests패키지를 통해 가져온 웹 페이지의 HTML 소스코드를 분석하여 원하는 영역만 추출하는 기능을 제공하는 패키지 입니다.

이 패키지를 활용할 때 필수적으로 요구되는 선행 지식이 CSS 선택자 입니다. 하지만 CSS 선택자는 HTML,CSS를 공부할 때 처음 등장하는 내용이기 때문에 선행학습 없이 파이썬을 시작하는 경우 이 부분에서 많은 어려움을 겪습니다.

이 포스팅에서는 CSS 선택자 중에서 자주 활용되는 패턴을 정리했습니다.

#01. 기본 준비

1) 필요한 패키지 설치

1
pip install --upgrade bs4
▶ 출력결과
1
2
3
4
5
6
7
8
Requirement already up-to-date: bs4 in c:\users\leekh\appdata\local\programs\python\python37\lib\site-packages (0.0.1)
Requirement already satisfied, skipping upgrade: beautifulsoup4 in c:\users\leekh\appdata\local\programs\python\python37\lib\site-packages (from bs4) (4.9.0)
Requirement already satisfied, skipping upgrade: soupsieve>1.2 in c:\users\leekh\appdata\local\programs\python\python37\lib\site-packages (from beautifulsoup4->bs4) (2.0)
Note: you may need to restart the kernel to use updated packages.


WARNING: You are using pip version 19.3.1; however, version 20.1.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

2) 패키지 참조

1
2
import requests
from bs4 import BeautifulSoup

3) 샘플 페이지 확인

이 단원의 예제를 진행하기 위해 샘플 웹 페이지를 준비했다.

http://itpaper.co.kr/demo/py/selector.html

img

웹 페이지의 화면 빈 공간에서 마우스를 우클릭하고 페이지 소스보기메뉴를 클릭하면 아래와 같이 웹 페이지를 구성하는 HTML 전체 소스코드를 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <title>BeautifulSoup Sample</title>
    <style type="text/css">
        * { padding: 5px; margin: 5px auto; list-style: none; }
        div#container { border: 3px dashed #ff00ff; }
        div#container > h1#title { border: 3px dashed #ff6600; }
        div#container div.box { border: 3px solid #ffff00; }
        div#container > ul { border: 3px solid #00ff00; }
        div#container > ul > li { border: 3px dotted #3438af; font-size: 18px; }
        p, pre { border: 1px solid #555; font-size: 16px; color: #f60;}
        i {font-size: 12px;}
    </style>
</head>

<body>
    <div id="container">
        <h1 id="title">Hello World</h1>
        <div class="box">이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.</div>
        <ul class="list-container">
            <li class="list-item">JAVA</li>
            <li class="list-item">HTML,CSS</li>
            <li class="list-item">Javascript,jQuery</li>
            <li class="list-item">JSP,Spring</li>
            <li class="list-item">Python</li>
        </ul>
        <p class="article hello">안녕하세요. <i>Hello.</i></p>
        <p class="article welcome">어서오세요. <i>Welcome</i></p>
        <p class="article say">샘플 웹 페이지 입니다. <i>This is sample web page.</i></p>
        <a href="https://www.naver.com" class="link">네이버</a>
        <a href="https://www.daum.net" class="link">다음</a>
        <a href="https://www.google.com" class="link">구글</a>
        <footer><i>copyright&copy;itpaper.co.kr</i></footer>
    </div>
</body>

</html>

4) requests 모듈로 웹 페이지 코드 가져오기

1
2
3
4
5
6
7
8
9
10
11
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36"
session = requests.Session()
r = session.get("http://itpaper.co.kr/demo/py/selector.html")

if r.status_code != 200:
    print("[%d Error] %s" % (r.status_code, r.reason))
    quit()

r.encoding="utf-8"
html = r.text
html
▶ 출력결과
1
'<!DOCTYPE html>\n<html lang="ko">\n\n<head>\n    <meta charset="UTF-8">\n    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">\n    <title>BeautifulSoup Sample</title>\n    <style type="text/css">\n        * { padding: 5px; margin: 5px auto; list-style: none; }\n        div#container { border: 3px dashed #ff00ff; }\n        div#container > h1#title { border: 3px dashed #ff6600; }\n        div#container div.box { border: 3px solid #ffff00; }\n        div#container > ul { border: 3px solid #00ff00; }\n        div#container > ul > li { border: 3px dotted #3438af; font-size: 18px; }\n        p, pre { border: 1px solid #555; font-size: 16px; color: #f60;}\n        i {font-size: 12px;}\n    </style>\n</head>\n\n<body>\n    <div id="container">\n        <h1 id="title">Hello World</h1>\n        <div class="box">이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.</div>\n        <ul class="list-container">\n            <li class="list-item">JAVA</li>\n            <li class="list-item">HTML,CSS</li>\n            <li class="list-item">Javascript,jQuery</li>\n            <li class="list-item">JSP,Spring</li>\n            <li class="list-item">Python</li>\n        </ul>\n        <p class="article hello">안녕하세요. <i>Hello.</i></p>\n        <p class="article welcome">어서오세요. <i>Welcome</i></p>\n        <p class="article say">샘플 웹 페이지 입니다. <i>This is sample web page.</i></p>\n        <a href="https://www.naver.com" class="link">네이버</a>\n        <a href="https://www.daum.net" class="link">다음</a>\n        <a href="https://www.google.com" class="link">구글</a>\n        <footer><i>copyright&copy;itpaper.co.kr</i></footer>\n    </div>\n</body>\n\n</html>\n\n\n'

5) BeautifulSoup 객체 생성

1
2
soup = BeautifulSoup(html, 'html.parser')
soup
▶ 출력결과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>

<html lang="ko">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"/>
<title>BeautifulSoup Sample</title>
<style type="text/css">
        * { padding: 5px; margin: 5px auto; list-style: none; }
        div#container { border: 3px dashed #ff00ff; }
        div#container > h1#title { border: 3px dashed #ff6600; }
        div#container div.box { border: 3px solid #ffff00; }
        div#container > ul { border: 3px solid #00ff00; }
        div#container > ul > li { border: 3px dotted #3438af; font-size: 18px; }
        p, pre { border: 1px solid #555; font-size: 16px; color: #f60;}
        i {font-size: 12px;}
    </style>
</head>
<body>
<div id="container">
<h1 id="title">Hello World</h1>
<div class="box">이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.</div>
<ul class="list-container">
<li class="list-item">JAVA</li>
<li class="list-item">HTML,CSS</li>
<li class="list-item">Javascript,jQuery</li>
<li class="list-item">JSP,Spring</li>
<li class="list-item">Python</li>
</ul>
<p class="article hello">안녕하세요. <i>Hello.</i></p>
<p class="article welcome">어서오세요. <i>Welcome</i></p>
<p class="article say">샘플 웹 페이지 입니다. <i>This is sample web page.</i></p>
<a class="link" href="https://www.naver.com">네이버</a>
<a class="link" href="https://www.daum.net">다음</a>
<a class="link" href="https://www.google.com">구글</a>
<footer><i>copyright©itpaper.co.kr</i></footer>
</div>
</body>
</html>

#02. HTML 태그와 CSS 선택자의 이해

1) HTML 태그의 구조

HTML은 기본적으로 아래와 같은 구조를 갖는다.

1
<태그이름 속성1="값" 속성2="값" 속성n="값">...내용...</태그이름>
  • 시작태그와 끝태그로 구성되며 시작태그는 <태그이름>, 끝태그는 </태그이름> 형식이다.
  • HTML 태그에는 하나 이상의 속성이 명시될 수 있으며, 속성이 없는 경우도 있다.

2) CSS 선택자

HTML은 웹 페이지의 골격을 구성하는 언어이고, 여기에 디자인을 추가하는 역할은 CSS라는 언어가 담당한다.

CSS가 HTML의 특정 부분에 접근하기 위한 표현법을 CSS Selector(CSS 선택자) 라고 하는데 이 패턴은 기본적으로 태그이름, id속성, class속성의 세 가지 형태로 되어 있다.

1
<div id="helloworld" class="foo bar">...</div>
  • 태그 이름은 div이다.
  • id 속성은 helloworld라는 값을 갖는다.
  • class 속성은 foobar라는 두 개의 값을 갖는다.

a) id 속성

id 속성은 그 페이지 안에서 고유한 요소를 의미한다. 그러므로 id속성의 값은 다른 태그 요소와 중복될 수 없다.

b) class속성

class 속성은 공백으로 구분하여 두 개 이상의 값을 부여할 수 있으며 다른 태그 요소와 중복 사용될 수 있다.

#03. HTML 요소 추출하기

크롬 브라우저에서 F12키를 누르면 화면 하단에 개발자 도구가 표시된다.

개발자 도구의 왼쪽 상단 버튼을 누르고 분석을 원하는 화면 영역을 클릭하면 해당 위치의 소스코드가 표시된다.

img

1) id에 의한 접근

a) 요소 추출하기

BeautifulSoup 객체의 select() 함수에 CSS 선택자를 전달하여 원하는 부분을 추출할 수 있다.

이 때 반환되는 결과는 항상 리스트 타입이다.

위의 결과에 따르면 “Hello World”라는 문장은 id속성이 title<h1>태그로 표현되고 있음을 알 수 있다.

id속성의 값을 명시할 때는 #기호를 사용하여 기술한다.

1
2
title = soup.select("#title")
title
▶ 출력결과
1
[<h1 id="title">Hello World</h1>]

b) 추출결과에서 HTML 태그 얻기

id 속성은 그 페이지 안에서 고유한 요소임을 의미하므로 리턴받은 결과가 리스트 타입이라 하더라도 원소는 단 하나만 포함되어 있기 때문에 반복문을 사용할 필요는 없다.

추출된 원소의 타입은 Tag 클래스의 객체이다.

1
2
tag = title[0]
print(type(tag))
▶ 출력결과
1
<class 'bs4.element.Tag'>

태그 안의 내용만 꺼내기

Tag 클래스의 객체를 사용하여 text 변수에 접근하면 내용만 추출할 수 있다. 이 값에 대해 앞뒤 공백을 제거하고 사용하면 원하는 값만 얻는것이 가능해 진다.

1
2
content = tag.text.strip()
content
▶ 출력결과
1
'Hello World'

2) class 속성에 의한 접근

a) 단일 원소에 대한 class 속성

class 속성은 값 앞에 점(.)을 붙여서 명시한다.

img

위의 화면 결과와 같이 .box라는 클래스를 갖는 요소를 select() 함수로 추출해 보면 1개의 원소를 갖는 리스트로 반환된다.

1
2
box = soup.select(".box")
box
▶ 출력결과
1
[<div class="box">이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.</div>]

원소가 하나밖에 없는 경우 반복문 없이 바로 0번째 원소에 접근할 수 있다.

1
2
content = box[0].text.strip()
content
▶ 출력결과
1
'이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.'

a) 복수 원소에 대한 class 속성

class 속성은 하나의 페이지 안에서 여러 개의 태그에 복수로 사용될 수 있다.

아래와 같이 .list-item이라는 class를 갖는 원소가 여러 개 존재하는 경우에는 select() 함수의 결과가 복수 개의 원소를 갖는 리스트로 반환된다.

img

1
2
item = soup.select(".list-item")
item
▶ 출력결과
1
2
3
4
5
[<li class="list-item">JAVA</li>,
 <li class="list-item">HTML,CSS</li>,
 <li class="list-item">Javascript,jQuery</li>,
 <li class="list-item">JSP,Spring</li>,
 <li class="list-item">Python</li>]

이 경우는 반복문을 사용해서 원소를 추출하는 처리를 구현해야 한다.

1
2
3
4
5
6
7
item_text = []

for i in item:
    k = i.text.strip()
    item_text.append(k)

item_text
▶ 출력결과
1
['JAVA', 'HTML,CSS', 'Javascript,jQuery', 'JSP,Spring', 'Python']

c) 복수의 값을 갖는 class 속성

class 속성은 공백으로 구분하여 두 개 이상의 값을 지정할 수 있다.

이 경우에는 적용된 값 중에서 하나만 활용해서 원소를 추출할 수 있다.

img

1
2
article = soup.select(".article")
article
▶ 출력결과
1
2
3
[<p class="article hello">안녕하세요. <i>Hello.</i></p>,
 <p class="article welcome">어서오세요. <i>Welcome</i></p>,
 <p class="article say">샘플 웹 페이지 입니다. <i>This is sample web page.</i></p>]
1
2
3
for i in article:
    k = i.text.strip()
    print(k)
▶ 출력결과
1
2
3
안녕하세요. Hello.
어서오세요. Welcome
샘플 웹 페이지 입니다. This is sample web page.

3) 태그 이름으로 접근하기

id나 class 속성이 없는 경우 HTML 태그 이름으로 직접 접근할 수 있다.

이 경우는 동일한 태그를 사용하는 모든 원소가 리스트로 반환되므로 가급적 지양해야 한다.

img

1
2
3
# 모든 <i>태그 가져오기
italic = soup.select("i")
italic
▶ 출력결과
1
2
3
4
[<i>Hello.</i>,
 <i>Welcome</i>,
 <i>This is sample web page.</i>,
 <i>copyright©itpaper.co.kr</i>]
1
2
3
for i in italic:
    k = i.text.strip()
    print(k)
▶ 출력결과
1
2
3
4
Hello.
Welcome
This is sample web page.
copyright©itpaper.co.kr

4) 자식 선택자

id, class, 태그이름으로 추출하려는 위치를 특정 지을 수 없을 경우 주변의 HTML 구조를 함께 명시한다.

여러개의 선택자를 >로 구분하여 지정하면 HTML 태그의 포함관계를 표현할 수 있다.

a) 예시1

img

1
2
article_i = soup.select("#container > .article > i")
article_i
▶ 출력결과
1
[<i>Hello.</i>, <i>Welcome</i>, <i>This is sample web page.</i>]

b) 예시2

img

1
2
title = soup.select("#container > #title")
title
▶ 출력결과
1
[<h1 id="title">Hello World</h1>]

c) 예시3

img

1
2
box = soup.select("#container > .box")
box
▶ 출력결과
1
[<div class="box">이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.</div>]

4) 자손 선택자

HTML 태그의 직계 자식 요소를 가리킬때는 >를 사용하지만 몇 단계를 건너뛴 하위 요소를 지정할 경우 공백으로 구분한다.

아래의 예시에서는 #container 안에 .list-container를 거쳐 .list-item으로 접근할 수 있다. 이 경우 자식 선택자를 사용하면 다음과 같이 표현된다.

1
#container > .list-container > .list-item

자손 선택자는 중간 단계를 건너뛰고 한 번에 내부 요소에 접근할 수 있다.

1
#container .list-item

img

1
2
list_item = soup.select("#container  .list-item")
list_item
▶ 출력결과
1
2
3
4
5
[<li class="list-item">JAVA</li>,
 <li class="list-item">HTML,CSS</li>,
 <li class="list-item">Javascript,jQuery</li>,
 <li class="list-item">JSP,Spring</li>,
 <li class="list-item">Python</li>]

5) 두 개 이상의 선택자를 복수로 지정하기

콤마(,)로 구분하여 두 개 이상의 선택자를 사용할 수 있다.```

img

1
2
title_box = soup.select("#container > #title, #container > .box")
title_box
▶ 출력결과
1
2
[<h1 id="title">Hello World</h1>,
 <div class="box">이 웹 페이지는 CSS 선택자 실습을 위한 샘플 페이지 입니다.</div>]

6) 두 개 이상의 class가 복수로 지정된 요소

하나의 HTML 요소에 id, class 등이 복수로 지정되어 있는 경우.

클래스 속성은 공백으로 구분하여 두 개 이상을 지정할 수 있다.

1
<div id="helloworld" class="foo bar"> ... </div>

공백 없이 나열하여 다양한 조합을 만들어 낼 수 있다.

표현식 설명
div#helloworld id속성이 helloworld<div> 태그 (순서변경 불가)
div.foo class속성이 foo<div> 태그 (순서변경 불가)
div.bar class속성이 bar<div> 태그 (순서변경 불가)
#helloworld.foo class속성이 foo이고 id속성이 helloworld인 어떤 요소 (순서변경 가능)
#helloworld.bar class속성이 bar이고 id속성이 helloworld인 어떤 요소 (순서변경 가능)
.foo.bar class속성이 foo이면서 bar인 어떤 요소 (순서변경 가능)

img

class속성이 .article이면서 .say인 어떤 요소

1
2
article_item = soup.select(".article.say")
article_item
▶ 출력결과
1
[<p class="article say">샘플 웹 페이지 입니다. <i>This is sample web page.</i></p>]

class 속성이 .say<p>태그

1
2
article_item = soup.select("p.say")
article_item
▶ 출력결과
1
[<p class="article say">샘플 웹 페이지 입니다. <i>This is sample web page.</i></p>]

7) 하나의 요소를 지정하는 다양한 표현 방법

CSS 선택자는 특정 요소를 지정하는데 있어 조합할 수 있는 경우의 수 만큼 다양한 표현법이 존재한다.

img

태그 이름으로 접근

<a>태그는 클릭할 수 있는 링크를 의미한다.

실제 웹 페이지에서 <a>태그 단독으로 추출할 경우 화면상에 있는 클릭 가능한 모든 요소를 가져오게 되므로 원하는 부분을 추출하기가 어려워 진다.

1
2
link = soup.select("a")
link
▶ 출력결과
1
2
3
[<a class="link" href="https://www.naver.com">네이버</a>,
 <a class="link" href="https://www.daum.net">다음</a>,
 <a class="link" href="https://www.google.com">구글</a>]

클래스로 접근

클래스 속성은 디자인 특성을 적용하기 위해 사용된다.

그러므로 단일 클래스 속성을 사용할 경우 비슷한 디자인 특성을 갖는 모든 요소가 추출될 가능성이 있다.

1
2
link = soup.select(".link")
link
▶ 출력결과
1
2
3
[<a class="link" href="https://www.naver.com">네이버</a>,
 <a class="link" href="https://www.daum.net">다음</a>,
 <a class="link" href="https://www.google.com">구글</a>]

태그 이름과 클래스 속성을 함께 적용

1
2
link = soup.select("a.link")
link
▶ 출력결과
1
2
3
[<a class="link" href="https://www.naver.com">네이버</a>,
 <a class="link" href="https://www.daum.net">다음</a>,
 <a class="link" href="https://www.google.com">구글</a>]

특정 속성을 갖는 요소 지정하기

예제에서 제시하는 <a> 태그들이 공통적으로 href 속성을 갖고 있다.

속성에 대한 지정은 아래와 같이 처리한다.

1
2
3
4
5
태그이름[속성명]
.클래스이름[속성명]
#아이디이름[속성명]
태그이름.클래스이름[속성명]
태그이름#아이디이름[속성명]

그 외에도 다양한 표현법을 적용할 수 있다.

1
2
link = soup.select("a[href]")
link
▶ 출력결과
1
2
3
[<a class="link" href="https://www.naver.com">네이버</a>,
 <a class="link" href="https://www.daum.net">다음</a>,
 <a class="link" href="https://www.google.com">구글</a>]

html 속성에 특정 값이 적용되어 있는 경우

1
2
3
4
5
태그이름[속성명='값']
.클래스이름[속성명='값']
#아이디이름[속성명='값']
태그이름.클래스이름[속성명='값']
태그이름#아이디이름[속성명='값']
1
2
link = soup.select("a[href='https://www.google.com']")
link
▶ 출력결과
1
[<a class="link" href="https://www.google.com">구글</a>]

#04. 추출한 요소에서 속성값을 얻어오기

웹 사이트에서 추출한 요소에 포함된 텍스트 뿐 아니라 이미지 수집이나 다른 하위 컨텐츠의 URL등 특정 속성에 대한 값이 필요한 경우가 있다.

Beautifulsoup으로 추출한 HTML 요소들은 속성을 attrs라는 이름의 딕셔니리 구조로 갖기 때문에 이를 활용하면 특정 속성에 대한 값을 추출할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 추출한 속성값을 모아놓기 위한 빈 리스트
url = []

# 웹 페이지에서 .link라는 클래스를 갖는 <a>태그 추출
link = soup.select("a.link")

# 추출된 원소 수 만큼 반복
for item in link:
    # 추출된 원소의 속성들 출력하기 -> 딕셔너리 구조
    print(item.attrs)

    # 속성 중에 `href`라는 속성이 있다면?
    if "href" in item.attrs:
        # 그 값만 미리 준비한 빈 리스트에 모아놓는다.
        url.append(item.attrs["href"])

# 결과 확인
url
▶ 출력결과
1
2
3
4
5
{'href': 'https://www.naver.com', 'class': ['link']}
{'href': 'https://www.daum.net', 'class': ['link']}
{'href': 'https://www.google.com', 'class': ['link']}

['https://www.naver.com', 'https://www.daum.net', 'https://www.google.com']

#05. 이미 추출한 객체의 하위 원소 추출하기

객체 = soup.select() 형태로 추출한 웹 페이지 원소는 리스트 형태로 반환된다.

그러므로 객체의 원소 수 만큼 반복 처리가 필요하며 각각의 개별 원소는 다시 select() 함수를 사용하여 하위 요소를 추출할 수 있다.

1) 클래스가 .list-container인 요소 얻기

1
2
list_container = soup.select(".list-container")
list_container
▶ 출력결과
1
2
3
4
5
6
7
[<ul class="list-container">
 <li class="list-item">JAVA</li>
 <li class="list-item">HTML,CSS</li>
 <li class="list-item">Javascript,jQuery</li>
 <li class="list-item">JSP,Spring</li>
 <li class="list-item">Python</li>
 </ul>]

2) 원소 수 만큼 반복하면서 클래스가 .list-item인 하위 요소 추출하기

추출된 하위 원소는 다시 리스트 형태로 반환된다.

1
2
3
4
5
6
7
for item in list_container:
    li = item.select(".list-item")
    print(li)
    print("--" * 10)

    for li_item in li:
        print(li_item.text.strip())
▶ 출력결과
1
2
3
4
5
6
7
[<li class="list-item">JAVA</li>, <li class="list-item">HTML,CSS</li>, <li class="list-item">Javascript,jQuery</li>, <li class="list-item">JSP,Spring</li>, <li class="list-item">Python</li>]
--------------------
JAVA
HTML,CSS
Javascript,jQuery
JSP,Spring
Python
Rating:

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Python 데이터 수집] BeautifulSoup 활용시의 CSS 선택자 정리≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

comments powered by Disqus