크롤링한 자료를 게시판에 자동 등록 되게 하려고 합니다.
CMS/프레임워크 | Rhymix 2.1 |
---|---|
개발 언어 | PHP 8.0 |
네이버 뉴스를 크롤링해서 게시판에 작성하는 방법을 찾고 있습니다.
파이썬을 이용해서 다음과 같은 코드를 작성 했는데 오류가 뜨네요.
아마도 추측건데 스펨 게시글 같은걸 차단하려고 라이믹스에서 자체 보안을 해 놓은것 같은데
혹시 이런 부분은 어떻게 설정해야 할까요?
import requests
from bs4 import BeautifulSoup
def crawl_naver_news(query):
print("Starting to crawl Naver News...")
url = f'https://search.naver.com/search.naver?&where=news&query={query}'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code != 200:
print(f"Failed to fetch news. Status code: {response.status_code}")
return []
soup = BeautifulSoup(response.content, 'html.parser')
articles = []
seen_titles = set()
for item in soup.find_all('div', class_='news_wrap'):
title_element = item.find('a', class_='news_tit')
if title_element:
title = title_element.get_text()
link = title_element['href']
if title not in seen_titles:
seen_titles.add(title)
articles.append({'title': title, 'link': link})
if len(articles) >= 3: # 상위 3개 의 기사만 가져오기
break
if not articles:
print("No articles found after crawling.")
else:
print(f"Number of articles found: {len(articles)}")
print("Finished crawling Naver News.")
return articles
def post_to_rhymix(title, content):
print(f"Posting article: {title}")
post_url = 'est' # 실제 게시판의 URL로 변경 필요
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36',
'Referer': post_url,
'Content-Type': 'application/x-www-form-urlencoded'
}
# CSRF 토큰을 가져오기 위한 요청 (이 부분은 실제 CSRF 토큰을 어떻게 처리할지에 따라 다를 수 있음)
csrf_response = requests.get(post_url, headers=headers)
csrf_soup = BeautifulSoup(csrf_response.content, 'html.parser')
csrf_token = csrf_soup.find('meta', {'name': 'csrf-token'})['content']
# 게시글 작성 데이터
post_data = {
'title': title,
'content': content,
'module': 'board',
'act': 'procBoardInsert',
'mid': '459', # 게시판 MID 설정
'csrf_token': csrf_token # CSRF 토큰 추가
}
response = requests.post(post_url, data=post_data, headers=headers)
if response.status_code == 200:
print(f"Successfully posted: {title}")
else:
print(f"Failed to post: {title}. Status code: {response.status_code}. Response: {response.text}")
return response.status_code
def main():
query = "배나무"
articles = crawl_naver_news(query)
if not articles:
print("No articles found.")
else:
for article in articles:
print(f"Article found: {article['title']} - {article['link']}")
content = f"{article['title']}\n\n링크: {article['link']}"
post_status = post_to_rhymix(article['title'], content)
if post_status == 200:
print(f"Successfully posted: {article['title']}")
else:
print(f"Failed to post: {article['title']} with status code: {post_status}")
if __name__ == "__main__":
main()
댓글 16
어디에서 무슨 오류가 뜨는지 써주셔야죠~
댓글로 쓰기에 로그 에러랑 너무 길어서 일단 좀 더 해결책을 찾아보고 문제가 조금더 구체적으로 질문할수 있을때 다시 질문 올리겠습니다. 감사 합니다.
파이썬과 셀레니움으로 네이버 뉴스 크롤링까지는 성공한 것 같습니다. 라이믹스 게시판에 로그인 하는 방법을 몰라서 이 부분을 어떻게 수정해야할지를 모르겠네요.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
# ChromeDriver 경로 설정
chrome_driver_path = r'C:\Users\VELOMANO\Documents\code\work\chromedriver.exe'
# ChromeDriver 설정
chrome_options = Options()
chrome_options.add_argument("--headless") # GUI 없이 실행
service = Service(chrome_driver_path)
# 브라우저 열기
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
# 1. 네이버 뉴스에서 데이터 추출
driver.get('https://search.naver.com/search.naver?where=news&query=%EB%8F%84%EC%8B%9C%EC%B2%A0%EB%8F%84')
time.sleep(3)
articles = driver.find_elements(By.CSS_SELECTOR, 'ul.list_news div.news_area')
news_data = []
for article in articles[:3]:
title = article.find_element(By.CSS_SELECTOR, 'a.news_tit').text
content = article.find_element(By.CSS_SELECTOR, 'a.api_txt_lines').text
news_data.append((title, content))
# 2. 라이믹스 사이트 로그인
driver.get('https://smrte.or.kr')
time.sleep(3)
# 로그인 버튼의 XPATH 또는 CSS_SELECTOR를 사용
login_button = driver.find_element(By.XPATH, '//a[contains(text(),"로그인")]')
login_button.click()
time.sleep(2)
username_input = driver.find_element(By.ID, 'id')
password_input = driver.find_element(By.ID, 'pw')
submit_button = driver.find_element(By.ID, 'login_submit')
username_input.send_keys('sky3rain7')
password_input.send_keys('sky1005')
submit_button.click()
time.sleep(3)
# 3. 로그인 상태 확인
try:
driver.find_element(By.ID, 'logout')
print("로그인 성공")
except:
print("로그인 실패")
driver.quit()
exit()
# 4. 게시판에 게시글 작성
driver.get('https://smrte.or.kr/board.php?bo_table=469')
time.sleep(3)
write_button = driver.find_element(By.LINK_TEXT, '글쓰기')
write_button.click()
time.sleep(2)
title_input = driver.find_element(By.NAME, 'wr_subject')
content_input = driver.find_element(By.NAME, 'wr_content')
submit_button = driver.find_element(By.ID, 'btn_submit')
# 게시글 제목과 내용 입력
title_input.send_keys('도시철도 뉴스')
content_input.send_keys('\n'.join([f"제목: {title}\n내용: {content}" for title, content in news_data]))
submit_button.click()
print("게시글 작성 완료")
finally:
# 브라우저 닫기
driver.quit()
로그는 다음과 같습니다.
PS C:\Users\VELOMANO\Documents\code\work> python main.py
DevTools listening on ws://127.0.0.1:55890/devtools/browser/1041320- 생략
Traceback (most recent call last):
File "C:\Users\VELOMANO\Documents\code\work\main.py", line 37, in <module>
login_button.click()
File "C:\Users\VELOMANO\Documents\code\work\venv\Lib\site-packages\selenium\webdriver\remote\webelement.py", line 94, in click
self._execute(Command.CLICK_ELEMENT)
File "C:\Users\VELOMANO\Documents\code\work\venv\Lib\site-packages\selenium\webdriver\remote\webelement.py", line 395, in _execute
return self._parent.execute(command, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\VELOMANO\Documents\code\work\venv\Lib\site-packages\selenium\webdriver\remote\webdriver.py", line 354, in execute
self.error_handler.check_response(response)
File "C:\Users\VELOMANO\Documents\code\work\venv\Lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 229, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
(Session info: chrome=128.0.6613.85)
Stacktrace:
GetHandleVerifier [0x00007FF750F4B632+29090]
(No symbol) [0x00007FF750EBE6E9]
(No symbol) [0x00007FF750D7AFF9]
(No symbol) [0x00007FF750DD0432]
(No symbol) [0x00007FF750DC2D61]
(No symbol) [0x00007FF750DF66EA]
(No symbol) [0x00007FF750DC26A6]
(No symbol) [0x00007FF750DF6900]
(No symbol) [0x00007FF750E165D9]
(No symbol) [0x00007FF750DF6493]
(No symbol) [0x00007FF750DC09B1]
(No symbol) [0x00007FF750DC1B11]
GetHandleVerifier [0x00007FF75126881D+3294093]
GetHandleVerifier [0x00007FF7512B4403+3604339]
GetHandleVerifier [0x00007FF7512AA2C7+3563063]
GetHandleVerifier [0x00007FF751006F16+797318]
(No symbol) [0x00007FF750EC986F]
(No symbol) [0x00007FF750EC5454]
(No symbol) [0x00007FF750EC55E0]
(No symbol) [0x00007FF750EB4A7F]
BaseThreadInitThunk [0x00007FFC54C47374+20]
RtlUserThreadStart [0x00007FFC54FBCC91+33]
PS C:\Users\VELOMANO\Documents\code\work>
게시판 아이디 비번은 테스트용이라 공개 되어도 괜찮습니다.
login_button.click()
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
에러 메세지는 위와 같고요
# 로그인 버튼의 XPATH 또는 CSS_SELECTOR를 사용
login_button = driver.find_element(By.XPATH, '//a[contains(text(),"로그인")]')
login_button.click()
이 소스에서 터지고 있네요.
'a[contains(text(),"로그인")]' 이 셀렉터로 찾은 버튼이 있는지, 활성화 되어있는지 확인해보세요
셀레니움 사용하면서 비슷한 에러를 겪은 적이 있는데요
btn = driver.find_element( ... )
btn.click()
버튼요소를 제대로 못 찾아서, 상호작용 안되는 element에서 click 실행한다고 에러를 내는거 같습니다.
이유는 모르겠는데, 가끔 버튼을 제대로 못찾는 경우가 있더라고요.
정 해결이 안되면.. click 메소드 호출 대신, 아래와 같이 스크립트 이용해서 클릭이 되는지 한번 시도해보세요.
btn = driver.find_element( ... )
driver.execute_script("arguments[0].click();", btn)
다음 코드로 웹스크래핑 뉴스를 가져와서 로그인 대신 바로 글쓰기 폼 링크로 이동한후 제목에 스크래핑한 뉴스 제목까지는 성공 했습니다. 이후 본문에 내용을 넣는 법을 못찾겠네요. 본문 클래스명을 따로 찾아서 넣어 주면 될것 같은데 이부분을 잘 모르겠습니다. 일단 코드는 다음과 같습니다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
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
# ChromeDriver 경로 설정
chrome_driver_path = r'C:\Users\VELOMANO\Documents\code\work\chromedriver.exe'
# ChromeDriver 설정
chrome_options = Options()
# chrome_options.add_argument("--headless") # UI를 확인하려면 이 줄의 주석을 제거하세요
service = Service(chrome_driver_path)
# 브라우저 열기
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
# 1. 네이버 뉴스에서 데이터 추출
driver.get('https://search.naver.com/search.naver?where=news&query=%EB%8F%84%EC%8B%9C%EC%B2%A0%EB%8F%84')
time.sleep(3) # 페이지 로딩 대기
articles = driver.find_elements(By.CSS_SELECTOR, 'ul.list_news div.news_area')
news_data = []
for article in articles[:3]:
title = article.find_element(By.CSS_SELECTOR, 'a.news_tit').text
content = article.find_element(By.CSS_SELECTOR, 'a.api_txt_lines').text
news_data.append((title, content))
# 2. 게시글 작성 페이지로 이동
driver.get('https://smrte.or.kr/test/write')
time.sleep(3) # 페이지 로딩 대기
# 3. 제목 입력
try:
title_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'title'))
)
title_input.clear() # 기존 입력값 제거
title_input.send_keys(news_data[0][0]) # 스크래핑한 뉴스 제목 입력
# 4. 본문 입력
try:
# 본문 입력 필드 찾기
content_body = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'body[contenteditable="true"]'))
)
# 본문 내용 구성
content_text = '\n'.join([f"제목: {title}\n내용: {content}" for title, content in news_data])
# JavaScript를 통해 본문 내용 입력
driver.execute_script("arguments[0].innerHTML = arguments[1];", content_body, content_text)
# 글쓴이와 비밀번호 입력
author_input = driver.find_element(By.NAME, 'wr_name')
password_input = driver.find_element(By.NAME, 'wr_password')
author_input.clear()
author_input.send_keys('임의의 이름')
password_input.clear()
password_input.send_keys('임의의 비밀번호')
# 게시글 제출
submit_button = driver.find_element(By.XPATH, '//button[text()="등록"]')
submit_button.click()
print("게시글 작성 완료")
except Exception as write_error:
print("본문 입력 또는 제출 실패:", write_error)
except Exception as e:
print("게시글 작성 페이지로 이동 또는 제목 입력 실패:", e)
finally:
# 브라우저 닫기
driver.quit()
에러 로그는 다음과 같습니다.
Created TensorFlow Lite XNNPACK delegate for CPU.
본문 입력 또는 제출 실패: Message:
Stacktrace:
GetHandleVerifier [0x00007FF74F6BB632+29090]
(No symbol) [0x00007FF74F62E6E9]
(No symbol) [0x00007FF74F4EB1CA]
(No symbol) [0x00007FF74F53EFD7]
(No symbol) [0x00007FF74F53F22C]
(No symbol) [0x00007FF74F5897F7]
(No symbol) [0x00007FF74F56672F]
(No symbol) [0x00007FF74F5865D9]
(No symbol) [0x00007FF74F566493]
(No symbol) [0x00007FF74F5309B1]
(No symbol) [0x00007FF74F531B11]
GetHandleVerifier [0x00007FF74F9D881D+3294093]
GetHandleVerifier [0x00007FF74FA24403+3604339]
GetHandleVerifier [0x00007FF74FA1A2C7+3563063]
GetHandleVerifier [0x00007FF74F776F16+797318]
(No symbol) [0x00007FF74F63986F]
(No symbol) [0x00007FF74F635454]
(No symbol) [0x00007FF74F6355E0]
(No symbol) [0x00007FF74F624A7F]
BaseThreadInitThunk [0x00007FFC54C47374+20]
RtlUserThreadStart [0x00007FFC54FBCC91+33]
거의 온것 같긴한데 아직도 어렵네요.
글쓰기 게시판 폼 링크 입니다. https://smrte.or.kr/test/write
아마도 글 입력할 엘레먼트를 못찾아서 에러가 난거같습니다.
에디터가 iframe 내부에 위치해있어서 그런거 같은데, 해당 iframe으로 컨텍스트 전환이 필요합니다.
아래 예제처럼 iframe 요소를 찾아서 switch_to 메서드 이용해서 컨텍스트 전환하고,
해당 컨텍스트 안에서 body 태그 위치에 글 내용 입력을 시도해보세요.
# iframe 으로 전환
iframe = WebDriverWait(driver, 10).until( ... )
driver.switch_to.frame(iframe)
driver.find_element(By.TAG_NAME, "body").send_keys(content)
# 기본컨텍스트로 되돌아오기
driver.switch_to.default_content()
https://xetown.com/questions/1834081
지금 작성하신 코드나 방식은 게시판 스킨이나, 레이아웃이 바뀌면 다시 Xpath나 TAG를 일일이 다시 찾아야할겁니다..
일단 웹스크래핑 한 뉴스를 게시글 등록시키는 것까지는 성공 했습니다. 다만 이렇게 하니 뉴스의 본문 내용이 텍스트 위주로 되어서 본문만 깔끔하게 이미지까지 복사해서 넣는건 좀 어려움이 있을것 같습니다. 그래서 네이버 뉴스 대신 유튜브 영상을 크롤링 해서 붙여 넣기 효과로 임베드 되도록 코드를 다시 만들었습니다. 혹시 필요하신 분이 계실지 몰라 코드 남겨 두겠습니다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
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
from selenium.webdriver.common.keys import Keys
import pyperclip
# ChromeDriver 경로 설정
chrome_driver_path = r'C:\Users\VELOMANO\Documents\code\work\chromedriver.exe'
# ChromeDriver 설정
chrome_options = Options()
# chrome_options.add_argument("--headless") # UI를 확인하려면 이 줄의 주석을 제거하세요
service = Service(chrome_driver_path)
# 브라우저 열기
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
# 1. 유튜브 뉴스 카테고리로 이동
driver.get('https://www.youtube.com/channel/UCtL6xC1dHKeM8n1dIfxIV9w') # 유튜브 뉴스 채널 링크 (예시)
time.sleep(3) # 페이지 로딩 대기
# 2. 도시철도 검색
search_box = driver.find_element(By.CSS_SELECTOR, 'input#search')
search_box.clear()
search_box.send_keys('도시철도')
search_box.send_keys(Keys.RETURN) # 검색 실행
time.sleep(3) # 검색 결과 로딩 대기
# 3. 가장 상단에 있는 영상 선택
videos = driver.find_elements(By.CSS_SELECTOR, 'ytd-video-renderer')
if not videos:
print("영상을 찾을 수 없습니다.")
driver.quit()
exit()
top_video = videos[0]
video_url = top_video.find_element(By.CSS_SELECTOR, 'a#video-title').get_attribute('href')
video_title = top_video.find_element(By.CSS_SELECTOR, 'a#video-title').get_attribute('title')
if not video_url:
print("영상 URL을 찾을 수 없습니다.")
driver.quit()
exit()
# 유튜브 링크를 클립보드에 복사
pyperclip.copy(video_url)
# 4. 게시글 작성 페이지로 이동
driver.get('https://smrte.or.kr/test/write')
time.sleep(3) # 페이지 로딩 대기
# 5. 제목 입력
try:
title_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'title'))
)
title_input.clear() # 기존 입력값 제거
title_input.send_keys(video_title) # 유튜브 영상 제목 입력
# 6. 본문 입력
try:
# iframe 찾기
iframe = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, 'iframe'))
)
driver.switch_to.frame(iframe)
# 본문 입력 필드 찾기
content_body = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, 'body'))
)
# 본문 내용으로 클립보드에 복사된 URL 붙여넣기
content_body.click()
content_body.send_keys(Keys.CONTROL, 'v') # Ctrl + V로 클립보드에서 붙여넣기
# 기본 컨텍스트로 돌아오기
driver.switch_to.default_content()
# 글쓴이와 비밀번호 입력
author_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, 'userName'))
)
password_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, 'userPw'))
)
author_input.clear()
author_input.send_keys('임의의 이름')
password_input.clear()
password_input.send_keys('임의의 비밀번호')
# 입력된 값 확인
entered_author = author_input.get_attribute('value')
entered_password = password_input.get_attribute('value')
# 입력된 값 출력
print(f"입력된 글쓴이: {entered_author}")
print(f"입력된 비밀번호: {entered_password}")
# 게시글 제출
submit_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'button.obtn.primary'))
)
submit_button.click()
print("게시글 작성 완료")
except Exception as write_error:
print("본문 입력 또는 제출 실패:", write_error)
except Exception as e:
print("게시글 작성 페이지로 이동 또는 제목 입력 실패:", e)
finally:
# 브라우저 닫기
driver.quit()