데이터 분석/웹 스크래핑

[Web Scrapping 과목평가]

eunnys 2023. 11. 7. 10:58

[문제1] 네이버 날씨 정보 스크래핑
 

from bs4 import BeautifulSoup
import requests
import datetime

res = requests.get('https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EB%82%A0%EC%94%A8')
soup = BeautifulSoup(res.text, 'lxml')

# div 태그에서 한 단계 더 아래인 h2 태그로 이동 (현재 위치)
location = soup.find('div', attrs={'class':'title_area _area_panel'}).find('h2', attrs={'class':'title'}).text 

# attrs 없어도 알아서 속성의 값으로 적용됨
weather = soup.find('span', {'class':'weather before_slash'}).text 

# div 태그 아래에 있는 모든 텍스트 값을 가져옴 (현재온도 몇 도)
temperature = soup.find('div', {'class':'temperature_text'}).text 

lowest = soup.find('span', {'class':'lowest'}).text        # 최저기온
highest = soup.find('span', {'class':'highest'}).text      # 최고기온
dust = soup.find('li', {'class':'item_today level2'}).text # 미세먼지

while True:
    print('='*30)
    print('날씨 확인 프로그램')
    print('='*30)
    print('접속 시간:', datetime.datetime.now())
    print('접속 위치:', location)
    print('-'*30)
    print('1. 현재 날씨 및 온도 확인')
    print('2. 최저/최고 온도 확인')
    print('3. 미세먼지 확인')
    print('0. 종료')
    print('-'*30)

    no = int(input('번호를 입력하세요:'))
    if no == 0:
        print('프로그램을 종료합니다.')
        break
    elif no ==1:
        print('='*30)
        print('현재 날씨 확인')
        print('='*30)
        print(weather, '/', temperature)
        print('-'*30)
    elif no ==2:
        print('='*30)
        print('최저/최고 기온 확인')
        print('='*30)
        print('최저 기온:', lowest[4:]) # 슬라이싱을 이용해 최저 기온의 숫자만 가져옴
        print('최고 기온:', highest[4:])
        print('-'*30)
    elif no ==3:
        print('='*30)
        print('미세먼지 확인')
        print('='*30)
        print(dust[7:]) # 슬라이싱을 이용해 미세먼지의 정보만 가져옴
        print('-'*30)

 


 
[문제2] 네이버에서 bts 이미지를 검색 한 후 나온 결과 중 10개의 이미지를 저장하기
 

from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
import os
import requests

driver = Chrome(service=Service(ChromeDriverManager().install()), options=ChromeOptions())
driver.get('https://www.naver.com')

ele = driver.find_element(By.ID, 'query') # 검색 필드에 대한 element 객체를 가져옴
ele.send_keys('bts')      # bts 입력
ele.send_keys(Keys.ENTER) # enter 클릭

driver.find_element(By.LINK_TEXT, '이미지').click() # 이미지 필드 클릭

time.sleep(5)

# 클릭 이벤트를 적용하려면 a 태그가 필요하기 때문의 a 태그의 CSS 선택자 값을 가져옴
bts_imgs = driver.find_elements(By.CSS_SELECTOR, '#main_pack > section.sc_new.sp_nimage._fe_image_viewer_prepend_target > div.api_subject_bx._fe_image_tab_list_root.ani_fadein > div > div > div.image_tile._fe_image_tab_grid > div > div > div > a')
print('그림 개수:', len(bts_imgs)) # 한 페이지에 50개

img_dir = './bts_img/' # 현재 경로 밑에 bts_img 폴더 생성

if not os.path.exists(img_dir): # 해당 디렉토리가 없으면
    os.makedirs(img_dir) # 해당 디렉토리를 생성
    print('폴더 생성')
else:
    print('폴더가 이미 존재합니다.')

for i, img in enumerate(bts_imgs):
    img.click() # 검색된 이미지의 a태그 클릭 (오른쪽에 큰 원본 이미지를 보여줌)
    original_img = driver.find_element(By.CLASS_NAME, '_fe_image_viewer_image_fallback_target')
    img_url = original_img.get_attribute('src') # 원본 이미지의 주소값을 가져옴

    # 이미지 url이 요청할 수 없는 프로토콜로 시작하면 스킵
    if not img_url.startswith('http'): continue
    res = requests.get(img_url) # 해당 url로 다시 요청

    with open(f'{img_dir}bts_{i:02d}.jpg', 'wb') as f: # 이미지는 bts_img 폴더 안에 저장이 됨
        print(img_url) # 이미지 url을 하나씩 출력해줌
        f.write(res.content)
    if i >= 10: break

print('BTS 사진 저장 완료')

 
 


[문제3] 멜론 사이트 최신곡 검색
 

from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

driver = Chrome(service=Service(ChromeDriverManager().install()), options=ChromeOptions())
driver.get('https://www.melon.com/new/index.htm')

soup = BeautifulSoup(driver.page_source)

# 첫번째 tr 태그의 CSS 선택자로 검색
song_list = soup.select('#frm > div > table > tbody > tr') # n번째 child 속성 값을 지워줌
print(len(song_list)) # 음악 목록 50개

# formatted string에서 정렬 문자: ^(가운데), <(기본:왼쪽 정렬), >(오른쪽 정렬)
print(f'{"곡목":^30s}{"가수":^30s}{"앨범":^30s}') # 30개 글자의 공간을 확보
print('-'*90)

for rank, song in enumerate(song_list, 1): # enumerate(두번째 값)은 시작 값 : 1부터 시작
    # class 속성의 값이 wrap_song_info인 태그가 2개여서(노래제목과 가수, 앨범명) find_all로 검색
    song_info = song.find_all('div', {'class':'wrap_song_info'}) # 2개의 element가 들어있음

    if rank > 10: break # 상위 10개만 출력 (1부터 시작하기 때문에 11에서 멈춤)

    title = song_info[0].find('div', {'class':'ellipsis rank01'}).find('a').text # div 태그 밑에 있는 a태그 안에 있는 곡명을 가져옴
    singer = song_info[0].find('div', {'class':'ellipsis rank02'}).find('a').text # div 태그 밑에 있는 a태그 안에 있는 가수이름을 가져옴
    album = song_info[1].find('div', {'class':'ellipsis rank03'}).find('a').text # div 태그 밑에 있는 a태그 안에 있는 앨범명을 가져옴

    print(f'{rank}.{title:<30s}|{singer:<30s}|{album:<30s}')