네이버 게시판 글 첨부파일 크롤링 한번에 다운받기 ㅣ 네이버 카페 유용한 글 및 첨부파일을 보다보면 한번에 자동으로 다운 받고 싶은 경우가 생깁니다. 물론 상업적으로 사용하지 않는다고 해서 이 모든 것이 불법적인 행동이 안된다는 것은 아니지만 몇개의 파일을 다운 받을 때 하나하나 직접 다운 받는 것은 굉장히 피곤한 일입니다. 그래서 오늘은 이 네이버 카페 게시판 글 및 첨부파일을 모두 다운 받는 프로그램을 하나 만들어 볼까 생각했습니다.
어렵지 않으니 하나씩 따라 하시면 여러분도 금방 코드를 짤 수 있을 것 같습니다. 동적 네트워크를 사용해야 하므로 오늘은 코랩이 아니라 직접 로컬 컴퓨터에서 실행하도록 하겠습니다.
제 블로그 글에도 로컬 컴퓨터 세팅하는 글을 작성했었으니 여러분도 아래 글을 읽어 보시고 준비가 되면 다음 단계로 넘어 오시는 것을 추천드립니다.
2023.06.30 - [부동산] - 부동산 통계 자료 내가 만들까? (개요)
이번 포스트에서는 웹 스크래핑을 통해 데이터를 수집하고 Google Sheets 및 Google Drive에 저장하는 Python 스크립트를 단계별로 설명하겠습니다. 이 스크립트는 Selenium을 이용하여 네이버 카페에서 정보를 수집하고, Google API를 통해 데이터를 저장하는 기능을 갖추고 있습니다.
1단계: 필요한 라이브러리 임포트
스크립트의 시작 부분에서는 필요한 라이브러리를 임포트합니다. 여기에는 웹 드라이버 제어를 위한 selenium, HTTP 요청을 위한 requests, Google API에 접근하기 위한 라이브러리 등이 포함됩니다.
import time
import os
import platform
import subprocess
import requests
import re
import urllib.parse
import traceback
from datetime import datetime
from tqdm import tqdm
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
먼저 관련 모듈을 임포트 합니다. 저는 구글 드라이브에 다운을 자동으로 받을 수 있도록 했습니다. 제 로컬 컴퓨터에 저장을 한 후 구글 드라이브에 저장이 되면 제 로컬 컴퓨터에서는 파일이 자동 삭제가 됩니다. 따라서 코드가 조금 지저분하고 길게 되어버렸습니다.
2단계: 시스템 아키텍처 확인
ARM 아키텍처인지 확인합니다. 이 부분은 ChromeDriver의 경로 설정에서 ARM을 지원하기 위한 조건문으로 사용됩니다.
is_arm = platform.machine().startswith('arm')
저는 개발 환경이 맥북입니다.
3단계: Google Sheets 및 Drive API 설정
Google API를 사용하기 위해 인증 정보를 설정합니다. g1.json 파일을 통해 Google API에 접근할 수 있는 자격증명을 가져옵니다.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive.file']
creds = Credentials.from_service_account_file('g1.json', scopes=SCOPES)
sheets_service = build('sheets', 'v4', credentials=creds)
drive_service = build('drive', 'v3', credentials=creds)
또한 구글시트에 내가 다운 받은 목록을 리스트화 할 생각입니다.
4단계: Chrome WebDriver 옵션 설정
Chrome WebDriver를 설정하는 함수입니다. ARM 아키텍처일 경우 추가적인 인자를 설정합니다.
def set_chrome_options(is_arm):
options = webdriver.ChromeOptions()
options.add_argument("--start-maximized")
options.add_argument("--disable-extensions")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36")
if is_arm:
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
return options
5단계: ChromeDriver 서비스 설정
ChromeDriver의 경로를 설정하고 서비스를 생성하는 함수입니다. ARM 아키텍처에 맞춰 ChromeDriver를 설치하는 과정을 포함하고 있습니다.
def get_chromedriver_service(is_arm):
try:
if is_arm:
home = os.path.expanduser("~")
chromedriver_path = f"{home}/chromedriver"
if not os.path.exists(chromedriver_path):
print("ChromeDriver for ARM Mac not found. Downloading...")
subprocess.run(["brew", "install", "chromedriver"])
subprocess.run(["xattr", "-d", "com.apple.quarantine", "/usr/local/bin/chromedriver"])
service = Service("/opt/homebrew/bin/chromedriver")
else:
service = Service(ChromeDriverManager().install())
return service
except Exception as e:
print(f"Error setting up ChromeDriver: {e}")
raise
6단계: WebDriver 초기화
WebDriver를 초기화하고 Chrome 브라우저를 실행하는 함수입니다.
def init_webdriver():
service = get_chromedriver_service(is_arm)
options = set_chrome_options(is_arm)
driver = webdriver.Chrome(service=service, options=options)
return driver
7단계: 첨부파일 다운로드 함수
특정 게시물에서 첨부파일을 다운로드하는 함수입니다. 두 가지 방법을 통해 파일을 찾고, 요청을 보내서 다운로드합니다.
def download_attachments(driver):
try:
files = driver.find_elements(By.CSS_SELECTOR, "li.AttachFileListItem")
if not files:
print("첫 번째 방법으로 첨부파일을 찾지 못했습니다. 두 번째 방법을 시도합니다.")
# 두 번째 방법: 새로운 방식
file_button = driver.find_element(By.CSS_SELECTOR, "#app > div > div > div.ArticleContentBox > div.article_container > div.AttachFileList > div.attach_file > a")
file_button.click()
download_link = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "a[role='button'][download].file_menu"))
)
file_url = download_link.get_attribute('href')
file_name = os.path.basename(urllib.parse.unquote(file_url.split('?')[0]))
# 다운로드 진행
cookies = driver.get_cookies()
session = requests.Session()
for cookie in cookies:
session.cookies.set(cookie['name'], cookie['value'])
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'
}
response = session.get(file_url, headers=headers, allow_redirects=True)
if response.status_code == 200:
download_dir = "/Users/사용자/Downloads"
if not os.path.exists(download_dir):
os.makedirs(download_dir)
save_path = os.path.join(download_dir, file_name)
with open(save_path, 'wb') as f:
f.write(response.content)
print(f"첨부파일 저장 완료: {save_path}")
return save_path
else:
print(f"파일 다운로드 실패: {response.status_code}")
return None
# 첫 번째 방법으로 진행
cookies = driver.get_cookies()
session = requests.Session()
for cookie in cookies:
session.cookies.set(cookie['name'], cookie['value'])
download_dir = "/Users/사용자/Downloads"
if not os.path.exists(download_dir):
os.makedirs(download_dir)
for idx, file in enumerate(files):
download_link = file.find_element(By.CSS_SELECTOR, "a.file_menu")
file_url = download_link.get_attribute('href')
print(f"다운로드 링크: {file_url}")
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'
}
response = session.get(file_url, headers=headers, allow_redirects=True)
if response.status_code == 200:
content_disposition = response.headers.get('Content-Disposition', '')
file_name = ''
if content_disposition:
file_name_match = re.search(r'filename[^;=\n]*=(([\'"]).*?\2|[^;\n]*)', content_disposition)
if file_name_match:
file_name = file_name_match.group(1).strip('"')
if not file_name:
file_name = os.path.basename(urllib.parse.unquote(file_url.split('?')[0]))
if not file_name:
file_extension = file_url.split(".")[-1].split("?")[0]
file_name = f"attachment_{idx + 1}.{file_extension}"
save_path = os.path.join(download_dir, file_name)
with open(save_path, 'wb') as f:
f.write(response.content)
print(f"첨부파일 {idx + 1}번째 저장 완료: {save_path}")
return save_path
else:
print(f"파일 다운로드 실패: {response.status_code}")
except Exception as e:
print(f"첨부파일 다운로드 중 오류 발생: {str(e)}")
traceback.print_exc()
return None
8단계: Google Drive에 파일 업로드 함수
다운로드한 파일을 Google Drive에 업로드하는 함수입니다. 업로드 후 로컬 파일을 삭제하는 기능도 포함되어 있습니다.
def upload_to_google_drive(file_path, file_name):
folder_id = '구글시트ID' # bee 폴더의 ID
file_metadata = {
'name': file_name,
'parents': [folder_id]
}
media = MediaFileUpload(file_path, resumable=True)
file = drive_service.files().create(
body=file_metadata,
media_body=media,
fields='id, webViewLink'
).execute()
print(f"File ID: {file.get('id')}")
# 업로드가 성공적으로 완료되었을 경우 로컬 파일 삭제
if file.get('id'):
try:
os.remove(file_path)
print(f"로컬 파일 삭제 완료: {file_path}")
except Exception as e:
print(f"로컬 파일 삭제 중 오류 발생: {e}")
return file
9단계: 게시물 데이터 수집 함수
웹 스크래핑을 통해 게시물의 제목과 내용을 수집하는 함수입니다. Selenium을 사용하여 특정 요소를 찾고 데이터를 추출합니다.
def scrape_post_data(driver):
post_title = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'h3.title'))
).text
post_content = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '.article_body'))
).text
return post_title, post_content
10단계: Google Sheets에 데이터 저장 함수
수집한 게시물 제목과 내용을 Google Sheets에 저장하는 함수입니다. Google Sheets API를 사용하여 데이터를 작성합니다.
def save_to_google_sheets(post_title, post_content):
spreadsheet_id = 'YOUR_SPREADSHEET_ID' # 스프레드시트 ID
range_name = 'Sheet1!A1:B1' # 데이터를 입력할 범위
values = [[post_title, post_content]] # 입력할 데이터
body = {
'values': values
}
result = sheets_service.spreadsheets().values().append(
spreadsheetId=spreadsheet_id,
range=range_name,
valueInputOption='RAW',
body=body
).execute()
print(f"{result.get('updates').get('updatedCells')} cells appended.")
11단계: 스크래핑 및 데이터 저장 메인 함수
전체 프로세스를 실행하는 메인 함수입니다. 게시물 URL을 통해 게시물 데이터를 수집하고, 첨부파일을 다운로드하며, 최종적으로 Google Sheets에 저장합니다.
def main(post_url):
driver = init_webdriver()
try:
driver.get(post_url)
time.sleep(2) # 페이지 로딩 대기
# 게시물 데이터 수집
post_title, post_content = scrape_post_data(driver)
# 첨부파일 다운로드
file_path = download_attachments(driver)
if file_path:
# 파일을 Google Drive에 업로드
upload_to_google_drive(file_path, os.path.basename(file_path))
# 수집한 데이터 Google Sheets에 저장
save_to_google_sheets(post_title, post_content)
except Exception as e:
print(f"메인 함수에서 오류 발생: {str(e)}")
traceback.print_exc()
finally:
driver.quit()
12단계: 스크립트 실행
스크립트를 실행하기 위해 필요한 게시물 URL을 제공하고, 메인 함수를 호출합니다.
if __name__ == "__main__":
post_url = "https://cafe.naver.com/your_post_url" # 게시물 URL
main(post_url)
위 스크립트는 네이버 카페에서 게시물 데이터를 수집하고, 첨부파일을 다운로드한 후, Google Sheets와 Google Drive에 저장하는 전체 프로세스를 보여줍니다. 각 단계에서 데이터 수집과 저장을 위한 다양한 라이브러리를 활용하여 효율적인 작업 흐름을 구축했습니다. Python을 활용한 웹 스크래핑과 API 연동을 통해 보다 자동화된 데이터 관리가 가능해지며, 이러한 방식은 업무의 효율성을 높이고 시간과 노력을 절약하는 데 기여할 수 있습니다
전체 코드가 궁금하신가요? 전체 코드가 궁금하신 분들은 아래 다운링크를 열면 받으실 수 있습니다!