Programming

[python] Selenium 웹스크래핑 - 제목과 내용 수집하기

IT오이시이 2023. 4. 28. 11:09
728x90

selenium을 이용하여 웹페이지 크롤링- 제목과 내용 수집 하기

웹페이지 크롤링을 하다가 뉴스나 블로그 제목과 내용을 따로 구분해서 수집을 해야한다면 selenium을 많이 사용하게 됩니다.  selenium을 이용하여 특정 영역의 데이터를 추출하고 저장하는 예시 코드를 작성해 보았습니다.
 

Selenium은

Selenium은 웹 애플리케이션을 테스트하기 위한 오픈 소스 자동화 도구입니다. 이를 사용하면 브라우저를 자동으로 제어하고, 사용자가 웹 사이트에서 수행하는 것과 같은 작업을 수행할 수 있습니다. Selenium은 여러 언어로 작성된 클라이언트 라이브러리를 제공합니다. 이를 사용하면 Python, Java, Ruby, C#, JavaScript 등의 언어를 사용하여 자동화 테스트를 작성할 수 있습니다. Selenium을 사용하여 웹 페이지를 자동으로 테스트하거나 웹 스크래핑을 수행할 수 있습니다.
 
 

[python] Selenium 웹스크래핑 - 웹페이지 자동화 테스트
- 웹페이지 객체 찾는 방법 정리 - https://couplewith.tistory.com/427

- 웹페이지 링크 찾고 이동하기 -  https://couplewith.tistory.com/428 

- 웹페이지 크롤링- 제목과 내용 수집하기 -  https://couplewith.tistory.com/424

 

 

웹페이지 영역을  지정하여  추출하는 방법

웹페이지의 특정 영역의 html tag element를 select 하여 추출하는 방법은  두가지 방식이 있습니다.

1. find_element_by_css_selector() 로 페이지가 로딩이 된것을 가정하고 특정 영역을 찾는 것이고, 

2. WebDriverWait(driver,

3. until(EC.presence_of_element_located() ) 을 이용하여 페이지 컨텐츠에 로딩된 Tag로 element 를 찾는 것 입니다.
    이 함수의 장점은 페이지  로딩되지 않아 오류가 발생하는 것을 방지 할 수 있습니다. ( 예시는  3초 정도 대기후 element를 찾는 것입니다.)

[웹페이지 html tag select를 통해 데이터 추출 하는 방법 두가지 ]

1. element = driver.find_element_by_css_selector("#articleTitle")

2. element = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, "#articleTitle")))


[[페이지 element 나 Tag가 없는 경우]

위의 두 예시는 element가 존재하지 않거나 페이지 로딩이 느리게 되는 경우 오류가 발생됩니다.
그래서 다음과 같은 try ~~ exception ~ finally  문을 이용 하여 오류가 발생되어도 프로그램이 종료 되지 않도록 할 수 있습니다.

위의 두가지 html tag의  selector를 이용하는 방법에 따라 exception은 다르게 나옵니다.

* driver.find_element_by_css_selector() 는 NoSuchElementException 이 발생되며, 

* WebDriverWait() 은 TimeoutException 이 발생 됩니다.

* Exception 처리로  영역을 select 하는 방법은  아래와 같습니다.

from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

try:
     element = driver.find_element_by_css_selector("#articleTitle")
except NoSuchElementException:
    print("요소가 존재하지 않습니다.")


try:
    wait = WebDriverWait(driver,10) element = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR,
"#articleTitle")))
except TimeoutException:
    print("요소가 나타나지 않았습니다.")


셀레니움으로 웹페이지 게시글의 내용을 찾아 크롤링 하는 소스를 만들어 보자



  [  웹페이지 크롤링 프로그램 설명 ]  

1. 뉴스(게시물)의 목록에서 첫번째 아티클(항목)을 찾는다.

2. 선택된 게시글의  링크를 클릭한다.

3. 게시글 content 페이지가 로딩되면 제목과 내용을 복사한다.

4. 복사된 제목과 내용을 파일로 저장한다.


 아래 예시를 작동하기 위해서는 명시적인 HTML의 Tag에서 명확한 CSS 영역을 알고 있어야 합니다.

1) 웹브라우저 도구> 개발자 도구 를 이용하여 뉴스 목록 중에서  첫번째 아티클을 찾는다.

     (1)  아래 버튼을 이용하면 웹페이지 소스와 화면에 보이는 영역이 선택 됩니다.

 
 (2) 선택된 영역에서 CSS Select 되는 값을 찾습니다.

 
 (3) 우측 HTML 소스 창에서 선택된 영역에서 마우스 오른쪽 클릭을 하면 아래와 같이 선택하는 내용이 보입니다.
         복사 > 요소 복사 > Selector 복사 를 하면 됩니다.
     

 

 [selector 복사 한 내용을 아래 소스에 배치 합니다.]  
     #ct > div > section.main_content > div.main_brick > div > div:nth-child(1) > div.main_brick_item._channel_news_preview_wrapper > div:nth-child(1) > div > div:nth-child(2) > a > div.cjs_news_tw > div

 

[예시 1]  selenium을 이용한 웹페이지 크롤링

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 웹 드라이버 로드
driver = webdriver.Chrome()

# 페이지 접속
driver.get("https://news.naver.com")

# 첫 번째 기사 클릭
first_article = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, "#ct > div > section.main_content > div.main_brick > div > div:nth-child(1) > div.main_brick_item._press_main_status_wrapper > div > div.cjs_news_flash_wrap.cjs_nf_close._newsflash_wrapper > div.cjs_nf_list._item_list > a:nth-child(2) > div > h4"))
)
first_article.click()

# 기사 제목과 내용 추출
title = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "#articleTitle"))
).text

content = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "#articleBodyContents"))
).text

# 추출한 데이터 저장
with open('article.txt', 'w', encoding='utf-8') as f:
    f.write(f"제목 : {title}\n\n")
    f.write(content)

# 브라우저 닫기
driver.quit()

 

[예시2]  try  ~ exception을 이용한 웹크롤링

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC



# 직접 tag 내용 추출
def get_tag_element(tag_name):
    element = None
    status = False
    try:
        element = driver.find_element_by_css_selector(tag_name)
        status = True
    except NoSuchElementException:
        print("요소가 존재하지 않습니다.",tag_name)
    finally:
        return element, status

#  화면 로딩 대기 후 tag 항목 추출 : 태그가 화면에 나타날 때까지 기다린 뒤 해당 요소를 반환
def get_tag_element_wait(tag_name, wait_time=10):
    element = None
    status = False
    try:
        wait = WebDriverWait(driver, wait_time)
        element = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, tag_name)))
        status = True
    except TimeoutException:
        print("요소가 존재하지 않습니다.",tag_name)
    finally:
        return element, status

####################################################
# 웹 드라이버 로드
driver = webdriver.Chrome()

# 경제 - 헤드라인
news_url="https://news.naver.com/main/main.naver?mode=LSD&mid=shm&sid1=101"
tag_first_article = "#main_content > div > div._persist > div:nth-child(1) > div:nth-child(1) > div.cluster_body > ul > li:nth-child(1) > div.cluster_text > a"
tag_title = "#title_area"
tag_contents = "#contents"



# 첫 번째 기사 클릭하여 뉴스 본문으로 이동하여  제목과 내용을 추출 한다.

# (1) 페이지 접속
driver.get(news_url)
driver.implicitly_wait(5) # 10초 대기

# (2) 특정 영역을 포함한 부모 요소를 찾아서 링크를 클릭한다.
(first_article, status) = get_tag_element(tag_first_article)
if first_article != None:
    first_article.click()
else:
    print(" article not found")
    exit(1)

# (3) 기사 본문 페이지 로딩을 위해 명시적으로 대기 한다.
driver.implicitly_wait(3) # 10초 대기


# (4) 기사 본문의 제목과 내용을 수집한다.
(title, status ) = get_tag_element(tag_title)
print(title, status, tag_title )

(content, status ) = get_tag_element(tag_contents)
print(content, status, tag_contents )



# (5) 기사 본문의 제목과 내용을 저장한다.
with open('article.txt', 'w', encoding='utf-8') as f:
    f.write(f"제목 : {title}\n\n")
    f.write(content)

# (6) 브라우저 닫고 종료한다.
driver.quit()
728x90
반응형