1.  배열의 연산

 

1) 기본 연산

 

🚀  배열 형태 (shape)가 같다면 덧셈과 뺄셈, 곱셈과 나눗셈 연산을 할 수 있음

import numpy as np

arr1 = np.array([10, 20, 30, 40])
arr2 = np.array([1, 2, 3, 4])

# 각 배열의 같은 위치의 원소끼리 더함.
print(arr1 + arr2)  # [11 22 33 44]

# 두 배열의 차는 같은 위치의 원소끼리 뺌
print(arr1 - arr2)  # [ 9 18 27 36]

# 배열에 상수를 곱하면 각 원소에 상수를 곱함
print(arr1 * 2)  # [20 40 60 80]

# 배열의 거듭제곱은 배열의 각 원소에 거듭제곱.
print(arr1 ** 2)  # [ 100  400  900 1600]

# 두 배열끼리의 곱셈은 각 원소끼리 곱함.
print(arr1 * arr2)  # [ 10  40  90 160]

# 두 배열의 나눗셈은 각 원소끼리 나눔
print(arr1 / arr2)  # [10. 10. 10. 10.]

# 배열은 비교 연산도 가능. 원소별로 조건과 일치하는지 검사한 후 일치하면 True를, 그렇지 않으면 False를 반환
print(arr1 > 20)  # [False False  True  True]

 


 

2) 통계를 위한 연산

🚀  NumPy에는 배열의 합, 평균, 표준 편차, 분산, 최솟값과 최댓값, 누적 합과 누적 곱 등 주로 통계에서 많이 이용하는 메서드가 있음
        ▶️  각각 sum(), mean(), std(), var(), min(), max(), cumsum(), cumprod()

import numpy as np

arr3 = np.arange(5)
print(arr3)  # [0 1 2 3 4]

# 합
print(arr3.sum())  # 10
# 평균
print(arr3.mean())  # 2.0
# 표준 편차
print(arr3.std())  # 1.4142135623730951
# 분산
print(arr3.var())  # 2.0
# 최솟값
print(arr3.min())  # 0
# 최댓값
print(arr3.max())  # 4

arr4 = np.arange(1, 5)
print(arr4)  # [1 2 3 4]
# 누적 합
print(arr4.cumsum())  # [ 1  3  6 10]
# 누적 곱
print(arr4.cumprod())  # [ 1  2  6 24]

 


 

3)  배열의 인덱싱과 슬라이싱

🚀  인덱싱 Indexing : 배열의 위치나 조건을 지정해 배열의 원소를 선택
🚀  슬라이싱 Slicing : 범위를 지정해 배열의 원소를 선택

1) 배열의 인덱싱

 

  👾  1차원 배열에서 특정 위치의 원소를 선택하려면 원소의 위치를 지정
  👾  배열명[위치] : 배열 원소의 위치는 0부터 시작

import numpy as np

a1 = np.array([0, 10, 20, 30, 40, 50])
print(a1[0])  # 0
print(a1[4])  # 40

# 배열을 변경
a1[5] = 70
print(a1)  # [ 0 10 20 30 40 70]

 

  👾  1차원 배열에서 여러 개의 원소를 선택
          ▶️  배열명[위치1, 위치2, ..., 위치n]

  👾  2차원 배열에서 특정 위치의 원소를 선택하려면 행과 열의 위치를 지정
          ▶️  배열명[행_위치, 열_위치]

  👾  2차원 배열의 여러 원소를 선택하기 위해서 아래와 같이 지정
          ▶️  배열명[[행_위치1, 행_위치2, ..., 행_위치n], [열_위치1, 열_위치2, ..., 열_위치n]]

# 1차원 배열
print(a1[[1, 3, 4]])  # [10 30 40]

# 2차원 배열
# 10부터 99까지 10씩 증가하는 1차원 배열을 생성한 후에 3행 3열의 2차원 배열로 모양을 바꿈.
a2 = np.arange(10, 100, 10).reshape(3, 3)
print(a2)
# [[10 20 30]
#  [40 50 60]
#  [70 80 90]]

# 2차원 배열 원소 선택
# 행 위치가 0이고, 열 위치가 2인 원소를 반환.
print(a2[0, 2])  # 30
print(a2[0][2])  # 30

# 2차원 배열의 행과 열의 위치를 지정해서 원소를 선택한 후 값을 변경할 수 있음
a2[2, 2] = 95
print(a2)
# [[10 20 30]
#  [40 50 60]
#  [70 80 95]]

# 2차원 배열 여러 원소 선택
print(a2[[0, 2], [0, 1]])  # [10 80]

 

  👾  배열에 조건을 지정해 조건을 만족하는 배열을 선택
          ▶️ 배열명[조건]

a = np.array([1, 2, 3, 4, 5, 6])
print(a[a > 3])  # [4 5 6]

# 짝수만 선택하는 예
print(a[(a % 2) == 0])  # [2 4 6]

# -인덱스도 사용가능
print(a1[-2])  # 40

 


 

2) 배열의 슬라이싱


  👾  1차원 배열의 경우 슬라이싱은 배열의 시작과 끝 위치를 지정
  👾  배열[시작_위치:끝_위치]
  👾  반환되는 원소의 범위는 '시작_위치 ~ 끝_위치 -1'
          ▶️ 시작 위치를 지정하지 않으면 0
          ▶️ 끝 위치를 지정하지 않으면 배열이 길이

 

import numpy as np

b1 = np.array([0, 10, 20, 30, 40, 50])
print(b1[1:4])  # [10 20 30]

# 1차원 배열에서 '시작_위치'와 '끝_위치'를 지정하지 않고 슬라이싱하는 예.
print(b1[:3])  # [ 0 10 20]
print(b1[2:])  # [20 30 40 50]
print(b1[:])  # [ 0 10 20 30 40 50]

# 슬라이싱을 이용해 원소를 변경할 수 있음.
b1[2:5] = np.array([25, 35, 45])
print(b1)  # [ 0 10 25 35 45 50]

# 여러 원소의 값을 같은 값으로 변경하는 예
b1[3:6] = 60
print(b1)  # [ 0 10 25 60 60 60]

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


 

1.  넘파이란 ?

🥑  NumPy : 배열 데이터를 효과적으로 다루고, 과학 연산을 쉽고 빠르게 할 수 있게 만든 패키지
🥑  파이썬의 기본 데이터 형식과 내장 함수를 이용하는 것보다 다차원 배열 데이터를 효과적으로 처리
🥑  NumPy는 파이썬의 내장 모듈이 아니라서 별도로 설치

import numpy as np

 

 

    📁 NumPy 홈페이지 : https://numpy.org/

 

NumPy -

Use the interactive shell to try NumPy in the browser

numpy.org


 

1) 배열 생성 

👾  배열 (Array) 이란?  순서가 있는 같은 종류의 데이터가 저장된 집합
👾  NumPy를 이용해 배열을 처리하기 위해서는 우선 NumPy로 배열을 생성해야 함

①  시퀀스 데이터로부터 배열 생성하기  'np. array()'

    - 시퀀스 데이터 seq_data를 인자로 받아 NumPy의 배열 객체 array object를 생성

# 정수 리스트로 배열 생성
data1 = [0, 1, 2, 3, 4, 5]
print(data1)  # [0, 1, 2, 3, 4, 5]
a1 = np.array(data1)
print(a1)  # [0 1 2 3 4 5]
print(a1.dtype)  # int64

# 정수와 실수가 혼합된 경우
data2 = [0.1, 5, 4, 12, 0.5]
a2 = np.array(data2)
print(a2)  # [ 0.1  5.   4.  12.   0.5]
print(a2.dtype)  # float64. 정수와 실수가 혼합돼 있을 때 모두 실수로 변환.

# 숫자와 문자가 있는 경우
data3 = [0.1, 5, 4, 12, 'test']
a3 = np.array(data3)
print(a3)  # ['0.1' '5' '4' '12' 'test']
print(a3.dtype)  # <U32 -> 길이가 32인 유니코드 문자열

# array()에 직접 리스트를 넣어서 배열 객체도 생성 가능
a3 = np.array([0.5, 2, 0.01, 8])
print(a3)  # [0.5  2.   0.01 8.  ]

# 다차원 배열의 생성 예
a4 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a4)
# [[1 2 3]
#  [4 5 6]
#  [7 8 9]]

    


 

②  범위를 지정해 배열 생성  'np.arange()'
 

    ·  arange()를 이용해 Numpy 배열을 생성, 파이썬의 range()와 사용방법이 비슷 

# 기본 형식
arr_obj = np.arrange([start,] stop[, step])

 

     📌  start부터 시작해서 stop 전까지 step만큼 계속 더해 NumPy 배열을 생성
            ➡️ start가 0인 경우에는 생략가능
            ➡️ step이 1인 경우에는 생략가능

a1 = np.arange(0, 10, 2)
print(a1)  # [0 2 4 6 8]

a2 = np.arange(1, 10)
print(a2)  # [1 2 3 4 5 6 7 8 9]

a3 = np.arange(5)
print(a3)  # [0 1 2 3 4]

 


 

③  2차원 배열로 변경 '.reshape(m, n)'

 

    ·  arrange()를 이용해 생성한 1차원 배열에 reshape(m, n)을 추가하면 m 행  n 열의 2차원 배열(행렬)로 변경
    ·  주의할 점은 arange()로 생성되는 배열의 원소 개수와 reshape(m, n)의 m * n 의 개수와 같아야

a4 = np.arange(12).reshape(4, 3)
print(a4)
# [[ 0  1  2]
#  [ 3  4  5]
#  [ 6  7  8]
#  [ 9 10 11]]

 


 

④  배열의 형태  '.shape'

# NumPy 배열의 형태를 알기 위헤서는 'ndarray.shape'를 실행
print(a4.shape)  # (4, 3)

# 1차원 배열의 경우 '(n, )'처럼 표시
print(a1.shape)  # (5,)

 


 

범위의 시작과 끝, 데이터 개수 지정하여 배열 생성  'np.linspace()'

# 기본 형식
arr_obj = np.linspace(start, stop[, num])
# linspace()는 start부터 stop까지 num개의 배열을 같은 간격으로 생성. 
# num을 지정하지 않으면 50이 기본값.

 

a1 = np.linspace(1, 10, 10)
print(a1)  # [ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]

a2 = np.linspace(1, 10, 4)
print(a2)  # [ 1.  4.  7. 10.]

# 0부터 파이까지 동일한 간격으로 20개를 나눈 배열 생성
a3 = np.linspace(0, np.pi, 20)
print(a3)
# [0.         0.16534698 0.33069396 0.49604095 0.66138793 0.82673491
#  0.99208189 1.15742887 1.32277585 1.48812284 1.65346982 1.8188168
#  1.98416378 2.14951076 2.31485774 2.48020473 2.64555171 2.81089869
#  2.97624567 3.14159265]

 


2)  특별한 형태의 배열 생성

👾  모든 원소가 0 혹은 1인 다차원 배열을 만들기 위해서는 'zeros()'와 'ones()'를 이용

a1 = np.zeros(10)
print(a1)  # [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

# 3 * 4의 2차원 배열을 생성
a2 = np.zeros((3, 4))
print(a2)
# [[0. 0. 0. 0.]
#  [0. 0. 0. 0.]
#  [0. 0. 0. 0.]]

a3 = np.ones(5)
print(a3)  # [1. 1. 1. 1. 1.]

 


 

3)  배열의 데이터 타입 변환

👾  배열은 숫자뿐만 아니라 문자열도 원소로 가질 수 있음

# 문자열이 원소인 배열 생성 예
a1 = np.array(['1.5', '0.62', '2', '3.14', '3.141592'])
print(a1)  # ['1.5' '0.62' '2' '3.14' '3.141592']
print(a1.dtype)  # <U8. 데이터 형식이 유니코드이며 문자의 수는 최대 8개라는 의미

 


 

4)  NumPy 데이터의 형식

b 불. bool
기호가 있는 정수. (signed) integer
u 기호가 없는 정수. unsigned integer
f 실수. floating-point
c 복소수. complex-floating point
M 날짜. datetime
O 파이썬 객체. (Python) objects
S or a 바이트 문자열. (byte) string
U 유니코드. Unicode


👾  배열이 문자열(숫자 표시)로 돼 있다면 연산을 위해서는 문자열을 숫자(정수나 실수)로 변환해야 함
👾  형 변환은 astype()로 가능

num_arr = str_arr.astype(dtype)
# 실수가 입력된 문자열을 원소로 갖는 배열을 실수 타입으로 변환하는 예.
str_a1 = np.array(['1.567', '0.123', '5.123', '9', '8'])
num_a1 = str_a1.astype(float)
print(num_a1)  # [1.567 0.123 5.123 9.    8.   ]
print(str_a1.dtype)  # <U5
print(num_a1.dtype)  # float64

# 정수를 문자열 원소로 갖는 배열을 정수로 변환하는 예.
str_a2 = np.array(['1', '3', '5', '7', '9'])
num_a2 = str_a2.astype(int)
print(str_a2.dtype)  # <U1
print(num_a2)  # [1 3 5 7 9]
print(num_a2.dtype)  # int64

 


 

5) 난수 배열의 생성

👾  rand() 함수를 이용하면 실수 난수를 요소로 갖는 배열을 생성
👾  randint() 함수를 이용하면 정수 난수를 요소로 갖는 배열을 생성

rand_num = np.random.rand([d0, d1, ..., dn])
rand_num = np.random.randint([low,] high [, size])

 

    📌  rand() 함수는 [0, 1) 사이의 실수 난수를 갖는 배열을 생성
            ▶️  [a, b)의 표현은 배열 크기
    📌  randint() 함수는 [low, high) 사이의 정수 난수를 갖는 배열을 생성
            ▶️ size는 배열의 형태 지정
            ▶️ low를 입력하지 않으면 0으로 간주
            ▶️ size를 입력하지 않으면 1로 간주

 

a1 = np.random.rand(2, 3)
print(a1)
# [[0.4980917  0.8726201  0.73129453]
#  [0.0029339  0.16124396 0.4579657 ]]

a2 = np.random.rand()
print(a2)  # 0.9081515820816426

a3 = np.random.rand(2, 3, 4)
print(a3)
# [[[0.03399706 0.84441171 0.17392205 0.09881563]
#   [0.98804228 0.5106279  0.49711395 0.34850446]
#   [0.12695874 0.70715927 0.08024678 0.58860936]]
#
#  [[0.02316629 0.75390742 0.09401929 0.56745535]
#   [0.10507769 0.53669669 0.35367215 0.1756888 ]
#   [0.02745259 0.90007949 0.42169534 0.46447165]]]

a4 = np.random.randint(10, size=(3, 4))
print(a4)
# [[9 9 5 6]
#  [3 3 5 5]
#  [9 3 5 3]]

a5 = np.random.randint(1, 30)
print(a5)  # 23

a6 = np.random.randint(1, 30, 3)
print(a6) # [ 3 19 17]

 

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


 

1. 파이썬 홈페이지 이미지 추출

 

 

 

 

📌  이미지 위에 우클릭 ▶️ 이미지 주소 복사 버튼 클릭하면 url을 가져올 수 있다

 

 

 

 

 


 

🥑 os.path : 경로명과 파일명에 대한 유용한 함수를 제공하는 모듈

import requests
import os.path

# 1. 파이썬 공식 홈페이지에서 이미지 링크 가져옴
url = 'https://www.python.org/static/img/python-logo@2x.png'

resp = requests.get(url)

 

🥑  os.path.basename() : 입력받은 경로의 파일명을 반환

# 2. 파일 이름 가지고 오기
image_file_name = os.path.basename(url)  # 파일 이름 가져오기
print(image_file_name)  # python-logo@2x.png

 

# 3. 파일 저장.
with open(f'./output_image/{image_file_name}', 'wb') as image_file:
    image_file.write(resp.content)
    print("이미지 파일로 저장하였습니다.")

 

2. 야후 이미지 검색 페이지 추출

🥑 https://www.yahoo.com/ 에서 이미지 검색을 한 후 url을 들고 올 것

import requests
from bs4 import BeautifulSoup as bs
import pprint

# 1. 이미지 태그 가져오기
url = 'https://images.search.yahoo.com/search/images;_ylt=Awrg1fJPpOplRwQAMU5XNyoA;_ylu=Y29sbwNncTEEcG9zAzEEdnRpZAMEc2VjA3BpdnM-?p=bts&fr2=piv-web&fr=yfp-t'
resp = requests.get(url)
soup = bs(resp.text, 'html.parser')

tag_images = soup.select('li.ld a > img')
pprint.pprint(tag_images)

실행 결과


 

# 2. 이미지 저장
dir_save = './output_image/yahoo/'  # 저장 경로

for idx, tag in enumerate(tag_images):
    #print(tag.get('data-src'))
    resp = requests.get(tag.get('data-src'))
    with open(f'{dir_save}{idx + 1}.png', 'wb') as image_file:
        image_file.write(resp.content)
        #print(f'{idx+1} / {len(tag_images)}')  # 진행 상황 확인

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


 

1.  select_one() 

🥑  find가 원하는 태그를 찾는게 목적이라면 select는 CSS selector로 tag 객체를 찾아 반환
🥑  select_one()은 원하는 태그 하나만 가져오고, 태그가 많은 경우에는 맨 앞의 것만 가져옴

 

    🐰 select 계열의 메소드는 css selector 이용 가능
    🐰  '.' -> class 속성 /  '#' -> id 속성
    🐰 class : 하나의 html 에서 여러 태그에 중복 사용 가능
    🐰 id : 하나의 html에서 한번만 사용. 권장사항

# 요소 내 text 가져오기
title = soup.select_one('title')

print(title.string)  # 선택된 요소 text만
print(title.text)
print(title.get_text())
# text, get_text는 하위 text 까지 같이

 

 

1)  select_one('태그명') 사용 예제

# 다음 > 뉴스 > IT > 오늘의 연재의 첫번째 글 제목과 신문사 들고오기
url = 'https://news.daum.net/digital#1'
resp = requests.get(url)
soup = bs(resp.text, 'html.parser')

html 소스

 

tag_series = soup.select_one(('.list_todayseries li'))
pprint.pprint(tag_series)

tag_series_title = tag_series.select_one('.link_txt').text
print(f'제목: {tag_series_title}')
# 제목: 전자사전으로 인기 끌던 '샤프'...최근엔 AI 아바타와 함께

tag_series_press = tag_series.select_one('.txt_info').text
print(f'신문사: {tag_series_press}')
# 신문사: 전자신문

tag_series 실행결과

 


 

2)  select_one('CSS선택자') 예제

 

import requests
from bs4 import BeautifulSoup as bs
import pprint

# 할리스 커피 : 매장 검색
url = 'https://www.hollys.co.kr/store/korea/korStore2.do'
resp = requests.get(url)
soup = bs(resp.text, 'html.parser')

매장 테이블의 html 소스

 

# 매장 테이블 가져오기
stores = soup.select_one('#contents > div.content > fieldset > fieldset > div.tableType01 > table')
pprint.pprint(stores)

  

 

 

 

 

📌  왼쪽은 css selector로 가져온 결과이다

      ➡️ selector 소스를 가져오는 방법은 html 소스코드 중 해당 태그 위에 커서를 가져다 놓고 우클릭 ▶️ 복사 ▶️ selector 복사 버튼을 클릭하면 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

# 첫 번째 가게 관련
first_store = stores.select_one('#contents > div.content > fieldset > fieldset > div.tableType01 > table > tbody > tr:nth-child(1)')
pprint.pprint(first_store)

 

first_store 결과

 

# td:nth-child(1) -> td 태그중 첫번째
second_store_name = first_store.select_one('td:nth-child(2)')
print(second_store_name.text)
# 부산사상광장점

# td:nth-child(1) -> td 태그중 4번째
second_store_addr = first_store.select_one('td:nth-child(4)')
print(second_store_addr.text)
# 부산광역시 사상구 광장로 22 (괘법동) 2층 사상구 괘법동 565-2

 


 

2. select()

🥑  CSS selector로 지정한 태그들을 모두 가져오는 메소드로 가져온 태그들은 모두 리스트에 보관

# 네이버 환율 크롤링
# 네이버에서 '환율' 검색 후 '환율 더보기'

url = 'https://finance.naver.com/marketindex'
resp = requests.get(url)
soup = bs(resp.text, 'html.parser')
pprint.pprint(soup)

실행결과

 

# 환전고시 국가 가져오기
nations = soup.select('#exchangeList > li > a.head > h3 > span')
print(nations)  # 리스트로 반환

실행결과

 

# 나라별 환율 가져오기
exchange_rates = soup.select('#exchangeList > li > a.head > div > span.value')
print(exchange_rates)

 

# 나라별 화폐 단위와 환율 같이 출력하기
for idx, item in enumerate(nations):
    print(f'{item.text} : {exchange_rates[idx].text}')
  
'''
실행결과)
미국 USD : 1,317.50
일본 JPY(100엔) : 895.98
유럽연합 EUR : 1,440.55
중국 CNY : 182.99
'''

 


 

3. CSS selector 

 

1) 태그명 선택    ex. li, a

test = soup.select('a')

 

 

2) 하위 태그 선택   ex. ul a / ul > a

# 상위 태그 > 하위 태그
test = soup.select('li a')
test = soup.select('li > a')

 

3) 클래스 이름으로 선택   ex. li.course / .course / li.course.paid

# 태그.클래스명
test = soup.select('li.value')
# .클래스명
test = soup.select('.value')
# 태그.클래스명.클래스명 (여러 클래스가 있는 경우)
test = soup.select('li.value.fieldset')

 

 

4) id 이름으로 선택   ex. #start

# '#id이름'
test = soup.select('#list50')
# '태그명#id이름'
test = soup.select('tr#list50')

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


 

1.  BeautifulSoup

🍯  구문을 분석해서 필요한 내용만 추출 할 수 있는 기능을 가지고 있는 패키지

        ➡️  xml or html을 수프객체로 만들어서 추출하기 쉽게 만들어 준다.

from bs4 import BeautifulSoup as bs  # bs4 라이브러리에서 Beautiful Soup를 import
import requests
import pprint

# html 파일 가져오기
with open('./sample.html', 'r', encoding='utf-8') as file:
    html = file.read()

# html.parser : html 코드를 사용하기 쉽게 BeautifulSoup의 객체로 분석
soup = bs(html, 'html.parser')  
# 첫번째 인자: 분석할 내용 전달
# 두번째 인자: "html"로 분석한다는 것을 명시

print(type(soup))  # <class 'bs4.BeautifulSoup'>
print(soup)  # (html 출력)

print(soup.find('title').text)  # This is title
print(soup.find('div').text)  # Division의 약자로, 레이아웃을 나누는데 사용.
print(soup.find('h1').text.strip())  # This is heading1 text.

 


 

1) find ()

🥑  지정된 태그들 중에서 가장 첫 번째 태그만 가져오는 메소드(하나의 값만 반환)로 문자열 형태로 반환
       ➡️  일반적으로 하나의 태그만 존재하는 경우에 사용  만약 여러 태그가 있으면 첫 번째 태그만 가져옴

 

# 속성값 가져오는 경우 형식 (find, find_all 동일)
find(태그명['속성명'])
find(태그명.attrs['속성명'])
find(태그명).get(속성명)
find_all('태그명', attrs={'속성명':'값'})
# 위키피디아 '대구광역시' 페이지
url = 'https://ko.wikipedia.org/wiki/%EB%8C%80%EA%B5%AC%EA%B4%91%EC%97%AD%EC%8B%9C'
resp = requests.get(url)
soup = bs(resp.text, 'html.parser')

first_img = soup.find(name='img')  # img 태그 중에 제일 먼저 나오는 것
print(type(first_img))  # <class 'bs4.element.Tag'>
print(first_img)  
# <img alt="" aria-hidden="true" class="mw-logo-icon" height="50" 
# src="/static/images/icons/wikipedia.png" width="50"/>

target_img = soup.find(name='img', attrs={'alt': 'Daedongyeojido (Gyujanggak) 17-02.jpg'})
print(target_img)
# <img alt="Daedongyeojido (Gyujanggak) 17-02.jpg" class="mw-file-element" 
# data-file-height="3005" data-file-width="4000" decoding="async" height="376" 
# src="//upload.wikimedia.org/wikipedia/commons/thumb/c/c5/
# Daedongyeojido_%28Gyujanggak%29_17-02.jpg/500px-Daedongyeojido_%28Gyujanggak%29_17-02.
# jpg" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Daedongyeojido_
# %28Gyujanggak%29_17-02.jpg/750px-Daedongyeojido_%28Gyujanggak%29_17-02.jpg 1.5x, 
# //upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Daedongyeojido_%28Gyujanggak%
# 29_17-02.jpg/1000px-Daedongyeojido_%28Gyujanggak%29_17-02.jpg 2x" width="500"/>


 

2)  find_all() 

🥑  지정한 태그들을 모두 가져오는 메소드로 가져온 태그들은 모두 리스트에 보관

# 네이버 스포츠 페이지에서 박스 뉴스 제목 들고 옴
url = 'https://sports.news.naver.com/index.nhn'
response = requests.get(url)
soup = bs(response.text, 'html.parser')

today_list = soup.find('ul', {'class': 'today_list'})
print(today_list)

today_list_title = today_list.find_all('strong', {'class', 'title'})
pprint.pprint(today_list_title)  # 리스트로 반환

for title in today_list_title:
    print(title.text.strip())

1. today_list 결과
2. today_list_title 결과
3. 반복문 실행결과

 


 

3) find_all 사용 예제

a. 다음 뉴스 사이트 html 분석

url = 'https://news.daum.net/'
response = requests.get(url)
soup = bs(response.text, 'html.parser')


 

b. a 태그의 갯수 출력

 

   👾  html의 'a' 태그 : 다른 콘텐츠와 연결되는 하이퍼링크(hyperlink)를 정의

print('1. a 태그의 갯수')
print(len(soup.find_all('a')))  # 124

 

c. a 태그 20개만 출력

print('2. a 태그 20개만 출력')
for news in soup.find_all('a')[:20]:
    print(news.text.strip())

실행결과


 

d.  a 태그 링크 5개 출력

print('3. a 태그 링크 5개 출력')
for i in soup.find_all('a')[:5]:
    print(i.attrs['href'])
    print(i.get('href'))
    # -> 둘 중 하나만 쓰면 된다.
print("=" * 20)

 

실행결과


 

e.  특정 클래스 속성을 출력하기

print('4. 특정 클래스 속성을 출력')
print(soup.find_all('div', {'class': 'item_issue'}))
print("=" * 20)

실행결과


f.  링크를 텍스트 파일로 저장

print('5. 링크를 텍스트 파일로 저장')
file = open('../output_02/links.txt', 'w')  # 쓰기 전용 파일 생성

for i in soup.find_all('div', {'class': 'item_issue'}):
    file.write(i.find('a').get('href') + '\n')
file.close()

실행결과

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


 

1.  url을 이용해서 HTML를 가져오는 방법

 

🚀  크롤링할 때 url을 이용해서 HTML를 가져오는 방법은 크게 2가지
      a. 내장 모듈인 urllib를 사용 
      b. 외장 모듈인 requests를 사용

 

1) urllib를 사용한 경우

# 정상 접속
url = "https://www.python.org/"
code = request.urlopen(url)
print(code)  # <http.client.HTTPResponse object at 0x103f16b30>

# 비정상 접속. 비정상일 경우 에러 발생.
url = "https://www.python.org/1"
code = request.urlopen(url)
print(code)

비정상 접속인 경우 실행 결과

 


 

2) requests를 사용한 경우

# 정상 접속인 경우
url = "https://www.python.org/"
response = requests.get(url)
print(response)  # <Response [200]>. 정상적인 통신이 이루어짐.

# 페이지가 없는 경우에도 에러가 발생하지 않고, Response [404]를 리턴.
url = "https://www.python.org/1"
response = requests.get(url)
print(response)  # <Response [404]>. 해당 페이지를 찾을 수 없음

 

  👾  requests 를 사용하면 urllib 를 사용한 경우와 달리 비정상 접속인 경우 에러가 발생하지 않고 응답코드를 준다

 

    📌  응답코드 : 서버에서 클라이언트로 보내는 코드
          a. 1XX : 요청을 받았고, 작업 진행 중
          b. 2XX : 사용자의 요청이 성공적으로 수행 됨
          c. 3XX : 요청은 완료 되었으나, 리다이렉션이 필요
          d. 4XX : 사용자의 요청이 잘못됨
          e. 5XX : 서버에 오류가 발생함

 


 

2. requests 사용법

 

🚀  서버로 요청을 할 때 브라우저의 정보(User-Agent)가 같이 전달됨
        ➡️ 요청 받은 서버에서는 브라우저의 정보를 가지고 접속자가 bot인지 일반 사용자임을 구분
        ➡️ 특정 사이트의 경우 요청하는 브라우저의 정보가 일반 사용자가 아니면 접속을 막는 경우가 있음
        ➡️ requests의 경우 브라우저의 헤더 정보를 수정해서 일반 브라우저 처럼 접속할 수 있게 함

 

# requests 사용법

url = 'https://www.naver.com/'
response = requests.get(url)  # get() 또는 post() 메서드를 이용해서 html 정보를 받아옴

html = response.text  # response 객체의 text 속성을 지정하면 html 정보 반환.
print(html)  # html 소스가 출력

headers = response.headers  
print(headers)  # response 객체의 headers 속성 지정하면 헤더 정보 반환.

 

 

1) 헤더 정보 확인하기

 

  👾  requests를 이용해서 url 접속을 하면 브라우저의 정보(User-Agent)가 requests의 모듈 정보로 나옴
          ➡️ 서버에서 해당 정보를 보고 크롤링을 판단할 수 있음

from bs4 import BeautifulSoup as bs
import requests

url = 'https://planet-trade.kr/header_info.php'

response = requests.get(url)  # 브라우저 접속 역할을 파이썬 requests가 해줌
soup = bs(response.text, 'html.parser')
print(soup)
# 접속 IP : 58.149.46.252
# 접속 정보 : python-requests/2.31.0

url 주소로 접속했을 때 브라우저의 정보

 


 

2) requests에서 헤더 정보를 변경

request_headers = {
    'User-Agent': ('(url 주소로 들어갔을 때 나오는 브라우저 접속 정보)'),
    'Referer': '',
}

resp = requests.get(url, headers=request_headers) # 변경된 헤더로 접속, 정보 가져옴
soup = bs(resp.text, 'html.parser')
print(soup)

# 접속 IP : 58.149.46.252
# 접속 정보 : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
# (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36

 


 

2. 크롤링 할 때 운영자 의사 확인

 

🚀  모든 크롤링이 불법은 아니지만 하지만 운영자의 의사에 상관없이 무단으로 크롤링하는 것은 불법
🚀  운영자의 크롤링 허용 여부를 알 수 있는 방법은 'robot.txt' 로 확인
        ➡️ allow는 허용, disallow는 검색 불가

 

    💡  robots.txt 설정 정보 안내 사이트

           https://searchadvisor.naver.com/guide/seo-basic-robots
           https://developers.google.com/search/docs/advanced/robots/intro?hl=ko

 

robots.txt 설정하기

robots.txt는 검색로봇에게 사이트 및 웹페이지를 수집할 수 있도록 허용하거나 제한하는 국제 권고안입니다. IETF에서 2022년 9월에 이에 대한 표준화 문서를 발행하였습니다. robots.txt 파일은 항상

searchadvisor.naver.com

 

robots.txt 소개 및 가이드 | Google 검색 센터  |  문서  |  Google for Developers

robots.txt는 크롤러 트래픽을 관리하는 데 사용됩니다. robots.txt 소개 가이드에서 robots.txt 파일의 정의와 사용 방법을 알아보세요.

developers.google.com

 

urls = ['https://www.naver.com/', 'https://ko.wikipedia.org/']
filename = 'robots.txt'

for url in urls:
    file_path = url + filename
    print(file_path)
    resp = requests.get(file_path)
    print(resp.text)
    print("\n")

실행 결과

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

+ Recent posts