파이썬 웹 크롤링이용 텔레그램 챗봇2

임재성·2024년 1월 6일
0

이번 글에서는 텔레그램 챗봇관련 챕터를 진행했던 내용을 작성한다.

오류

  • 텔레그램 봇을 생성한 후 강의 진행대로 텔레그램 봇이 업데이트된 내용을 출력하는 간단한 코드를 실행했음.

    for I in bot.getUpdates():
    print(i.message)

  • 해당 내용이 아래와 같은 오류를 발생시켰다.

  • 검색해보니 비동기로 실행해 줘야 한다고 하여 아래와 같이 변경.

    async def getUpdate() :
        msg=await bot.getUpdates()
        for data in msg :
            print(data)
    asyncio.run(getUpdate())

결과가 나오긴 나온다.

  • 다음과 같은 오류가 같이 나오지만..

  • 해당 오류는 Python 3.8 이후 부터, 윈도우는 타 운영체제랑 다른 EventLoop를 기본 값으로 활용하기 때문에 나타나는 오류라고 한다.
    • 타 OS 기본 : SelectorEventLoop
    • 윈도우 기본 : ProactorEventLoop

  • 아래 코드를 입력해, 윈도우의 EventLoop를 SelectorEventLoop로 변경하면 된다.

    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

  • selectorEventLoop로 변경후 아래와 같은 제약사항 발생
    • Can't support more than 512 sockets
    • Can't use pipe
    • Can't use subprocesses

  • 아래 스택오버플로에서는 Trio를 사용하라고 되어있다.
    https://stackoverflow.com/questions/63860576/asyncio-event-loop-is-closed-when-using-asyncio-run

최종 완성 코드

  url = 'http://www.cgv.co.kr/theaters/?areacode=01&theaterCode=0013&date=20240103'

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
from bs4 import BeautifulSoup

import telegram
import asyncio
import secret

from apscheduler.schedulers.blocking import BlockingScheduler


asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
async def send(text, bot) :    
    await bot.sendMessage(chat_id=secret.chat_id, text=text)


def job_function() :
    bot = telegram.Bot(token=secret.token)

    # Selenium WebDriver를 초기화합니다. (ChromeDriver 사용 예제)
    driver = webdriver.Chrome()

    # 대상 웹 페이지로 이동합니다.

    driver.get(url)

    # iframe의 XPath를 찾아서 해당 iframe으로 전환합니다.
    iframe_xpath = '//iframe[@id="ifrm_movie_time_table"]'  # 실제 웹 페이지의 iframe ID에 맞게 수정
    iframe = WebDriverWait(driver, 5).until(
        EC.presence_of_element_located((By.XPATH, iframe_xpath))
    )
    driver.switch_to.frame(iframe)

    # iframe 내용이 로드될 때까지 대기합니다.
    iframe_content_xpath = '//body'  # 실제 웹 페이지의 iframe 내용에 맞게 수정
    iframe_content = WebDriverWait(driver, 1).until(
        EC.presence_of_element_located((By.XPATH, iframe_content_xpath))
    ).get_attribute("outerHTML")

    # iframe에서 벗어나 원래의 상위 레벨로 돌아갑니다.
    driver.switch_to.default_content()

    # WebDriver를 종료합니다.
    driver.quit()

    soup = BeautifulSoup(iframe_content, 'html.parser')

    is_imax_list = soup.select('span.imax')
    imax_name_lst= []
    if len(is_imax_list) > 0 :
        for i in is_imax_list :
            imax = i.find_parent('div', class_='col-times')
            imax_name_lst.append(imax.select_one('div.info-movie > a > strong').text.strip())

        asyncio.run(send(str(imax_name_lst) + " IMAX가 열렸습니다." , bot))
        sched.pause()
    else :
        asyncio.run(send("열린 IMAX가 없습니다." , bot))


sched = BlockingScheduler()
sched.add_job(job_function, 'interval', seconds=30)
sched.start()

보완점

  • 1시간짜리 강의이기 때문에 많은 내용은 없다.
  • 하나의 날짜만 검색하는게 아니라 여러 날짜를 검색하거나 사용자의 입력에 반응하여 답할 수 있는 기능도 있어야 할 듯하다.
  • 천천히 고쳐나가 보려고 한다.
profile
조금씩 앞으로

4개의 댓글

comment-user-thumbnail
2025년 1월 9일

안녕하세요.. 지금 인프런을 통해서 강의를 듣고있는데, 모르는것이 많아서 댓글 질문 남깁니다..
참고로 저는 Mac, visual code 사용하고있습니다.
현재, 진행되고있는 부분은 텔레그램봇을 통해서 몇개의 채팅 이후 반환값을 받아서 제 고유아이디를 알아내야되는데, 아래와 같이 코딩을 하여서 실행하였으나, 반환되는것이 하나도 없습니다. 문제가 무엇인지 알려주시면 너무 감사드리겠습니다.
import telegram
import asyncio
bot = telegram.Bot(token='제 토큰')
async def main():
updates = await bot.getUpdates()
for i in updates:
print(i)

asyncio.run(main())

1개의 답글