python/data crawling

8. selenium (3) - webdriverWait

Abokadoh 2023. 2. 15. 15:17

selenium을 활용하여 특정 element의 로딩기다리고 데이터를 크롤링해보자

element의 로딩을 기다린다는 말은 예를 들어 페이지가 완전히 Load되고 나서 정보를 긁어오고 싶을 때를 말한다.

ex) 뉴스의 댓글 수는 처음 페이지 요청시에 곧바로 불러지지 않는다. 이런 경우 로딩을 완전히 기다리고 데이터를 크롤링하는 방법을 사용해야 할 수 있다.

 

네이버 기사의 댓글 수를 추출해보겠다.

 

우선 네이버 기사의 html 문서를 크롤링해보자

chorme_drvier = '/Users/choehyeogjae/Desktop/chromedriver'
driver = webdriver.Chrome(chrome_drvier)

url = 'https://n.news.naver.com/mnews/article/081/0003018031?sid=105'

driver.get(url)

scr = driver.page_source # scr은 string 타입의 html문서임

코드를 실행하면 scr객체str typehtml 문서가 들어간다.

 

이것을 BeautifulSoup을 사용하여 분석에 용이하게 만들어주자.

from bs4 import BeautifulSoup
soup = BeautifulSoup(scr)

개발자도구에서 확인한 댓글수는 span tag, class = u_cbox_count에 있므로 select_one 함수를 사용해보자

soup.select_one('span.u_cbox_count')

내가 원하는 텍스트값이 추출되지 않았다.

왜지?

 

그 이유는 댓글의 숫자 같은경우 우리가 처음에 url을 요청했을 때 바로 응답되는 데이터가 아닌 일정 시간(0.x초)후에 돌아오는 데이터이기 때문이다..

 

이런 경우 webdriverWait를 사용하면 해결할 수 있다.

chrome_driver = '/Users/choehyeogjae/Desktop/chromedriver'
driver = webdriver.Chrome(chrome_driver)

url = 'https://news.naver.com/main/read.nhn?mode=LSD&mid=shm&sid1=105&oid=081&aid=0003018031'

driver.get(url)

myElem = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '.u_cbox_count')))

scr = driver.page_source

soup = BeautifulSoup(scr)

comment_area = soup.select_one('.u_cbox_count')

driver.close()

comment_area.get_text()

WebDriver(driver, 10)

  • WebDriverWait을 통해 driver를 ‘최대’ 10초동안 기다린다.
    • 이 때 10초가 넘어가면 NoSuchElementException, ElementNotVisibleException 에러가 뜰 것이다.

until(EC.presence_of_element_located((By.CSS_SELECTOR, ‘.u_cbox_count’)))

  • 언제까지? ; u_cbox_count를 css selector로 찾을 때까지~
  • 이때 해당 element가 나오면 ECTRUE를 리턴하는 것이다.

 

 

실습 ; 댓글 끌어오기
import requests
def get_daum_news_comments(news_id):
    headers = {
        'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJncmFudF90eXBlIjoiYWxleF9jcmVkZW50aWFscyIsInNjb3BlIjpbXSwiZXhwIjoxNTY0Njc4NjQ1LCJhdXRob3JpdGllcyI6WyJST0xFX0NMSUVOVCJdLCJqdGkiOiJlZGUxNzM0MS1hNWNjLTRmYmQtODJkMy0zZTMwOGMwMGViZTEiLCJjbGllbnRfaWQiOiIyNkJYQXZLbnk1V0Y1WjA5bHI1azc3WTgifQ.Cxs2g1hUUAjyuSrUDAhaKGol8vvyW-_mwPtV0X0DvEU',
        'Origin': 'https://news.v.daum.net',
        'Referer': 'https://news.v.daum.net/v/20190728165812603',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    url_template = 'https://comment.daum.net/apis/v1/posts/@{}/comments?parentId=0&offset={}&limit=10&sort=RECOMMEND&isInitial=false'
    offset = 0
    comments = []
    while True:
        url = url_template.format(news_id, offset)
        resp = requests.get(url, headers=headers)
        data = resp.json()
        if not data:
            break
            
        comments.extend(data)
        offset += 10
        
    return comments

len(get_daum_news_comments('20190728165812603'))