Python/데이터분석

Python 셀레니움

dustKim 2024. 5. 22. 00:16
셀레니움

 

- 브라우저를 컨트롤할 수 있도록 지원하는 라이브러리이다.

더보기
!pip install selenium
!pip install chromedriver_autoinstaller

 

셀레니움과 크롬드라이버 오토인스톨러를 설치해 준다.

크롬드라이버 오토인스톨러는 셀레니움이 구글 크롬 브라우저를 제어할 수 있도록 도와주는 별도의 실행 파일이다.

 

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

#웹 드라이버 객체 생성
driver = webdriver.Chrome()

# 구글 홈페이지 열기
driver.get("https://www.google.com")

#검색창 요소 찾기
search = driver.find_element("name", 'q')

#검색어 입력
search.send_keys('미세먼지')

#검색어 실행
search.send_keys(Keys.RETURN)

 

 

from selenium import webdriver: 셀레니움 라이브러리의 webdriver 모듈을 import 하면, 웹 브라우저를 열고 닫을 수 있다. 

from selenium.webdriver.common.keys import Keys: 셀레니움에서 제공하는 keys 클래스를 import 하면, 키보드의 키들을 사용할 수 있다. Keys.RETURN은 엔터 키를 나타낸다.

 

 

실행시켜 주면 자동으로 크롬을 열고 검색을 해준다.

 

  • 예제 1
더보기

네이버 웹툰에서 베스트댓글 가져오기.

driver = webdriver.Chrome()
driver.get("https://comic.naver.com/webtoon/detail?titleId=783053&no=134&week=tue")

 

웹 드라이버 객체로 크롬을 여는데 주소를 넣으면 그 주소 페이지를 연다.

 

from bs4 import BeautifulSoup

soup = BeautifulSoup(driver.page_source)

cboxList = soup.findAll("span", {"class", "u_cbox_contents"})

print("***************베스트 댓글******************")
for i in range(len(cboxList)):
    comment = cboxList[i].text.strip()
    print(comment)
    print('-'*30)

 

저번에 했던 BeautifulSoup을 import 하고, driver.page_source를 사용하여 셀레니움을 통해 열린 웹 페이지 HTML소스를 가져온다.

그리고 댓글을 가져오기 위해서 findAll을 사용하여 배열에 담아주고 반복문을 통해 출력한다.

결과

결과 화면을 보면 댓글을 가져온 것을 알 수 있다.

 

  • Xpath

- 기존의 컴퓨터 파일 시스템에서 사용하는 경로 표현식과 유사한 경로 언어이다.

더보기

위에 했던 네이버 전체 댓글 가져오기를 예제로 해보자.

driver.find_element("xpath", "/html/body/div[1]/div[5]/div/div/div[5]/div[1]/div[3]/div/div/div[4]/div[1]/div/ul/li[2]/a/span[2]").click()

soup = BeautifulSoup(driver.page_source)
comment_area = soup.findAll("span", {"class", "u_cbox_contents"})
print(comment_area)

print("***************전체 댓글******************")
for i in range(len(cboxList)):
    comment = cboxList[i].text.strip()
    print(comment)
    print('-'*30)

 

find_element를 사용하여 xpath의 경로를 준다. xpath의 경로는 해당 HTML 소스에서 마우스 우클릭을 하면 Copy가 있는데, Copy를 클릭하면 Copy full Xpath가 있다. 그것을 가져오면 된다.

그리고 click() 메서드를 사용하여 특정 요소를 클릭하게 된다.

 

기본적으로 베스트 댓글을 보여주는 웹페이지에서 xpath와 click을 이용하여 전체 댓글로 변환하게 되는데 저번에 했던 것과는 다르게 동적으로 작용하게 된다.

 

  • 예제 2
더보기

인스타그램 로그인, 해시태그 검색, 스크롤 내리기, 사진 클릭하기, 좋아요 및 댓글달기.

!pip install selenium
!pip install chromedriver_autoinstaller

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

 

기본적으로 import 해줘야 하는 것들을 해준다.

 

#로그인
def login(id, pw):
    input_id = driver.find_element("xpath", "/html/body/div[2]/div/div/div[2]/div/div/div[1]/section/main/article/div[2]/div[1]/div[2]/form/div/div[1]/div/label/input")
    input_pw = driver.find_element("xpath", "/html/body/div[2]/div/div/div[2]/div/div/div[1]/section/main/article/div[2]/div[1]/div[2]/form/div/div[2]/div/label/input")
    input_id.send_keys(id)
    input_pw.send_keys(pw)
    driver.find_element("xpath", "/html/body/div[2]/div/div/div[2]/div/div/div[1]/section/main/article/div[2]/div[1]/div[2]/form/div/div[3]/button").click()

#해시태그 검색
def search(hashtag):
    url = f"https://instagram.com/explore/tags/{hashtag}/"
    driver.get(url)

#좋아요 및 댓글달기
def like_and_comment(comment):
    #원하는 게시물 클릭
    xpath = '/html/body/div[2]/div/div/div[2]/div/div/div[1]/div[1]/div[2]/section/main/article/div/div[2]/div/div[1]/div[2]/a'
    driver.find_element("xpath", xpath).click()

    #좋아요 버튼 누르기
    like_xpath = "/html/body/div[7]/div[1]/div/div[3]/div/div/div/div/div[2]/div/article/div/div[3]/div/div/section[1]/span[1]/div/div"
    driver.find_element("xpath", like_xpath).click()
    driver.find_element("xpath", like_xpath).click()
	
    #댓글 달기
    reply_xpath = ""
    driver.find_element("xpath", reply_xpath).click()
    driver.find_element("xpath", reply_xpath).send_keys(comment)
    
    
    
    
#실행
driver = webdriver.Chrome()
driver.get("https://www.instagram.com/")
driver.implicitly_wait(3)

id = "id를 넣어주면 된다."
pw = "pw를 넣어주면 된다."

login(id, pw)
time.sleep(4)

hashtag = "사과"
search(hashtag)
time.sleep(4)

like_and_comment("안녕하세요. 잘 보고갑니다.")

 

함수로 만들어 보았다.

먼저 로그인, xpath를 이용하여 열린 웹 페이지에서 아이디 입력창과 비밀번호 입력 창을 선택하여 내용을 넣어준다.

그리고 로그인 버튼도 xpath로 선택을 해주고 click으로 누르게 만들면 로그인을 하게 된다.

 

로그인 후 해시태그를 검색하는 것은 간단하게 url에서 원하는 검색어를 바꿔주면 되기에 f-string을 변수를 받아주면 된다.

 

좋아요와 댓글달기 등도 xpath를 이용하면 할 수 있는데, instagram은 xpath가 계속해서 변화하기에 그냥 이론적으로만 알고 넘어가자.

 

  • 예제 3
더보기

픽사베이에서 원하는 사진 가져오기

!pip install selenium
!pip install chromedriver_autoinstaller
import time
from urllib.request import Request, urlopen
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

 

from urllib.request import Request, urlopen에서 Request는 url 요청을 생성하기 위한 것이고, urlopen은 url을 열고, 반환된 데이터를 읽어오는 역할을 한다.

 

driver = webdriver.Chrome()
url = 'https://pixabay.com/ko/images/search/강아지'
driver.get(url)

image_xpath = "/html/body/div[1]/div[1]/div/div[2]/div[3]/div/div/div/div[1]/div/a/img"
image_url = driver.find_element("xpath", image_xpath).get_attribute("src")

image_byte = Request(image_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
f = open("dog.jpg", "wb")
f.write(urlopen(image_byte).read())
f.close()

 

해당하는 url에 웹 브라우저를 열고, image_xpath로 이미지의 요소를 저장한다.

find_element로 웹 페이지에서 해당 이미지 요소를 찾고, get_attribute("src")를 사용하여 이미지 요소의 "src" 속성을 가져와 이미지의 url을 추출한다. (image_xpath는 해당 이미지의 요소를 가리키는 경로를, image_url은 그 경로에서 해당 이미지의 url을 가져오는 것이다.)

마지막으로 Request요청을 보내 이미지 url에 대해 dog.jpg라는 이름으로 파일을 열면, 선택한 강아지 사진이 폴더에 생성된다.

 

  • 문제
더보기

여러 개 이미지 수집하기.

driver = webdriver.Chrome()
url = "https://pixabay.com/ko/images/search/고양이"
driver.get(url)


for i in range(10):
    image_xpath = f"/html/body/div[1]/div[1]/div/div[2]/div[3]/div/div/div/div[{i+1}]/div/a/img"
    image_url = driver.find_element("xpath", image_xpath).get_attribute("src")
    print(image_url)
    image_byte = Request(image_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
    f = open(f"cat{i+1}.jpg", "wb")
    f.write(urlopen(image_byte).read())
    f.close()
    time.sleep(1)

 

위에서는 원하는 이미지 하나를 선택했다. 이번에는 여러 가지 이미지를 선택해 보겠다.

나는 각 이미지의 xpath를 사용하여 반복문을 돌려보았다. 각 이미지의 xpath를 확인해 보면 div[change]가 변하는 부분이 있어서 그것을 중점으로 했다.

 

하지만... 더 좋은 방법이 있었다...

 

from selenium.webdriver.common.by import By  # 상수 정의 모듈

 

일단 그전에 상수를 정의하는 모듈을 깔아주자. 사실 사용하지 않아도 된다.

driver = webdriver.Chrome()
url = "https://pixabay.com/ko/images/search/강아지"
driver.get(url)
driver.implicitly_wait(3)


for _ in range(20):
    driver.execute_script("window.scrollBy({ top: window.innerHeight, behavior: 'smooth' })")
    time.sleep(1)
# for i in range(20):
#     driver.execute_script(f"window.scrollTo(0, 1000 * {i})")
#         # f'window.scrollTo(0, document.body.scrollHeight/(21-{i}))')
#     time.sleep(0.2)

image_area_xpath = "/html/body/div[1]/div[1]/div/div[2]/div[3]"
image_area = driver.find_element(By.XPATH, image_area_xpath)
image_elements = image_area.find_elements(By.TAG_NAME, "img")

image_urls = []

for image_element in image_elements:
    image_url = image_element.get_attribute("src")
    if not image_url is None:
        print(image_url)
        image_urls.append(image_url)
        

for i in range(len(image_urls)):
    image_url = image_urls[i]
    # https://cdn.pixabay.com/photo/2023/03/29/16/13/labrador-retriever-7885881_640.jpg
    url = parse.urlparse(image_url)
    name, ext = os.path.splitext(url.path)
    image_byte = Request(image_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
    f = open(f"dog{i}.{ext}", "wb")
    f.write(urlopen(image_byte).read())
    f.close()

 

먼저 내가 생각한 것처럼 이미지 자체의 xpath를 사용한 것이 아니고 그 페이지의 xpath를 사용한 것이다.

페이지의 url을 받아 사용하는데 그 안에서 fine_element를 사용하여 이미지 요소로 잡아주는 것이다. 그러면 반복문을 통해서 전체 이미지를 가져올 수 있다...!

하지만 문제가 하나 있었다. 그것은 스크롤! 이미지가 스크롤로 내려가서 화면에 보여야만 blank가 나오지 않는다... 그래서 스크롤을 먼저 다 해주고, 여기서 바로 마지막 스크롤까지 내리면 안 되고 조금씩 내려가면서 이미지를 불러올 수 있어야 한다. 코드는 위를 참고하자. 2개의 버전이 있다.

아무튼 스크롤을 사용하여 이미지를 웹상에서 나타나게 한 후 이미지의 url을 받아보면 blank가 없다!

그런 후 저장하면 끝이다! 👍

 

  • + 문제
더보기

위에서 여러 가지 이미지를 가져왔다. 

이번에는 이미지를 한 페이지가 아닌 원하는 페이지만큼 가져오고, 디렉토리 안에 넣어주며, 함수로 만드는 것이다.

 

import os
from urllib import parse

 

먼저 디렉토리를 만들어 줄 모듈을 깔아주자..!

def crawl_and_svae_imgage(keyword, pages):
    for i in range(pages):
        url = f"https://pixabay.com/ko/images/search/{keyword}/?pagi={i+1}"
        driver.get(url)
        driver.implicitly_wait(3)

        for i in range(20):
            driver.execute_script(f"window.scrollTo(0, 1000 * {i})")
            time.sleep(0.5)
                
        image_area_xpath = "/html/body/div[1]/div[1]/div/div[2]/div[3]"
        image_area = driver.find_element(By.XPATH, image_area_xpath)
        image_elements = image_area.find_elements(By.TAG_NAME, "img")
        
        image_urls = []
        
        for image_element in image_elements:
            image_url = image_element.get_attribute("src")
            if not image_url is None:
                print(image_url)
                image_urls.append(image_url)

    if not os.path.exists(keyword):
        os.mkdir(keyword)
            
    for i in range(len(image_urls)):
        image_url = image_urls[i]
        url = parse.urlparse(image_url)
        filename = image_url.split('/')[-1]
        image_byte = Request(image_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
        f = open(f"{keyword}/{filename}", "wb")
        f.write(urlopen(image_byte).read())
        f.close()

 

기본적인 틀은 비슷하다. 변수로 keyword와 pages를 받아서 keyword로 검색해서 나온 이미지들을 원하는 pages 만큼 저장하는 것이다. f 스트링을 사용하여 적절하게 변수를 넣어주면 된다. 그리고 디렉토리를 만들어 넣어주면 끝이다...! 생각보다 쉽지만 처음에 만들려면 생각이 잘 나지 않는다. 수련이 부족하다...

'Python > 데이터분석' 카테고리의 다른 글

Python seaborn, folium, 상권별 업종 밀집 통계 데이터  (0) 2024.05.28
Python 가상 온라인 쇼핑몰 데이터  (0) 2024.05.28
Python MatPlotlib  (0) 2024.05.27
Python 넘파이(Numpy)  (0) 2024.05.22
Python 크롤링  (0) 2024.05.21