[웹개발 종합반] 3주 2일차 개발일지(3주 4-9강)


💻TIL Web.302

1. 파이썬 시작하기

1) 파이썬을 설치한다는 것의 의미

컴퓨터는 0, 1의 전기 신호만 인식하므로, 사람의 언어와 가장 가깝게 고안된 프로그래밍 언어를 사용한다. 파이썬을 설치한다는 것은 사람과 컴퓨터 간의 번역 패키지를 설치하는 것과 같다. 내가 파이썬으로 명령을 내리면, 파이썬 프로그램은 파이썬 문법을 컴퓨터가 알아들을 수 있는 언어로 번역해 준다.



2) 새 파이썬 파일 생성하기

Pycharm 프로그램에서 새 파이썬 파일을 생성한다. 파일 location 마지막에 ₩venv가 있는지 확인하고, 없으면 입력해준다. 후에 생성된 venv 폴더는 절대 건드리지 않으며, 보이지만 안 보이는 폴더라고 생각한다. 기본 인터프리터는 내가 설치한 파이썬 폴더를 선택하고, 맨 아래쪽 체크(main.py 웰컴 스크립트 생성)는 해제해준다.

print('hello sparta')
# hello sparta

‘hello.py’라는 새로운 파일을 생성하고 위 코드를 입력한다. 실행할 때는 반드시 오른쪽 마우스 클릭 후 ‘실행(Run)’ 버튼을 누른다. 파이참 실행창 아래쪽의 초록 실행 버튼을 눌러도 되지만, 내가 보는 파일이 아닌 이전에 실행했던 파일이 실행되는 오류가 있을 수 있다.


2. 파이썬 기초 문법

파이썬 또한, 기초 문법을 토대로 필요한 문법들은 구글링하는 습관을 들이자.

1) 변수

a = 3
b = 2
print(a+b)  # 5

firstName = 'ramona'
lastName = 'doe'
print(firstName+lastName)  # ramonadoe

자바스크립트는 변수 앞에 let이나 const 등을 붙였지만, 파이썬은 단순히 변수 이름과 값만 적어주면 된다.


name = 'yendoz'
num = 6
print(name+num)
# Traceback (most recent call last):
#   File "C:\Users\82105\PycharmProjects\pythonProject\hello.py", line 3, in <module>
#   print(name+num)
# TypeError: can only concatenate str (not "int") to str

에러가 났을 때는, 에러 제일 마지막 줄과 그 앞의 줄을 보면 해결의 실마리를 찾을 수 있다. 에러 마지막 줄은 에러에 대한 설명이며, 그 앞의 줄은 에러가 난 코드를 말해준다. 에러 마지막 줄을 그대로 복사해 구글에 검색하면 잘못된 지점을 찾을 수 있다. 예를 들어, 위 에러에서는 ‘문자는 (숫자가 아니라) 문자와만 합칠 수 있다’라고 나와 있다. 해당 내용을 복사해 검색하면 str()을 이용해 숫자를 문자 형태로 바꿔줄 수 있다는 설명이 나온다.


name = 'yendoz'
num = str(6)  # '6'과 같은 의미
print(name+num)  # yendoz6

위 코드에서 str(6)은 ‘6’과 같은 의미로, 문자열 6이다. 문자열과 문자열은 합칠(concatenate) 수 있으므로, 두 변수를 더하면 에러 없이 출력된다.



2) 리스트(Array)와 딕셔너리(Object)

a_list = ['사과', '배', '딸기', '바나나']
print(a_list)  # ['사과', '배', '딸기', '바나나']
print(a_list[2])  # 딸기

a_list.append('수박')
print(a_list)  # ['사과', '배', '딸기', '바나나', '수박']

리스트 이용 방식은 자바스크립트와 동일하다. 대괄호([])를 사용해 나타낼 수 있고, 0부터 시작하는 index값을 활용해 값에 접근할 수 있다. 리스트에 값을 추가할 때는 .append를 이용한다.


a_dict = {'name': 'ramona', 'age': 23}
print(a_dict)  # {'name': 'ramona', 'age': 23}
print(a_dict['name'])  # ramona

a_dict['country'] = 'Canada'
print(a_dict)  
# {'name': 'ramona', 'age': 23, 'country': 'Canada'}

딕셔너리도 자바스크립트와 동일한 방식으로 이용된다. 대신 JSON 데이터처럼 key에도 ''""을 써주어야 한다. back-tick 키는 syntax error가 뜬다. 원하는 key의 값을 출력하기 위해서는 ['']을 이용한다. key들이 모두 문자열 처리가 되어 있어서 print(a_dict.name)처럼 연결 연산자를 사용하면 에러가 난다. 딕셔너리에 새 값을 추가하려면 자바스크립트와 동일하게 새로운 key와 그에 따른 value를 지정해주면 된다.



3) 함수

def sum(num1,num2): 
  return num1+num2

result = sum(2,3)
print(result)  # 5

프로그래밍에서의 함수는 ‘정해진 동작을 수행하는 것’이라고 했다. 파이썬의 함수는 자바스크립트와 달리 function 키워드와 {}가 아니라 def:를 이용해 정의된다. sumnum1,num2는 각각 함수의 이름과 인자(parameter)로, 이름을 바꿀 수 있다. : 이후의 코드는 자동으로 들여쓰기(Tab 처리)가 되며, :의 내용물이라고 해석된다. 파이썬에서는 자바스크립트에서 사용되는 중괄호({})가 사용되지 않고, 그보다 더 직관적인 줄바꿈과 들여쓰기로 코드가 함수의 내용임을 판단한다.


def sum(num1,num2):
  print('안녕!') 
  return num1+num2

result = sum(2,3)

print(result)

위 함수의 로직을 살펴보자. 먼저, defsum이라는, 두 개의 parameter를 받는 함수가 선언된다. 이 함수는 ‘안녕!’을 출력하고, 인자로 받은 두 값을 더한 값을 반환한다. 코드는 아래로 내려가다가 result라는 변수를 발견하고 2와 3을 인자로 갖는 sum 함수를 호출한다. 그러면 다시 코드 첫 번째 줄로 돌아가, 함수는 먼저 ‘안녕!’을 출력한다. 그리고 두 번째 줄에서 두 인자를 더해 5를 return한다. return은 값을 변신시키는 키워드라고 했으므로, result 값은 이때부터 5가 된다. 그리고 코드 마지막 줄에서 5로 바뀐 result가 출력된다.



4) 조건문

age = 23

if age > 20:
  print('성인입니다')
else:
  print('청소년입니다')

# 성인입니다

조건문도 함수와 같이 중괄호({}) 대신 콜론(:)을 사용한다.


def isAdult(age):
  if age > 20:
    print('성인입니다')
  else:
    print('청소년입니다')

isAdult(21)  # 성인입니다
isAdult(17)  # 청소년입니다

위처럼 조건문을 이용한 함수도 만들 수 있다. 처음에 print(isAdult(25))를 썼는데 ‘성인입니다’와 ‘None’이 같이 출력되었다. print가 자바스크립트의 console.log와 비슷한 개념이라고 생각하면, ‘None’은 undefined에 해당하는 것 같다. 함수 자체에서 이미 print를 쓰고 있으니 print를 다시 쓸 필요가 없다. 또, 중괄호를 사용하지 않으므로 함수와 조건문 각각 Tab 처리를 해주는 것이 중요하다.



5) 반복문

자바스크립트에서 반복문을 쓸 때, 우리는 보통 리스트(Array)와 반복문을 함께 사용하며 i < array.length 형태로 리스트의 길이를 사용했었다. 파이썬은 더 직관적으로, 리스트와 함께 반복문을 사용할 때 리스트의 원소를 하나씩 빼서 사용하는 형태를 취한다.

① 리스트(Array)에서의 반복문

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

for fruit in fruits:
  print(fruit)
# 사과 배 배 감 수박 귤 딸기 사과 배 수박


count = 0
for fruit in fruits:
  if fruit == '수박':
    # count = count + 1과 같음
    count += 1  

print(count)  # 2

fruit는 리스트(array)의 각 원소(element)를 지칭하는 새로운 변수라고 생각하면 쉽다. 변수이므로 이름을 바꾸어도 된다. fruits는 반복문을 돌릴 array의 이름이다. 위 반복문은 fruits array에서 fruit라 명명한 각 원소를 가지고 와서 함수에서 사용한다. 원소를 하나하나 빼서 사용하는 것이므로 원소를 다 가지고 오면 함수의 실행이 멈춘다. 즉 배열의 길이를 몰라도 자동으로 리스트의 길이만큼 반복문이 실행된다.

파이썬의 반복문 형태를 보면, 자바스크립트의 for...of 반복문과 비슷해 보인다. 자바스크립트에서도 아래 코드와 같이 배열의 길이를 몰라도 반복문이 돌아갈 수 있도록 하는 for...of 반복문이 있었다. 30DaysOfJS 노트와 공식 문서를 참고하자.

let array = [1, 0, 2, 7, 5, 9]
for (let elements of array) {
  console.log(elements)
}
// 1 0 2 7 5 9 



② 딕셔너리가 포함된 리스트에서의 반복문

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

for person in people:
  print(person['name'], person['age'])
# bob 20 carry 38 john 7 smith 17 ben 27

for person in people:
  if person['age'] > 20:
    print(person)
# {'name': 'carry', 'age': 38}
# {'name': 'ben', 'age': 27}

리스트를 보면, nameage라는 키를 가진 딕셔너리(Object) 5개가 포함되어 있다. print(people)을 입력하면 각 element가 모두 출력된다. 딕셔너리의 특정 key 값에 접근하고 싶다면 [''] 형태를 사용하면 된다. 쉼표(,)를 사용해 여러 값을 출력할 수도 있다. 특정 조건에 맞는 딕셔너리(Object) 또는 key 값 또한 반복문과 조건문을 조합한 형태로 출력할 수 있다.

중괄호나 대괄호 등 기본 문법의 생김새를 하나하나 파고들기보다는 맥락에 맞게 통째로 이해하자!


3. 파이썬 패키지 설치하기

파이썬은 라이브러리가 방대한 것으로 유명하다. 패키지란 모듈(기능들의 묶음)을 모아 놓은 단위이며, 이러한 패키지들의 묶음을 라이브러리라고 한다. 외부 라이브러리를 사용하려면 패키지를 설치해야 한다. 여러 사람들이 만들어 둔 라이브러리를 import해와서 사용하면, 어려운 기능들을 라이브러리 문법에 맞게 간단히 실행할 수 있다.


1) 가상 환경(=venv)

가상 환경(virtual environment)이란 프로젝트별로 패키지들을 담는 공구함 개념이다. 즉, 같은 시스템에서 실행되는 다른 파이썬 응용 프로그램들의 동작에 영향을 주지 않기 위해, 파이썬 배포 패키지들을 설치하거나 업그레이드하는 것을 가능하도록 하는 격리된 실행 환경이다. 앞에서 만든 venv 폴더가 가상 환경에 해당하며, 앞으로 사용할 라이브러리들은 이 폴더에 담기게 된다.

예를 들어, 회사에서는 패키지 A, B, C를 쓰고, 개인 프로젝트에서는 B, C, D, E를 설치해서 쓰고 있는 상황이다. 이때 회사에서 B 패키지를 이전 버전인 B’으로 쓰자고 한다면, 개인 프로젝트도 같은 컴퓨터를 사용하므로 B 버전의 코드를 모두 B’ 코드로 바꿔야 한다. 이때 프로젝트별 가상 환경을 생성해서 공구함1(회사)에는 A, B’, C를, 공구함2(개인 프로젝트)에는 B, C, D, E를 담아두고 쓰면 관리하기 편하다.



2) pip 사용/requests 패키지 설치해보기

앱 설치를 위해 앱스토어를 이용하듯, 새로운 프로젝트의 라이브러리를 가상 환경(공구함)에 설치하려면 pip(python install package)를 이용하게 된다. 파이썬 패키지 설치를 위해, PyCharm 설정 > 프로젝트 > 프로젝트 인터프리터 > + > 패키지 이름 검색 및 설치 순으로 실행한다. 강의에서는 requests라는 패키지를 설치했다. 설치한 패키지들의 사용 방법은 해당 패키지의 공식 문서(documentation)나, 블로그 글 등을 검색해 참고한다.



3) requests 패키지 이용하기

{
  "RealtimeCityAir": {
    "list_total_count": 25,
    "RESULT": {
    "CODE": "INFO-000",
    "MESSAGE": "정상 처리되었습니다"
    },
    "row": [
      {
      "MSRDT": "202206032100",
      "MSRRGN_NM": "도심권",
      "MSRSTE_NM": "중구",
      "PM10": 31.0,
      "PM25": 23.0,
      "O3": 0.053,
      "NO2": 0.026,
      "CO": 0.5,
      "SO2": 0.004,
      "IDEX_NM": "보통",
      "IDEX_MVL": 70.0,
      "ARPLT_MAIN": "O3"
      },
      {
        ...
      }
# requests 라이브러리 설치 필요
import requests 

r = requests.get('http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99')
rjson = r.json()

print(rjson['RealtimeCityAir']['row'][0]['NO2'])  

# 0.026

위 예시 코드의 url은 전에도 다뤄본 적 있는 서울시의 미세먼지 OpenAPI다. print(rjson)을 입력하고 실행시키면, Ajax를 이용했을 때처럼 JSON 데이터가 출력된다. 위의 API 데이터 구조를 참고하면, 코드의 마지막 줄은 딕셔너리 형태의 데이터에서 원하는 key 값에 접근하는 방식과 동일하다.


import requests 

r = requests.get('http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99')
rjson = r.json()

# 모든 구들의 리스트
gus = rjson['RealtimeCityAir']['row']

for gu in gus:
  gu_name = gu['MSRSTE_NM']
  gu_mise = gu['IDEX_MVL']
  if (gu_mise > 90):
    print(gu_name, gu_mise)

# 도봉구 96.0 강북구 94.0 노원구 96.0

for...in으로 반복문을 활용할 수도 있고, if 문을 더해 조건문과 결합도 가능하다. if 문에서 ()는 생략 가능하다.


4. 웹 스크래핑(크롤링) 기초

1) 크롤링이란

web302

네이버 영화 랭킹 사이트에 들어가보면 다음과 같이 영화 이름과 평점 등이 나와 있다. 이러한 순위와 이름 등을 갖고 오는 것을 흔히 크롤링(crawling)이라고 한다. 사실 크롤링이란 구글의 검색 엔진이나 네이버의 검색 엔진이 내 사이트를 가져가서 데이터를 추출하는 것(퍼가는 것)이고, 지금처럼 웹 사이트의 정보를 긁어오는 것은 스크래핑(scrapping)이라 부른다. 위 화면에서는 순위, 영화 제목, 별점 데이터를 가져올 것이다. 크롤링에 필요한 패키지는 beautifulsoup4(bs4)이므로 해당 패키지를 설치한다.



2) 크롤링은 어떻게 이루어지나

웹 개발 첫 시간에, 내가 보고 있는 페이지는 인터넷과 관계없이 내가 받아온 페이지라고 했다. 이 받아온 페이지에서 데이터를 솎아내는 것이 크롤링이다. 실제 사람이 페이지를 보고 따라 쓰는 것도 일종의 크롤링이라 할 수 있다.

컴퓨터가 크롤링을 할 때는 기술적으로 두 가지가 중요하다. 첫 번째는 코드 단에서 브라우저를 켜지 않고 데이터를 요청하는 것, 두 번째는 요청해서 가지고 온 HTML 문서들 중에 내가 원하는 정보를 잘 솎아내는 것이다. 실제 HTML 문서를 보면, 내가 원하는 정보를 한눈에 찾아내기가 힘든데, 이때 사용되는 패키지가 바로 beautifulsoup4이다.


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.nhn?sel=pnt&date=20200303',headers=headers)

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

크롤링은 requests로 데이터를 요청하고, beautifulsoup4로 이를 솎아내는 과정으로 이루어진다. 이 두 패키지를 이용해 크롤링할 때는 항상 위의 기본 코드를 붙여넣고 시작한다. 코드 최상단의 import는 패키지를 불러오기 위한 코드다.

headers는 기본적인 코드 단에서의 요청을 막아둔 사이트들에서, 웹 브라우저에서 엔터 키를 친 것과 동일한 효과를 주기 위해 사용한다. data 변수는 requests.get()을 이용해서 해당 url에서 데이터를 요청한다. 데이터를 받아오면, BeautifulSoup으로 그 데이터들을 솎아내기 좋은 형태로 만들어서 soup 변수에 저장한다. print(soup)를 입력해 코드를 실행시키면, soup은 HTML 문서 전체를 출력한다.



3) beautifulsoup 이용하기

beautifulsoup을 이용하는 방법에는 select_oneselect의 두 가지가 있으며, 각각 하나를 선택하거나 여러 개를 선택하는 방식이다.

① select_one

영화 랭킹 페이지에서 영화 제목 오른쪽 클릭 > 검사(Inspect) > Elements 창에서 해당 코드 Copy > Copy Selector(선택자, 요소의 정확한 위치를 알려줌) > select_one('')의 ‘ ‘ 사이에 붙여넣기

# title = soup.select_one('')
title = soup.select_one('#old_content > table > tbody > tr:nth-child(2) > td.title > div > a')

print(title)
# <a href="/movie/bi/mi/basic.naver?code=171539" title="그린 북">그린 북</a>
print(title.text)
# 그린 북
print(title['href'])
# /movie/bi/mi/basic.naver?code=171539

select_one('')을 사용해 태그와 태그 사이의 텍스트(그린 북)를 가져오고 싶다면 가지고 오고자 하는 데이터 뒤에 .text를 붙이면 된다. 반대로 태그 안에 있는 속성값(href의 값)을 가지고 오고 싶다면 가져오고자 하는 데이터 뒤에 ['속성 이름']을 붙이면 된다. [''] 형태가 사용되었다고 해서 이것이 딕셔너리(Array)라는 뜻은 아니다. 라이브러리를 만든 사람이 정한 문법이므로 정확히 이해할 필요는 없다.



② select

위의 랭킹 화면에서 여러 영화들의 순위, 제목, 별점 데이터를 가져오려면 한 줄씩 분리해서 데이터를 추출하는 것이 효율적일 것이다. 이를 위해서는 HTML 문서에서 한 줄에 해당하는 코드가 어디까지인지를 알아야 한다. 한 줄에 해당하는 코드 전체를 Copy Selector 해보자.

#old_content > table > tbody > tr:nth-child(2)
#old_content > table > tbody > tr:nth-child(3)

여러 세트를 복사해 보면, 마지막의 숫자 부분만 다른 것을 확인할 수 있다. 여기에서 다른 부분인 nth-child() 부분을 제외한 코드를 복사해 select('')의 ‘ ‘ 안에 붙여넣는다.


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

for tr in trs:
  print(tr)

select는 결과가 리스트(array) 형태로 나온다. print(tr)을 반복문으로 돌리면 <tr> 태그가 하나씩 출력된다. 이후 이 <tr> 태그 안에서 필요한 데이터 값들을 찾으면 된다.



③ select/select_one/조건문 이용

#old_content > table > tbody > tr:nth-child(2) > td.title > div > a

영화의 제목을 불러오고 싶다면, 페이지에서 해당 부분을 우클릭해 Copy Selector 해온다. 위의 코드를 보면, tr:nth-child(2)까지는 방금 찾은 부분이다. 그 다음 이어지는 td.title > div > a 부분이 제목에 해당하는 태그다.


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

for tr in trs:
  a_tag = tr.select_one('td.title > div > a')
  print(a_tag)

# None
# <a href="/movie/bi/mi/basic.naver?code=171539" title="그린 북">그린 북</a>
# <a href="/movie/bi/mi/basic.naver?code=174830" title="가버나움">가버나움</a>
# ...

찾은 부분 이후의 코드를 복사한 다음, tr 변수 뒤에 select_one('')을 입력하고 ‘ ‘ 안에 코드를 붙여넣는다. 이는 반복문을 돌면서 <tr> 태그들을 다 불러온 다음, 각각의 태그(화면에서의 한 줄, 변수 tr)마다 제목에 해당하는 부분을 다시 찾는 것이다. 한 줄당 제목은 하나씩이므로 select를 사용할 필요 없이 하나의 값만을 찾는 select_one을 사용한다.

위 코드의 출력 창을 보면 ‘None’이라는 값이 가끔 보인다. 이는 랭킹 사이트 화면에서의 구분선 부분에 해당한다. 이러한 부분들은 사이트 화면마다 다르므로, 코드를 보고 전략을 짜는 것이 중요하다. 태그 형태 대신 제목에 해당하는 텍스트만 출력하기 위해 print(a_tag.text)를 실행시키면 ‘AttributeError: ‘NoneType’ object has no attribute ‘text’‘라는 에러가 뜬다. 이는 ‘None’에는 .text를 적용할 수 없다는 뜻이다.


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

for tr in trs:
  a_tag = tr.select_one('td.title > div > a')
  # if (a_tag is not None): 도 가능
  if a_tag is not None:
    title = a_tag.text
    print(title)

# 그린 북 가버나움 베일리 어게인...

위의 코드와 같이 조건문을 이용하면 ‘None’이 아닌 태그들에서만 텍스트를 추출할 수 있다. != 연산자를 이용하는 자바스크립트와 달리, 파이썬은 더 직관적인 is not을 사용한다. 위 코드를 실행시키면 None 이 아닌 태그들에 한해 텍스트, 즉 영화의 제목만을 추출할 수 있다.


5. 웹 스크래핑(크롤링) Quiz

01 그린 북 9.60
02 가버나움 9.59
03 베일리 어게인 9.52

위 형태처럼 순위, 영화 제목, 평점 데이터를 스크래핑해보자.

1) 순위 데이터 가져오기

앞서, 랭킹 화면의 한 줄에 해당하는 코드가 #old_content > table > tbody > tr라는 사실을 알았다. 순위, 제목, 평점 데이터를 가져오려면, 각 요소의 코드를 개별적으로 확인해서 한 번 더 걸러내야 한다. select로 태그들만 다 출력해 봤는데, 제목과 마찬가지로 ‘None’값이 중간중간 있다.


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

# 코드의 위치(selector)
#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img

순위 이미지에 해당하는 코드와 그 위치는 다음과 같다. 이미지의 url 주소를 가져올 수는 없으니, 태그의 alt 속성값을 가져와야겠다. 코드의 위치를 가져올 때는 콜론(:) 다음에 있는 ‘nth-child’는 생략하고 tr, td와 같은 태그들만 가져온다.


# 화면상의 한 줄(순위, 제목, 평점 데이터)
trs = soup.select('#old_content > table > tbody > tr')

for tr in trs:
  # 순위 태그 선별
  rankTag = tr.select_one('td > img')
  if rankTag is not None:
    rank = rankTag['alt']
    print(rank)

# 01 02 03 04 ...

태그의 텍스트를 가져오려면 .text, 속성값을 가져오려면 ['']를 이용해야 한다.



2) 평점 데이터 가져오기

# HTML 태그
<td class="point">9.60</td>

# 코드의 위치(selector)
#old_content > table > tbody > tr:nth-child(2) > td.point

평점 데이터 태그에서는 .text를 이용해 텍스트를 가져와야 한다.


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

for tr in trs:
  # 평점 태그 선별
  starTag = tr.select_one('td.point')
  if starTag is not None:
    star = starTag.text
    print(star)

# 9.60 9.59 9.52 9.52 ...

위 코드를 사용해 평점 값을 추출할 수 있다. 평점 태그들을 쭉 출력해보면 순위, 제목과 같이 ‘None’ 값이 섞여 있으므로, 마찬가지로 조건문을 활용해 걸러낸다.



3) 데이터 합쳐서 출력하기

앞에서 추출한 순위, 제목, 데이터들을 모두 합쳐 출력한다. 세 데이터가 같은 줄에 위치하므로 ‘None’ 값이 뜨는 지점은 모두 같다. 조건문을 사용해 구분선이 아닌(추출한 값이 ‘None’이 아닌) 부분에서의 값들을 스크래핑한다.

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.nhn?sel=pnt&date=20200303', headers=headers)

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

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

for tr in trs:
  # 평점 태그 선별
  rankTag = tr.select_one('td > img')
  titleTag = tr.select_one('td.title > div > a')
  starTag = tr.select_one('td.point')
  if rankTag is not None:
    rank = rankTag['alt']
    title = titleTag.text
    star = starTag.text
    print(rank, title, star)

# 01 그린 북 9.60
# 02 가버나움 9.59
# 03 베일리 어게인 9.52
# ...


4) 해설 코드

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.nhn?sel=pnt&date=20200303', headers=headers)

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

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

for tr in trs:
  a_tag = tr.select_one('td.title > div > a')
  if a_tag is not None:
    rank = tr.select_one('td > img')['alt']
    title = a_tag.text
    star = tr.select_one('td.point').text
      print(rank, title, star)

코드를 따라 쓰면서, a_tag라는 변수는 각각의 줄에 해당하는 태그가 화면 상에서의 구분선인지, 데이터를 담은 태그인지를 판별하는 용도였음을 깨달았다. 'td.title > div > a' 부분은 순위, 제목, 평점 중 아무 변수여도 상관없다. 이렇게 a_tag를 조건으로 사용해, 출력할 값을 각각 rank, title, star의 변수로 설정했다. 바로 출력될 값이므로 변수를 하나하나 분리할 필요는 없고, 연산자를 이어붙여서 쓸 수도 있다는 점 기억하기!

크롤링이란 정답이 있는 것이 아니라 값이 추출되도록 만드는 것!


Categories:

Updated:

Leave a comment