Web 심화 3 - 웹스크래핑, 셀레니움

호호빵·2022년 5월 1일
1

Web

목록 보기
8/12

브라우저 제어

  • 내가 필요한 정보를 얻기 위해 로그인, 스크롤 내리기 등 브라우저를 동작시키는 것
  • 웹스크래핑 뿐만 아니라 브라우저 제어 기능을 응용하면 정해진 시간에 게시판에 글을 작성하는 등 다양한 업무를 자동화 가능

웹스크래핑(Web scraping)

  • 웹 페이지에서 우리가 원하는 부분의 데이터를 수집해오는 것
  • 크롤링(Crawling) : 자동화하여 주기적으로 웹 상에서 페이지들을 돌아다니며 분류/색인하고 업데이트된 부분을 찾는 등의 일을 하는 것

멜론 차트에서 정보 가져오기

1. requests 와 beautifulsoup4로 스크래핑

  • 가상환경 세팅(flask, pymongo, bs4, request, selenium 설치)
  • app.py, statice, templates(index.html) + prac_scraping.py 파일 만들기
  • 멜론 차트에서 각 노래 제목, 가수 이름, 좋아요 수 가져오기
  • 선택자로 가져오기 코드를 붙여넣어도 좋아요수는 0으로 가져옴
    -> 멜론 차트처럼 동적인 웹페이지를 스크래핑할 때는 브라우저에 띄운 후 소스코드를 가져오는 방법 사용해야함

2. selenium으로 스크래핑

  • 가상환경 세팅
  • app+s+t+prac_scraping.py 파일 만들기
  • 크롬 드라이버 다운받아서 설치
  • prac_scraping.py에 아래처럼 코드 만들기
# app.py
from flask import Flask, render_template, request, jsonify, redirect, url_for
from pymongo import MongoClient


app = Flask(__name__)

client = MongoClient('내AWS아이피', 27017, username="아이디", password="비밀번호")
db = client.dbsparta_plus_week3


@app.route('/')
def main():
    return render_template("index.html")


if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)
    
    
    
# prac_scraping.py
from bs4 import BeautifulSoup
from selenium import webdriver
from time import sleep

driver = webdriver.Chrome('./chromedriver')  # 드라이버를 실행


url = "https://www.melon.com/chart/day/index.htm"
# 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(url, headers=headers)

driver.get(url)  # 드라이버에 해당 url의 웹페이지를 띄움
sleep(5)  # 페이지가 로딩되는 동안 5초 간 기다림

req = driver.page_source  # html 정보를 가져옴
driver.quit()  # 정보를 가져왔으므로 드라이버는 끄기

# soup = BeautifulSoup(data.text, 'html.parser')
soup = BeautifulSoup(req, 'html.parser')  # 가져온 정보를 bs4으로 파싱

songs = soup.select("#frm > div > table > tbody > tr")
print(len(songs))

for song in songs:
    title = song.select_one("td > div > div.wrap_song_info > div.rank01 > span > a").text
    artist = song.select_one("td > div > div.wrap_song_info > div.rank02 > span > a").text
    likes = song.select_one("td > div > button.like > span.cnt").text
    print(title, artist, likes)

가져온 결과 ->

Selenium

브라우저 제어 프로그램

  • 웹사이트를 테스트하기 위한 도구로, 브라우저 동작 자동화 가능
  • 브라우저를 띄운 후 소스 가져오기
  • 브라우저 동작을 제어해 마치 사람이 이용하는 것처럼 웹페이지를 요청하고 응답을 받아올 수 있음(스크롤, 버튼클릭 하기 등)

네이버 검색에서 이미지 소스 불러오기


# 5초 후 뜨는만큼의 이미지만 불러오기
from bs4 import BeautifulSoup
from selenium import webdriver
from time import sleep


driver = webdriver.Chrome('./chromedriver')

url = "https://search.naver.com/search.naver?where=image&sm=tab_jum&query=%EC%95%84%EC%9D%B4%EC%9C%A0"
driver.get(url) 		  # 드라이버에 해당 url 띄움
sleep(5)  				  # 페이지가 로딩 5초 기다림

req = driver.page_source  # html의 정보 가져옴
driver.quit()			  # 가져오고 나서 끔

soup = BeautifulSoup(req, 'html.parser')
images = soup.select(".tile_item._item ._image._listImage")
print(len(images))

for image in images:
    src = image["src"]
    print(src)

# 1000픽셀만큼 스크롤 내린만큼도 가져오기

driver.get(url)   # url 띄움
sleep(5)		  # 5초 로딩 기다림
driver.execute_script("window.scrollTo(0, 1000)")  # 1000픽셀만큼 내리기
sleep(2)		  # 2초 로딩 기다림
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
sleep(7)						# 화면의 밑까지 스크롤해서 이미지 소스 가져오기

# excute.script("")  ""라는 명령을 실행해줘


네이버 지도 API

  • API 사용신청 후 id, key 받기, 내 연결 주소 추가
  • templates 폴더에 prac_map.html 만들기
  • your_client_id에 신청 후 받은 id 입력
  • app.py에서 main()에 연결된 html을 prac_map.html로 바꾸고 실행

다양한 기능 다뤄보기

  • 확대/축소 버튼 넣기
  • 마커 띄우기(마커 오브젝트 만들기)
  • 마커 이미지 바꾸기
  • 정보창 띄우고 닫기
  • 마커를 누를 때마다 정보창이 나왔다 들어가기
	naver.maps.Event.addListener(marker, "click", function () {}
	네이버 맵의 이벤트 등록, 마커를 기준으로 클릭이 일어났을 때 함수 실행
# prac_map.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport"
              content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
        <title>간단한 지도 표시하기</title>
        <script type="text/javascript"
                src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=YOUR_CLIENT_ID"></script>
        <script src=" https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

        <style>
            #map {
                width: 100%;
                height: 400px;
            }
        </style>

        <script>
        	# 지도를 만들어 map변수에 놓기
            # 지도를 중앙에 놓고(위도,경도), zoom 10정도 당기기
            $(document).ready(function () {
                let map = new naver.maps.Map('map', {
                    center: new naver.maps.LatLng(37.4981125, 127.0379399),
                    zoom: 10
                    # 확대축소 버튼
                    zoomControl: true,
                    zoomControlOptions: {
                        style: naver.maps.ZoomControlStyle.SMALL,
                        position: naver.maps.Position.TOP_RIGHT
                    }
                });
                
                # 마커 먼들고 센터에 놓기
                let marker = new naver.maps.Marker({
                    position: new naver.maps.LatLng(37.4981125, 127.0379399),
                    map: map  # 어떤map : 위에 만든 map 위에
                    icon: "{{ url_for('static', filename='rtan_heart.png') }}"
                });
                
                # 정보창 띄우기
                let infowindow = new naver.maps.InfoWindow({
                    content: `<div style="width: 50px;height: 20px;text-align: center">\
                    		  <h5>안녕!</h5></div>`,
                });
                
                # infowindow.open(map, marker);   # 내가 만든 map, marker를 기준으로 보여줘
                # infowindow.close();
                
                # 마커 클릭할 때마다 정보창 나왔다 들어가기
                naver.maps.Event.addListener(marker, "click", function () {
                  console.log(infowindow.getMap()); # 열려있을 때는 지도 반환, 닫혀있을 때는 null을 반환
                  if (infowindow.getMap()) {  	    # 열려있다면
                      infowindow.close();			# 닫기
                  } else {
                      infowindow.open(map, marker);
                  }
              });
            })
        </script>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>

맛집 지도 만들기

더보기버튼의 선택자로 버튼 클릭

# 셀레니움 드라이버로 css 선택자 요소를 찾아서 btn_more 변수로 지정
btn_more = driver.find_element_by_css_selector("#foodstar-front-location-curation-more-self > div > button")
btn_more.click()
time.sleep(5)

# 더보기버튼 10번 클릭 하기 
for i in range(10):
    try:
        btn_more = driver.find_element_by_css_selector("#foodstar-front-location-curation-more-self > div > button")
        btn_more.click()
        time.sleep(5)
    except NoSuchElementException:  # 에러가 나면
        break

함수 순서

make_card() -> get_matjips()

정보 추가하기

1. 마커 만들기

  • 네이버의 정해진 규칙을 따라얌
    makers를 전역변수로 선언해야함

make_card() 실행하는 거 밑에
make_marker(matjip) 실행해주기
info_window 로도 사용할 거라서 let marker = make_marker() 로 변수 선언해주기

2. 정보 띄우기

add_info(i, marker, matjip) 몇번째의 어떤 마커의 맛집인지
content에 temp_Html

고급 기능

스크롤

마커를 클릭했을 때
infowindow 가 열리고 중앙에 위치했을 때 스크롤 하기

("#matjip-box").animate({ scrollTop: $("#matjip-box").get(0).scrollTop + $(`#card-{i}`).position().top
}, 2000);

맛집 박스 제일 위의 높이에서 클릭한 아이번째 맛집의 높이까지 내려가줘 2초동안

맛집 박스에서 클릭했을 때

a 태그를 클릭했을 때 새창이 뜨는게 아니라 javascript 함수를 실행하고 싶다면?
...

click2center 함수만들고 make_card() 에 href에 넣기;

profile
하루에 한 개념씩

0개의 댓글