오늘은 NLP Task 프로젝트에서 도움될만한 글을 적어보겠습니다.
네이버 블로그, 지식iN, 뉴스 등은 API로 크롤링할 수 있습니다.
자세한 내용은 아래 링크 활용해주시면 감사하겠습니다.
그래서 이번에는 네이버 블로그가 아닌, 티스토리 블로그 텍스트를 추출해보도록 하겠습니다.
티스토리 블로그와 네이버 블로그는 html 구조가 달라서 다른 방식으로 크롤링해야 된답니다.
1. Web Driver 준비, url 입력
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
import time
## Chrome WebDriver 설정
driver = webdriver.Chrome()
## 크롤링할 URL
blog_url = 'https://dangingsu.tistory.com/42'
driver.get(blog_url)
time.sleep(3)
2. 추출할 부분의 CLASS or ID 등 확인
chrome webdriver로 웹페이지를 열었다면 추출할 부분의 class나 id, css 등을 확인해야 합니다.아래와 같이 페이지에서 F12 키를 누르면 개발자 도구가 열리고 여기서 확인할 수 있습니다.
그런데 위 경우처럼 CLASS가 상위 항목에만 있고 하위 클래스에서는 CLASS NAME이 없다면 아래처럼 copy XPATH로 재설정할 수 있습니다.
그러면 이번에는 내용 부분을 추출해볼까요?
아래 사진처럼 class 부분을 찾았습니다.
이를 기반으로 코드를 작성해볼게요.
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
import time
# Chrome WebDriver 설정
driver = webdriver.Chrome()
# 크롤링할 URL
blog_url = 'https://dangingsu.tistory.com/42'
driver.get(blog_url)
time.sleep(3)
# 포스트 제목 추출 (XPATH 사용)
try:
path = '//*[@id="content"]/div/div[1]/div/h1'
title = driver.find_element(By.XPATH, path).text
print("Title:", title)
except Exception as e:
print(f"Error extracting title: {e}")
# 포스트 내용 추출 (CLASS NAME 사용)
try:
content = driver.find_element(By.CLASS_NAME, "entry-content").text
print("Content:", content)
except Exception as e:
print(f"Error extracting content: {e}")
# 종료
driver.quit()
3. No symbol 오류
웹크롤링을 하다보면 정말 가장 짜증나는 순간이 No Symbol 오류를 직면했을 때에요.
보통 이 No Symbol 오류가 생기는 이유는 다음과 같습니다.
- WebDriver 경로를 잘못 설정했을 때
- CLASS NAME 등의 요소를 잘못 입력했을 때
- WebDriver 가동 시간이 다 지났을 때
- 웹 연결이 불안정할 때 등등
크롤링을 그래도 적지않게 해본 전공생의 입장에서 봤을 때 가장 자주 발생하는 문제는 요소를 잘못 입력했을 때입니다. 그래서 요소를 이것저것 입력해보고 되는 것을 찾아보는 게 현실적인 해결책인 것 같습니다.
# 포스트 내용 추출 (CLASS NAME 사용)
try:
## 여기서 Class name을 잘못 입력했을 때 No Symbol 오류가 발생할 수 있음
content = driver.find_element(By.CLASS_NAME, "entry-content").text
print("Content:", content)
except Exception as e:
print(f"Error extracting content: {e}")
4. 한 번에 여러 개의 글을 크롤링할 때
사실 텍스트 데이터는 많으면 많을수록 좋다고 생각합니다.
그래서 보통 웹 크롤링을 통해 데이터를 수집할 때 여러 개의 포스팅을 직접 들어가서 내용을 추출하곤 하는데요.
이럴 때 구동시간, 클릭의 변수(다른 요소가 막는 등 여러 변수 존재), 잘못된 요소 등 다양한 변수가 존재합니다.
크롤링할 때 가장 시간이 많이 걸리는 이유가 이러한 변수에 대해서 제대로 예외처리 등을 해줘야 하는 부분때문이라고 생각하구요.
지금까지 크롤링을 해본 결과 한 번에 여러 글을 크롤링하려고 할 때에는 먼저 url을 수집하고 해당 url에 get 함수로 직접 접속해서 내용을 추출하는 것이 가장 안정적인 방법이라고 느꼈습니다.
예시를 통해 무슨 말인지 더 자세히 보겠습니다.
아래와 같이 여러 개의 블로그 포스트를 크롤링하려고 하는 경우에 먼저 class name을 확인합니다.
그리고 아래 코드처럼 해당 CLASS NAME에서 URL을 추출합니다.
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
import time
## Chrome WebDriver 설정
driver = webdriver.Chrome()
## 크롤링할 URL
blog_url = 'https://dangingsu.tistory.com'
driver.get(blog_url)
time.sleep(3)
## URL이 href가 아닌 data-url 속성에 있을 때
## post_urls = [post.get_attribute('data-url') for post in driver.find_elements(By.CLASS_NAME, 'inner')]
## URL이 자식 <a> 태그에 있을 때
post_urls = [post.find_element(By.TAG_NAME, 'a').get_attribute('href') for post in driver.find_elements(By.CLASS_NAME, 'post-item')]
## URL이 텍스트로 있을 때
## post_urls = [post.text for post in driver.find_elements(By.CLASS_NAME, 'title')]
## URL이 onclick 속성에 있을 때
## post_urls = [post.get_attribute('onclick').split("'")[1] for post in driver.find_elements(By.CLASS_NAME, 'title')]
driver.quit()
항상 크롤링에는 변수가 존재하기 때문에 여러 CASE들을 고려해서 코드를 작성하였습니다.
그래서 이제 지금까지의 코드를 종합해볼까요?
5. 전체 코드
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
import time
## Chrome WebDriver 설정
driver = webdriver.Chrome()
## 크롤링할 URL
blog_url = 'https://dangingsu.tistory.com'
driver.get(blog_url)
time.sleep(3)
## URL이 href가 아닌 data-url 속성에 있을 때
## post_urls = [post.get_attribute('data-url') for post in driver.find_elements(By.CLASS_NAME, 'inner')]
## URL이 자식 <a> 태그에 있을 때
post_urls = [post.find_element(By.TAG_NAME, 'a').get_attribute('href') for post in driver.find_elements(By.CLASS_NAME, 'post-item')]
## URL이 텍스트로 있을 때
## post_urls = [post.text for post in driver.find_elements(By.CLASS_NAME, 'title')]
## URL이 onclick 속성에 있을 때
## post_urls = [post.get_attribute('onclick').split("'")[1] for post in driver.find_elements(By.CLASS_NAME, 'title')]
driver.quit()
## Chrome WebDriver 설정
driver = webdriver.Chrome()
## 포스트 내용 추출을 위한 리스트
post_data = []
## 각 포스트에 접속하여 제목과 내용 크롤링
for url in post_urls:
driver.get(url)
time.sleep(2)
## 포스트 제목 추출 (XPATH 사용)
try:
path = '//*[@id="content"]/div/div[1]/div/h1'
title = driver.find_element(By.XPATH, path).text
except Exception as e:
print(f"Error extracting title: {e}")
## 포스트 내용 추출 (CLASS NAME 사용)
try:
content = driver.find_element(By.CLASS_NAME, "entry-content").text
except Exception as e:
print(f"Error extracting content: {e}")
## 결과를 딕셔너리로 저장
post_data.append({
'title': title,
'content': content
})
## 종료
driver.quit()
오늘은 프로젝트에서 중요한 데이터 수집 부분, 웹 크롤링 부분에 대해 알아보았습니다.
다들 예외처리 잘 해서 좋은 크롤링하셨으면 좋겠습니다 !!
'프로젝트' 카테고리의 다른 글
[프로젝트] HR_면접자 정보 맞추기 프로젝트 (3) (2) | 2024.10.12 |
---|---|
[프로젝트] HR_면접자 정보 맞추기 프로젝트 (2) (1) | 2024.10.04 |
[프로젝트] HR_면접자 정보 맞추기 프로젝트 (1) (4) | 2024.10.01 |
[프로젝트] Whisper 파인튜닝 (3) | 2024.09.21 |
[프로젝트] 2024 하반기 ICT 학점연계 프로젝트 인턴십 합격 후기 (0) | 2024.08.14 |
[프로젝트] 국내 주요 게임사 텍스트 데이터 분석 프로젝트 리뷰 (2) (4) | 2024.07.12 |
[프로젝트] 자전거 교통사고 원인 분석 프로젝트 리뷰 (0) | 2024.07.09 |
[프로젝트] 국내 주요 게임사 텍스트 데이터 분석 프로젝트 리뷰 (1) (2) | 2024.07.05 |