이번 과제는 지니뮤직 사이트의 음원 순위를 크롤링하는거였다.

사실 과제 자체가 많이 어렵진 않았다.

3주차에서 배운 내용들과 추가로 알려주신 function을 이용하면 할 수 있었음.

처음에 썼던 코딩은 이랬다

import requests
from bs4 import BeautifulSoup

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://www.genie.co.kr/chart/top200?ditc=M&rtm=N&ymd=20210701',headers=headers)

soup = BeautifulSoup(data.text, 'html.parser')

songs = soup.select('#body-content > div.newest-list > div > table > tbody > tr')

for song in songs:
    a = song.select_one('td.info')
    b = song.select_one('td.number')

    rank = b.text[0:2].strip()
    artist = song.select_one('a.artist.ellipsis').text.strip()
    title   = song.select_one('a.title.ellipsis').text.strip()

    print(rank, title, artist)

1. 문제 발견

그런데 이렇게 해보니 문제가 하나 발생했다 ^^

저스틴 비버의 피치쓰... 이눔자식에.... 쓸데없는 친구 하나가 딸려오는 것이었다

이렇게....

딴건 잘 나오는데 피치쓰...왜이래...?

 

2. 원인 분석

결과물이 이렇게 나오는 이유는, 

크롤링으로 읽어오는 class에

 

유일하게 피치쓰만

19금으로 span class가 하나 더 있기 때문이었다 ^^

혹시 숙제 해설 코드에는 이거 없애는게 반영되어있나? 싶어서 코드 복사하고 실행해봤지만 마찬가지였다 ㅎㅎ

 

이게 너무나 거슬려서 해결을 해보려 했지만 증말 쉽지 않았다 ㅠ

ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

거의 1시간 가량 구글링하고 테스트해봐서 성공ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

3. 해결 방법

구글링을 해보았더니 function 하나를 알아낼 수 있었다.

바로 'descompose()'!!!

 

class의 아래에 있는 자식 태그를 골라내어서 지울 수 있는 메서드다.

descompose에 대한 설명이 잘 되어있는 블로그는 아래를 참조.

 

https://studyforus.com/innisfree/650714

 

[BeautifulSoup] 자식태그를 제거하기 - .decompose() & .extract() - Study For Us

안녕하세요?날씨가 쌀쌀해졌는데 다들 건강히 계시는지요? ^^이번 강좌에서는 BeautifulSoup에서 상대적으로 덜 사용되지만 유용한 두 메서드를 다뤄보고자 합니다.BeautifulSoup을 사용하다보면 자식

studyforus.com

 

이친구를 사용해서 없애보려 했지만 이 또한 쉽지 않았다.

왜냐하면 다른 곡들에는 span 태그가 없는데 피치쓰만 있으니까....

span class를 지워줘! 하면

여긴 span 없는데?ㅠ

와 같은 결과가 나왔다.

span 없는데 뭘 지우라는거니?ㅠㅠ

 

이를 해결하려면

"span이 있으면 > 지워주고 title 뽑아내

           없으면 > 그냥 title 뽑아내"

와 같이 조건문을 이용해서 구분을 지어줘야한다.

 

if a.span is not None:
    a.span.decompose()
    title = song.select_one('a.title.ellipsis').text.strip()
else:
    title   = song.select_one('a.title.ellipsis').text.strip()

이렇게 구분을 지어줘서

성공적인 결과를 볼 수 있었다 움하하

 

 

짜면서 알게 된 건, decompose는 단순히 "지워주는" 메서드라 굳이 따로 변수를 설정할 필요가 없는 것 같다.

뭔 말이냐면...

aa = a.span.decompose()
title = song.select_one('aa.title.ellipsis').text.strip()

이렇게 a를 지운게 aa고, aa에서 title 뽑아내줘

하면 오류난다. 아마 내가 매트랩에 익숙해져 있어서 자꾸 변수 설정 하려는 것 같은데ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

python에 익숙해지는 시간이 필요할 듯 하다....

 

4. 결론

사실 이것저것 막 해보면서 성공한 결과라 ㅠㅠ 원리를 잘 이해하고 짰는지는 모르겠다...

decompose 함수를 알고 나서도 거의 30분에서 1시간 정도 헤맨 듯 ㅠㅠ

class와 tag, 부모 자식 태그에 대한 이해도가 있어야 크롤링을 잘 할 수 있을 것 같다.

검색하다가 잘 정리해놓은 블로그가 있길래 또 따옴

https://blog.naver.com/PostView.naver?blogId=kiddwannabe&logNo=221177292446&redirect=Dlog&widgetTypeCall=true&directAccess=false 

 

코.알.못. 마케터도 크롤링하기#4. BeautifulSoup으로 정보가져오기

설명 영상을 게시글 아래에 추가하였습니다. (updated 2021.01.15) html 구조를 살펴보았다면, 이제는 실제...

blog.naver.com

시간을 엄청 많이 쓰긴 했지만 ㅠ_ㅠ

그래도 막상 성공하고나니 매우매우 뿌-듯 (●'◡'●)

기록하지 않고 넘어가기 아까워서 일지를 따로 써봤다.

1. DB

"내가 원하는 데이터를 잘 찾기 위해서"

Index로 구분되어 관리되는 데이터!

 

<DB 형태에 따른 구분>

   SQL NoSQL (Not only SQL)
구분 특징 칸에 채워서 관리 - 정형화된 데이터 자유롭게 관리
장점 이상한 데이터가 적음
찾을 때 속도가 빠름
확장성이 좋음. 유연한 대처 가능
(>초기 스타트업, 서비스에서 사용하면 좋음)
단점 확장성이 낮음  

2. mongoDB에 저장하기

pymongo.errors.ServerSelectionTimeoutError:

에러 메시지 때문에 정말 한참 고생했다 ... ^_ㅠ...

결과적으로 사용하고 있는 인터넷 환경 때문이었고 추가 설정해서 해결함 ㅠ_ㅠ

다만 코드를 바꾸기 전에 클라우드에 폴더가 있으면 충돌이 일어날 수 있다고해서 폴더의 위치도 조정해주었다.

해결 방법 >> 스파르타코딩클럽 FAQ에서 찾은 듯

from pymongo import MongoClient
import certifi

ca = certifi.where()

client = MongoClient('url', tlsCAFile=ca)

db = client.dbsparta

 

3. mongoDB의 데이터 파이썬으로 조정하기

# 저장 - 예시
doc = {'name':'bobby','age':21}
db.users.insert_one(doc)

# 한 개 찾기 - 예시
user = db.users.find_one({'name':'bobby'})

# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
all_users = list(db.users.find({},{'_id':False}))

# 바꾸기 - 예시
db.users.update_one({'name':'bobby'},{'$set':{'age':19}})

# 지우기 - 예시
db.users.delete_one({'name':'bobby'})

※ print 함수는 한꺼번에 표출은 안되고... for 문으로 하나씩 읽어오는 형태로 표출해줘야 한다.

#제목이 가버나움인 데이터를 찾으시오
movie = db.movies.find_one({'title':'가버나움'})

#가버나움의 star과 같은 데이터를 찾으시오
all_movies = list(db.movies.find({'star':movie['star']},{'_id':False}))

#그 데이터들을 하나씩 읽어서, title을 표출하시오
for m in all_movies:
    print(m['title'])
    
#이렇게 하면 안됨
print(all_movies['title'])

번외. 3주차의 거대한 문제 : 인터프리터 설정

mongoDB 저장이 계속 안되어 해결하는 과정(2)에서 실습하던 폴더의 경로를 한번 바꿨다.

그랬더니 인터프리터에 문제가 생겨서 .. ^^ 이전에 설치해놓은 라이브러리 함수가 안먹고...

재설치를 해보려해도 계속 오류....

오류 메세지 & 구글링을 통하여 추측한 결과 인터프리터 설정을 할 때 보통 경로 하나에 대해서만 적용되기 때문에..

경로를 바꾸니 해당 인터프리터가 작동을 안하고 그렇다고 재설치도 안되는? (아마 충돌하니까?) 그런 문제였음

 

이것저것 뒤져보다가 결국

이 버튼을 눌러봤었는데 엥? 그동안 설치했던 라이브러리가 쭉- 나오면서 해결이 됐다

모든 프로젝트에서 사용할 수 있도록 설정하는게 간단하지만 후에 문제가 될 수도 있을 ^_^ 방법일 듯 한데

나야 뭐 전문 개발자 아니니까 ㅎ 별 문제 없을거라 생각하고....

일단은 이렇게 고... 추후에 문제 생기면 다시 그때가서 해결하지 뭐...

1. JQuery& Ajax 복습

헷갈려서 적어두는 중요한 내용

Ajax 내에서 정의된 변수를 Ajax 내에서 호출할 때, ${변수이름} < 이 형식으로 호출을 해줘야 한다.

      외부에서 정의된 ID를 Ajax 내에서 호출할 때에는, $('#ID이름') < 이 형식으로 호출.

 

꼭 기억하기 !_!

 

2. 파이썬 기본 문법

list형

fruits = ['사과','배','배','감','수박','귤','딸기','사과','배','수박']

 

dictionary형

people = [{'name': 'bob', 'age': 20}, 
{'name': 'carry', 'age': 38},
{'name': 'john', 'age': 7},
{'name': 'smith', 'age': 17},
{'name': 'ben', 'age': 27}]

 

if문

파이썬의 충격적인 직관성.. 줄만 맞추면 된다. 괄호도 필요없고 end도 필요 없다!

if person['age'] 
    print('성인')
else:
    print('청소년')

 

for문

파이썬의 충격적인 직관성2.. List/ Dictionary 안에 있는 데이터 내에서 알아서 돈다!!!!!!!!!!

for person in people:
     print(person['name'])

 

3. 파이썬 크롤링

1) request로 html 불러오기

 

2) html 내에서 가져올 대상 찾기

   > "BeautifulSoup"이라는 라이브러리 함수(?)를 가지고 가져올 대상을 찾는다.

import requests
from bs4 import BeautifulSoup

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=pnt&date=20210829',headers=headers)

soup = BeautifulSoup(data.text, 'html.parser')

 

BeautifulSoup의 가장 기본적인 형태.

data = requests.get() 안에 들어있는 url을 바꿔주면 해당 url에 있는 내용들을 크롤링할 수 있다.

(((이번 예제에서는 text를 가져왔기에 BeautifulSoup(data.text)로 했지만 숫자면 .number 이렇게 바뀌려나?

    >> html문 내에서는 겉보기와 관계 없이 전부 다 text인 듯?)))

 

    > html 중에서 가져오고 싶은 특정 대상을 검사해서 나오는 html문을 가져온다.

       : 데이터의 형태가 일정하다면, html문은 반복되기 마련.

       : 반복되는 html문을 간단하게 for문으로 처리해서 크롤링할 수 있다.

 

movies = soup.select('#old_content > table > tbody > tr')

의미 : html문 안의 id들을 타고 타고 타고 들어가자! (아래 참조)

 

<div id = "old-content">
	<table>
		<tbody>
			<tr>
             #여기에 html 리스트가 들어가 있음
             #<tr>영화1</tr> <tr>영화2</tr> 이렇게 반복적으로 들어가 있어서, 이것을 크롤링해오는 것!!
			</tr>
		</tbody>
	</table>
</div>

: 그 다음, 리스트인 <tr></tr> 내의 텍스트를 하나씩 가져온다.

 

for movie in movies:
    a = movie.select_one('td.title > div > a')
    if a is not None:
    	title = a.text
        print(title)

> html의 구조를 잘 이해하는 것이 중요!!!!!!!

 

<img src="https://ssl.pstatic.net/imgmovie/2007/img/common/bullet_r_r01.gif" alt="01" width="14" height="13">

rank = movie.select_one('td:nth-child(1) > img')['alt']

위와 같은 경우는 img 안에 alt를 가져와야해서, ['alt']로 덧붙여주는 것이고

 

<td class="point">9.64</td>

star = movie.select_one('td.point').text

위와 같은 경우는 point라는 class 안의 텍스트를 가져오는 것이라 .text로 덧붙여주는 것

(html에서는 데이터 형식이 숫자처럼 보여도 전부 다 text인건가..? number로 하려니 안됐음 ^^;;;;)

강의 듣는 스파르타 코딩클럽에 무료 강의가 있길래... 흥미로워보여서 들어보았음

 

<개발 순서 Tip>

1. 결과물로부터 시작해라.

: 결과물을 구상하고, 구상한 결과물을 어떻게 구현할 수 있을지를 파악하며 계획을 세워준다.

 

2. 큰 단위부터 시작해라.

: 배경 > 구성 단위 (이것 역시 큰 제목, 작은 제목, 내용물 순으로) > 작동 코드

 

<CSS>

무료강의 자체가 페이지 꾸미기 위주로 이루어져있다보니 CSS를 꽤 자세하게 알려주셨다.

알아두어야 할 것은 이때까지 모르고 지나갔던 margin/ border/ padding의 개략적인 개념

margin: 컨텐츠의 외부

border: 컨텐츠의 벽

padding: 컨텐츠 내부 (background - text 사이라고 생각하면 됨)

 

이 세 개념은 컨텐츠를 중심점으로 구동됨.

 

 

CSS 외에는 웹개발 강의에서 배운 것에서 추가로 배운 건 없었다...

아무래도 무료강의라 흥미 돋우는 데에 집중하신 듯ㅋㅋㅋㅋㅋㅋㅋㅋ

자바스크립트가 궁금했는데ㅠ 흑흑ㅠ 코드가 넘 복잡해서 해석도 어렵당....

암턴 웹개발 강의 복습하며 만든 것에 의의를 두며 끄읕~~!!!

1. JQuery

간단하게, 직관적으로 만든 Javascript. 일종의 사용자 정의 함수인데 인터넷에 공유되어서 다함께 쓸 수 있는 그런 것

JQuery를 이용, 요소 지정 시에는 <id=""> 태그를 써 준다. (CSS에서 class 지정 후 값을 주는 것과 같은 원리)

 

- JQuery 불러오기

$('# ID NAME ').val()

ID NAME이라는 ID에 JQuery를 먹일건데 val()이라는 쿼리를 맥일거시다

$('#input-q1').val()

 

불러오기만 해서는 안된다. 새로운 이름을 지정해줘야지 (let~)

let input1 = $('#input-q1').val()

 

그 다음 원하는 방식으로 변수를 사용하기

if (input1 == '') {
    alert('입력하세요!')
} else {
    // 4. alert(입력값) 띄우기
    alert(input1)
}

 

cf) 이름 지정하지 않고 바로 사용해도 가능은 하다. 예를 들어...

function q1() {
    if ($('#input-q1').val() == '') {
        alert('입력하세요!')
    }
}

이런 식으로.

하지만 MATLAB 때와 마찬가지로 비효율적인 코딩일 듯?

 

- JQuery 이용해 html 수정하기

 

1) 임시 html을 만든다.

let temp_html = `<li>${input3}</li>`
let temp_html = `<button>'버튼'</button>`

등등 html의 형태로 텍스트 변수 만들어줌

(cf. temp_html : 임시적인 html이라고 html을 닮은 텍스트에 이름 붙여준거. 다른 이름으로 바꿔도 노상관이지만 직관적이고 좋은 이름인 것 같다)

 

2) ID와 JQuery 이용하여 임시 html을 html화 시켜준다.

$('#names-q1').append(temp_html)

.append: 붙여줘

 

2. 서버-클라이언트 통신 : JSON과 AJAX

- JSON(JavaScript Object Notation)

서버 > 클라이언트로 데이터 보낼 때 일반적으로 사용하는 데이터 형식.

List & Dictionary의 조합 형태로 되어 있음

 

- AJAX(Asynchronous Javascript And Xml)

클라이언트와 서버 간 데이터를 주고 받는 기술/ 통신 방식.

$.ajax({
    //ajax 코드. 복붙해서 사용하면 된다
    type: "GET",
    url: "가져올 데이터가 있는 url",
    data: {},
    success: function (response) {
    	//실행할 내용
    }
})

 

3. 기억해야 할 것

console.log() : DevTools의 콘솔창에 ()안에 있는 것을 표출해주는 함수. 코드의 중간 진행 상황 볼 때 사용.

>> 중간 진행 상황을 자주 확인할수록 좋다.

 

4. 깨달은 것

웹개발할 때 파이썬을 쓰는 이유로 '결과를 바로 확인할 수 있어서'라고 보았는데 그 이유를 알 것 같다.

매트랩은 코드를 다 짜고나서 실행해서 결과보고.. 오류뜨고.. 오류찾고..

만약에 중간 결과를 보고 싶으면 코드가 멈추도록 걸어놓고 변수 일일히 확인해보면서 찾았어야 했는데.

 

웹개발의 기본(?)은 검색과 복붙인듯.

코드는 거의 외우지 않는다. 기본 골격과 원리를 잘 이해하고 응용을 많이 해보자~!~

1. 웹 페이지의 구성

HTML - 뼈대. 큰 구성

CSS - 꾸미기. 폰트/ 색상/ 크기/ 그림 넣기 등

JAVA - 실행 코드

 

2. HTML과 CSS

- HTML

<head>

웹페이지 타이틀

</head>

 

<style>

  class의 스타일을 지정해준다. class 내의 요소들도 지정 가능.

*** class 정의를 내려야 스타일 지정도 가능

*** 한 class로 정의 내린 요소들은 한꺼번에 묶여서 스타일 지정됨. 만약 따로 정하고 싶다면 다른 class로 분리해야

 

   class의 스타일 지정시

   .classname {

         color: red;

         font-size: 30px;

    }

   classname 부분에 지정해준 class의 이름이 들어가면 된다.

 

   같은 요소가 여러 개로 들어가 있어서 이를 구분하려고 class를 지정해주는 것.

   해당 요소가 전 페이지에 1개밖에 없으면 class 별도 지정 필요 없음. 예를 들어, h1(제목)은 보통 한 개 밖에 없으니..

 

  h1 {

     color: red;

  }

 

  이런 식으로 짜줘도 된다는 것 !

 

</style>

 

<body>

웹페이지 메인 화면 구성

<div class=""> </div>

</body>

 

- CSS

*부트스트랩 적극 활용하기*

3. Javascript

//변수, 자료형, 함수, 조건문, 반복문

 

- 자료형: 리스트 & 딕셔너리

 

리스트는 말 그대로 리스트. 

let b_list = [1,2,'hey',3]

number/ text 간의 구분은 없는 듯 하다. matlab으로 따지면 cell? 

 

딕셔너리는 Tag가 붙은 리스트. 그림으로 표현하자면...

name age height
Bob 21 180

코드로 나타낼 때에는 {'name': 'Bob', 'age': 21}

['height'] = 180

이런 식으로 추가도 가능

matlab에서 table과 유사한 형태인 듯.

 

- 함수

  • 기본 형태

function 함수이름(필요한 변수들) { 내릴 명령들 순차적 작성 }

  • 조건문 : if (조건) {결과} elseif (조건) {결과} else {결과}
function is_adult(age){

   if(age > 20)  {
     alert('성인이에요') 
     }   else if (age > 10) {
     alert('청소년이에요') 
     }   else {
     alert('10살 이하!') 
     }
    
    }

주의할 점: 조건에 괄호 필요!!!

  • 반복문
for (let i = 0; i < 100; i++) { console.log(i); }

++ means 하나씩 더해준다

 

4. 궁금한 점,,

폰트 설정 시 1개의 폰트 당 1개의 링크를 가져와서 읽어야 하는 건가?

전체 링크 하나를 가져온 후 속해 있는 폰트를 하나씩 읽어올 수는 없을까

 

 

+ Recent posts