Extra Form
PHP PHP 8.0
CMS Rhymix 2.1

 

네이버 뉴스를 크롤링해서 게시판에 작성하는 방법을 찾고 있습니다. 

 

파이썬을 이용해서 다음과 같은 코드를 작성 했는데 오류가 뜨네요.

 

아마도 추측건데 스펨 게시글 같은걸 차단하려고 라이믹스에서 자체 보안을 해 놓은것 같은데 

 

혹시 이런 부분은 어떻게 설정해야 할까요? 

 

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()

 

 

  • profile

    어디에서 무슨 오류가 뜨는지 써주셔야죠~

  • profile profile
    질문을 바보 같이 썼네요. 일단 작업하던 내용들이 모두 날아가서 저녁에 다시 실행해보고 리포트해보겠습니다. 기억나는건 403 오류 정도 밖에는 남는게 없네요. ㅜ ㅜ
  • profile profile

    댓글로 쓰기에 로그 에러랑 너무 길어서 일단 좀 더 해결책을 찾아보고 문제가 조금더 구체적으로 질문할수 있을때 다시 질문 올리겠습니다. 감사 합니다. 

  • profile profile

    파이썬과 셀레니움으로 네이버 뉴스 크롤링까지는 성공한 것 같습니다. 라이믹스 게시판에 로그인 하는 방법을 몰라서 이 부분을 어떻게 수정해야할지를 모르겠네요.

    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>

    게시판 아이디 비번은 테스트용이라 공개 되어도 괜찮습니다.

  • profile profile
    File "C:\Users\VELOMANO\Documents\code\work\main.py", line 37, in <module>
    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(),"로그인")]' 이 셀렉터로 찾은 버튼이 있는지, 활성화 되어있는지 확인해보세요
  • profile profile
    아무래도 text로 검색하는 것보다는 구체적인 id나 class로 찾는 것이 더 확실하겠죠
  • profile profile
    감사 합니다. 다시 한번 꼼꼼하게 훓어봐야겠네요. 아무래도 사용하는 레이아웃이 아이콘을 한번 클릭해야 로그인 창이 열리는 형태라서 링크 주소로는 못찾는것 같습니다.
  • profile profile
    메인화면 말고 도메인.com/?mid=아무게시판&act=dispMemberLoginForm 으로 들어가서 로그인해 보세요. 화면 정중앙에 로그인 폼이 나오니까 다루기가 훨씬 편합니다.
  • profile profile

    셀레니움 사용하면서 비슷한 에러를 겪은 적이 있는데요

    btn = driver.find_element( ... )
    btn.click()

    버튼요소를 제대로 못 찾아서, 상호작용 안되는 element에서 click 실행한다고 에러를 내는거 같습니다.
    이유는 모르겠는데, 가끔 버튼을 제대로 못찾는 경우가 있더라고요.
    정 해결이 안되면.. click 메소드 호출 대신, 아래와 같이 스크립트 이용해서 클릭이 되는지 한번 시도해보세요.

    btn = driver.find_element( ... )
    driver.execute_script("arguments[0].click();", btn)

  • profile

    다음 코드로 웹스크래핑 뉴스를 가져와서 로그인 대신 바로 글쓰기 폼 링크로 이동한후 제목에 스크래핑한 뉴스 제목까지는 성공 했습니다. 이후 본문에 내용을 넣는 법을 못찾겠네요. 본문 클래스명을 따로 찾아서 넣어 주면 될것 같은데 이부분을 잘 모르겠습니다. 일단 코드는 다음과 같습니다. 
     

    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

  • profile profile

    아마도 글 입력할 엘레먼트를 못찾아서 에러가 난거같습니다.
    에디터가 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()

  • profile profile
    감사 합니다. 내용을 바탕으로 코드를 변경하니 본문 글이 들어갔습니다.
  • profile
    꼭 셀레니엄으로 게시글을 작성하기 보단, DB에 먼저 정제된 데이터를 저장하고, crawling_document.php 등의 파일로 하단의 게시글 처럼 게시글을 생성하시는 건 어떨까요?

    https://xetown.com/questions/1834081

    지금 작성하신 코드나 방식은 게시판 스킨이나, 레이아웃이 바뀌면 다시 Xpath나 TAG를 일일이 다시 찾아야할겁니다..
  • profile profile
    감사 합니다. 일단 제가 전문적인 수준의 코딩 능력이 없어서 gpt를 이용해서 문제를 해결하고 있어서 내용을 제대로 이해하기가 어려운 상태입니다. 이번 문제가 완벽히 해결 되면 알려 주신 방법도 시도해보겠습니다.
  • profile profile
    파이썬 스크립트를 로컬에서 잘 작동하게 만들고 서버에 업로드해서 크론으로 연결하려고 시도중인데 오라클 인스턴트 서버 무료 티어의 사양이 낮은지 실행하면 5분 이상 걸리고 이마저 오류가 뜨네요. 그래서 알려 주신대로 db를 이용해서 크롤링한 자료를 먼저 db에 입력시키고 이 자료를 게시글로 작성시키려고 합니다. 링크에 있는 함수들을 이용하면 라이믹스 게시판에 게시글 작성시 셀레니움 대신 파이썬 스크립트에서 작동이 될까요?
  • profile

    일단 웹스크래핑 한 뉴스를 게시글 등록시키는 것까지는 성공 했습니다. 다만 이렇게 하니 뉴스의 본문 내용이 텍스트 위주로 되어서 본문만 깔끔하게 이미지까지 복사해서 넣는건 좀 어려움이 있을것 같습니다. 그래서 네이버 뉴스 대신 유튜브 영상을 크롤링 해서 붙여 넣기 효과로 임베드 되도록 코드를 다시 만들었습니다. 혹시 필요하신 분이 계실지 몰라 코드 남겨 두겠습니다. 

     

    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()