...
This commit is contained in:
parent
3fce9b2018
commit
a922dc2ba4
354
src/Scrapper1.py
354
src/Scrapper1.py
|
|
@ -9,147 +9,160 @@ from playwright.async_api import async_playwright, Page
|
|||
import time
|
||||
|
||||
class Scrapper1(QThread):
|
||||
# 데이터 수집 완료 시그널 (성공 여부, 메시지)
|
||||
data_collected = Signal(bool, str)
|
||||
progress_signal = Signal(int) # 진행률을 전달하는 시그널
|
||||
login_complete = Signal() # 로그인 완료 시 MainWindow에 알림
|
||||
|
||||
# QR 코드가 준비되면 QR 이미지 바이트를 전달 (메인윈도우에서 이미지 표시)
|
||||
login_ready = Signal(bytes)
|
||||
# 로그인 완료 시(현재 URL이 로그인 페이지와 달라지면) 신호 전달
|
||||
login_complete = Signal()
|
||||
# 스크래핑 완료 후 결과 전달
|
||||
scraping_complete = Signal(bool, str)
|
||||
# 진행률 업데이트용 시그널 (필요 시)
|
||||
progress_signal = Signal(int)
|
||||
|
||||
def __init__(self, logger, db_manager):
|
||||
super().__init__()
|
||||
self.logger = logger
|
||||
self.db_manager = db_manager
|
||||
self.search_query = ""
|
||||
self.login_detected = False
|
||||
self.search_query = "" # 메인윈도우에서 할당(중국어 검색어)
|
||||
self.browser = None
|
||||
self.context = None
|
||||
self.page = None
|
||||
self.playwright = None
|
||||
self.loop = None
|
||||
self._initialized = False
|
||||
|
||||
async def collect_data(self):
|
||||
try:
|
||||
async with async_playwright() as p:
|
||||
# 브라우저 경로 설정
|
||||
browser_path = None
|
||||
if getattr(sys, 'frozen', False):
|
||||
browser_path = os.path.join(os.path.dirname(sys.executable), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
else:
|
||||
browser_path = os.path.join(os.path.dirname(__file__), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
# async def collect_data(self):
|
||||
# try:
|
||||
# async with async_playwright() as p:
|
||||
# # 브라우저 경로 설정
|
||||
# browser_path = None
|
||||
# if getattr(sys, 'frozen', False):
|
||||
# browser_path = os.path.join(os.path.dirname(sys.executable), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
# else:
|
||||
# browser_path = os.path.join(os.path.dirname(__file__), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
|
||||
self.logger.log(f"브라우저 경로: {browser_path}", level=logging.DEBUG)
|
||||
# self.logger.log(f"브라우저 경로: {browser_path}", level=logging.DEBUG)
|
||||
|
||||
# 사용자 에이전트 설정
|
||||
user_agent = random.choice([
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.0.0",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/85.0.0.0",
|
||||
])
|
||||
self.logger.log(f"user_agent: {user_agent}", level=logging.DEBUG)
|
||||
# # 사용자 에이전트 설정
|
||||
# user_agent = random.choice([
|
||||
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.0.0",
|
||||
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
|
||||
# "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
|
||||
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/85.0.0.0",
|
||||
# ])
|
||||
# self.logger.log(f"user_agent: {user_agent}", level=logging.DEBUG)
|
||||
|
||||
# 브라우저 시작 (headless 모드)
|
||||
browser = await p.chromium.launch(
|
||||
headless=True, # headless 모드로 설정
|
||||
executable_path=browser_path,
|
||||
args=[
|
||||
'--disable-popup-blocking',
|
||||
'--start-maximized',
|
||||
'--window-size=1920,1080'
|
||||
]
|
||||
)
|
||||
# # 브라우저 시작 (headless 모드)
|
||||
# browser = await p.chromium.launch(
|
||||
# headless=True, # headless 모드로 설정
|
||||
# executable_path=browser_path,
|
||||
# args=[
|
||||
# '--disable-popup-blocking',
|
||||
# '--start-maximized',
|
||||
# '--window-size=1920,1080'
|
||||
# ]
|
||||
# )
|
||||
|
||||
# 시크릿 브라우저 컨텍스트 생성
|
||||
context = await browser.new_context(
|
||||
user_agent=user_agent,
|
||||
geolocation={"latitude": 37.5665, "longitude": 126.9780},
|
||||
locale="ko-KR",
|
||||
permissions=["geolocation", "notifications"]
|
||||
)
|
||||
# # 시크릿 브라우저 컨텍스트 생성
|
||||
# context = await browser.new_context(
|
||||
# user_agent=user_agent,
|
||||
# geolocation={"latitude": 37.5665, "longitude": 126.9780},
|
||||
# locale="ko-KR",
|
||||
# permissions=["geolocation", "notifications"]
|
||||
# )
|
||||
|
||||
# 페이지 열기
|
||||
page = await context.new_page()
|
||||
# await page.goto("https://world.taobao.com")
|
||||
await page.goto("https://s.taobao.com/search?commend=all&ie=utf8page=1&q=%E5%A5%B3%E5%A3%AB%E8%A5%BF%E6%9C%8D&search_type=item")
|
||||
# # 페이지 열기
|
||||
# page = await context.new_page()
|
||||
# # await page.goto("https://world.taobao.com")
|
||||
# await page.goto("https://s.taobao.com/search?commend=all&ie=utf8page=1&q=%E5%A5%B3%E5%A3%AB%E8%A5%BF%E6%9C%8D&search_type=item")
|
||||
|
||||
self.logger.log(f"접속 완료.", level=logging.INFO)
|
||||
# self.logger.log(f"접속 완료.", level=logging.INFO)
|
||||
|
||||
# 페이지 로딩 확인 및 pagedown
|
||||
# await page.wait_for_selector(".tb-pick-content-item") # 상품 카드 로딩 대기
|
||||
await page.wait_for_selector("doubleCard--gO3Bz6bu") # 상품 카드 로딩 대기
|
||||
# # 페이지 로딩 확인 및 pagedown
|
||||
# # await page.wait_for_selector(".tb-pick-content-item") # 상품 카드 로딩 대기
|
||||
# await page.wait_for_selector("doubleCard--gO3Bz6bu") # 상품 카드 로딩 대기
|
||||
|
||||
self.logger.log(f"페이지 로딩 완료", level=logging.INFO)
|
||||
await page.keyboard.press("PageDown")
|
||||
await page.wait_for_timeout(1000) # 1초 대기
|
||||
await page.keyboard.press("PageDown")
|
||||
await page.wait_for_timeout(2000) # 추가 2초 대기 (상품 로딩)
|
||||
# self.logger.log(f"페이지 로딩 완료", level=logging.INFO)
|
||||
# await page.keyboard.press("PageDown")
|
||||
# await page.wait_for_timeout(1000) # 1초 대기
|
||||
# await page.keyboard.press("PageDown")
|
||||
# await page.wait_for_timeout(2000) # 추가 2초 대기 (상품 로딩)
|
||||
|
||||
# 상품 수집
|
||||
items_data = await self.scrape_items(page)
|
||||
if items_data:
|
||||
# # 상품 수집
|
||||
# items_data = await self.scrape_items(page)
|
||||
# if items_data:
|
||||
|
||||
# 중복 필터링 후 새 상품만 추가
|
||||
self.db_manager.insert_items(items_data)
|
||||
# # 중복 필터링 후 새 상품만 추가
|
||||
# self.db_manager.insert_items(items_data)
|
||||
|
||||
self.data_collected.emit(True, "데이터 수집 완료")
|
||||
else:
|
||||
self.data_collected.emit(False, "데이터 수집 실패")
|
||||
# self.data_collected.emit(True, "데이터 수집 완료")
|
||||
# else:
|
||||
# self.data_collected.emit(False, "데이터 수집 실패")
|
||||
|
||||
await context.close()
|
||||
await browser.close()
|
||||
# await context.close()
|
||||
# await browser.close()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.log(f"브라우저 작업 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
self.data_collected.emit(False, f"오류 발생: {e}", exec=True)
|
||||
# except Exception as e:
|
||||
# self.logger.log(f"브라우저 작업 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
|
||||
# self.data_collected.emit(False, f"오류 발생: {e}", exec=True)
|
||||
|
||||
async def perform_qr_login(self):
|
||||
try:
|
||||
async with async_playwright() as p:
|
||||
# 1. 로그인 페이지 접속
|
||||
if getattr(os, 'frozen', False):
|
||||
browser_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
else:
|
||||
browser_path = os.path.join(os.path.dirname(__file__), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
# async def perform_qr_login(self):
|
||||
# try:
|
||||
# async with async_playwright() as p:
|
||||
# # 1. 로그인 페이지 접속
|
||||
# if getattr(os, 'frozen', False):
|
||||
# browser_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
# else:
|
||||
# browser_path = os.path.join(os.path.dirname(__file__), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
|
||||
user_agent = random.choice([
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
|
||||
# ... (기타 user agent)
|
||||
])
|
||||
# user_agent = random.choice([
|
||||
# "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
|
||||
# # ... (기타 user agent)
|
||||
# ])
|
||||
|
||||
browser = await p.chromium.launch(
|
||||
headless=False, # QR 로그인은 창이 보여야 함
|
||||
executable_path=browser_path,
|
||||
args=[
|
||||
'--disable-popup-blocking',
|
||||
'--start-maximized',
|
||||
'--window-size=1920,1080'
|
||||
]
|
||||
)
|
||||
# browser = await p.chromium.launch(
|
||||
# headless=False, # QR 로그인은 창이 보여야 함
|
||||
# executable_path=browser_path,
|
||||
# args=[
|
||||
# '--disable-popup-blocking',
|
||||
# '--start-maximized',
|
||||
# '--window-size=1920,1080'
|
||||
# ]
|
||||
# )
|
||||
|
||||
context = await browser.new_context(
|
||||
user_agent=user_agent,
|
||||
geolocation={"latitude": 37.5665, "longitude": 126.9780},
|
||||
locale="ko-KR",
|
||||
permissions=["geolocation", "notifications"]
|
||||
)
|
||||
# context = await browser.new_context(
|
||||
# user_agent=user_agent,
|
||||
# geolocation={"latitude": 37.5665, "longitude": 126.9780},
|
||||
# locale="ko-KR",
|
||||
# permissions=["geolocation", "notifications"]
|
||||
# )
|
||||
|
||||
page = await context.new_page()
|
||||
login_url = "https://login.taobao.com/member/login.jhtml"
|
||||
await page.goto(login_url)
|
||||
# page = await context.new_page()
|
||||
# login_url = "https://login.taobao.com/member/login.jhtml"
|
||||
# await page.goto(login_url)
|
||||
|
||||
# 2. QR 페이지 스크린샷 캡쳐 후 저장
|
||||
await page.wait_for_selector("div#qrcode-img canvas", timeout=10000)
|
||||
await asyncio.sleep(2)
|
||||
qr_canvas = await page.query_selector("div#qrcode-img canvas")
|
||||
if not qr_canvas:
|
||||
self.logger.log("QR 코드 캔버스 찾지 못함", level=30)
|
||||
await browser.close()
|
||||
return None, None, None
|
||||
img_bytes = await qr_canvas.screenshot()
|
||||
qr_path = os.path.join(os.getcwd(), "temp_qr.png")
|
||||
with open(qr_path, "wb") as f:
|
||||
f.write(img_bytes)
|
||||
self.logger.log("QR 코드 캡쳐 및 저장 완료", level=20)
|
||||
# # 2. QR 페이지 스크린샷 캡쳐 후 저장
|
||||
# await page.wait_for_selector("div#qrcode-img canvas", timeout=10000)
|
||||
# await asyncio.sleep(2)
|
||||
# qr_canvas = await page.query_selector("div#qrcode-img canvas")
|
||||
# if not qr_canvas:
|
||||
# self.logger.log("QR 코드 캔버스 찾지 못함", level=30)
|
||||
# await browser.close()
|
||||
# return None, None, None
|
||||
# img_bytes = await qr_canvas.screenshot()
|
||||
# qr_path = os.path.join(os.getcwd(), "temp_qr.png")
|
||||
# with open(qr_path, "wb") as f:
|
||||
# f.write(img_bytes)
|
||||
# self.logger.log("QR 코드 캡쳐 및 저장 완료", level=20)
|
||||
|
||||
return browser, page, login_url, qr_path
|
||||
# return browser, page, login_url, qr_path
|
||||
|
||||
except Exception as e:
|
||||
self.logger.log(f"QR 로그인 수행 중 오류: {e}", level=40)
|
||||
return None, None, None, None
|
||||
# except Exception as e:
|
||||
# self.logger.log(f"QR 로그인 수행 중 오류: {e}", level=40)
|
||||
# return None, None, None, None
|
||||
|
||||
async def monitor_login(self, page, login_url, timeout=90):
|
||||
"""
|
||||
|
|
@ -234,4 +247,117 @@ class Scrapper1(QThread):
|
|||
await asyncio.sleep(2)
|
||||
|
||||
def run(self):
|
||||
asyncio.run(self.collect_data())
|
||||
"""
|
||||
QThread의 run()에서 별도의 asyncio 이벤트 루프를 생성하여
|
||||
브라우저(및 playwright 객체)를 초기화한 후 대기상태로 둡니다.
|
||||
"""
|
||||
self.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(self.loop)
|
||||
self.loop.run_until_complete(self.start_browser())
|
||||
# 이벤트 루프를 계속 돌려서 앞으로 호출되는 코루틴들을 처리합니다.
|
||||
self.loop.run_forever()
|
||||
self.loop.close()
|
||||
|
||||
|
||||
async def start_browser(self):
|
||||
"""
|
||||
async_playwright를 이용해 브라우저를 실행하고,
|
||||
초기 페이지(빈 페이지)를 준비합니다.
|
||||
"""
|
||||
try:
|
||||
self.playwright = await async_playwright().start()
|
||||
if getattr(sys, 'frozen', False):
|
||||
browser_path = os.path.join(os.path.dirname(sys.executable), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
else:
|
||||
browser_path = os.path.join(os.path.dirname(__file__), 'browsers', 'chromium-1112', 'chrome-win', 'chrome.exe')
|
||||
# 로그인 시에는 headless=False (로그인 창이 보여야 함)
|
||||
self.browser = await self.playwright.chromium.launch(
|
||||
headless=False,
|
||||
executable_path=browser_path,
|
||||
args=[
|
||||
'--disable-popup-blocking',
|
||||
'--start-maximized',
|
||||
'--window-size=1920,1080'
|
||||
]
|
||||
)
|
||||
self.context = await self.browser.new_context()
|
||||
self.page = await self.context.new_page()
|
||||
self._initialized = True
|
||||
self.logger.log("브라우저 초기화 완료", level=20)
|
||||
except Exception as e:
|
||||
self.logger.log(f"브라우저 초기화 오류: {e}", level=40)
|
||||
|
||||
def start_login(self):
|
||||
"""
|
||||
메인윈도우에서 로그인 버튼 클릭 시 호출.
|
||||
QThread의 이벤트 루프에서 _start_login() 코루틴을 실행합니다.
|
||||
"""
|
||||
if not self._initialized:
|
||||
self.logger.log("브라우저가 초기화되지 않음", level=40)
|
||||
return
|
||||
asyncio.run_coroutine_threadsafe(self._start_login(), self.loop)
|
||||
|
||||
async def _start_login(self):
|
||||
"""
|
||||
로그인 페이지로 이동하여 QR 코드를 캡쳐하고, 메인윈도우에 전달한 후
|
||||
1초마다 현재 URL을 감시하여 로그인 완료 여부를 판단합니다.
|
||||
"""
|
||||
login_url = "https://login.taobao.com/member/login.jhtml"
|
||||
await self.page.goto(login_url)
|
||||
self.logger.log("로그인 페이지 접속", level=20)
|
||||
try:
|
||||
await self.page.wait_for_selector("div#qrcode-img canvas", timeout=10000)
|
||||
except Exception as e:
|
||||
self.logger.log(f"QR 코드 로드 오류: {e}", level=40)
|
||||
return
|
||||
await asyncio.sleep(2) # QR 코드 렌더링 대기
|
||||
qr_canvas = await self.page.query_selector("div#qrcode-img canvas")
|
||||
if not qr_canvas:
|
||||
self.logger.log("QR 코드 캔버스 없음", level=40)
|
||||
return
|
||||
qr_bytes = await qr_canvas.screenshot()
|
||||
# 메인윈도우에 QR 이미지(바이트)를 전달
|
||||
self.login_ready.emit(qr_bytes)
|
||||
# 로그인 감시 시작 (90초 제한)
|
||||
asyncio.create_task(self._monitor_login(login_url, timeout=90))
|
||||
|
||||
async def _monitor_login(self, login_url, timeout=90):
|
||||
"""
|
||||
1초마다 현재 URL을 확인하여, 로그인 페이지 URL과 달라지면
|
||||
로그인 완료로 판단하고 login_complete 시그널을 emit합니다.
|
||||
"""
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
current_url = self.page.url
|
||||
if current_url != login_url:
|
||||
self.logger.log(f"로그인 완료 감지: {current_url}", level=20)
|
||||
self.login_complete.emit()
|
||||
return
|
||||
await asyncio.sleep(1)
|
||||
self.logger.log("로그인 시간 초과", level=30)
|
||||
# 시간 초과 시 별도 처리 가능 (예: 실패 시그널 emit 등)
|
||||
|
||||
def start_scraping(self, search_query):
|
||||
"""
|
||||
메인윈도우에서 “시작” 버튼 클릭 시 호출.
|
||||
동일한 playwright 객체를 재활용하여 검색 페이지에 접속하고 데이터를 수집합니다.
|
||||
"""
|
||||
self.search_query = search_query
|
||||
if not self._initialized:
|
||||
self.logger.log("브라우저 초기화 안됨", level=40)
|
||||
return
|
||||
asyncio.run_coroutine_threadsafe(self._start_scraping(), self.loop)
|
||||
|
||||
async def _start_scraping(self):
|
||||
"""
|
||||
검색어를 기반으로 검색 페이지에 접속하여 데이터를 수집합니다.
|
||||
실제 스크래핑 로직은 필요에 따라 구현하세요.
|
||||
"""
|
||||
import urllib.parse
|
||||
encoded_query = urllib.parse.quote(self.search_query)
|
||||
url = f"https://s.taobao.com/search?commend=all&ie=utf8&page=1&q={encoded_query}&search_type=item"
|
||||
await self.page.goto(url)
|
||||
self.logger.log("검색 페이지 접속 완료", level=20)
|
||||
# 예시: 간단한 대기 후 데이터 수집 완료 신호 emit (실제 스크래핑 로직 추가 필요)
|
||||
await asyncio.sleep(2)
|
||||
self.scraping_complete.emit(True, "데이터 수집 완료")
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import sys, os, configparser, logging
|
|||
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QPushButton, QLabel, QMessageBox,
|
||||
QTextBrowser, QDialog, QProgressBar, QTextEdit, QHBoxLayout, QMenuBar, QMenu, QComboBox)
|
||||
from PySide6.QtGui import QAction, QPixmap
|
||||
from PySide6.QtCore import Qt, Slot, Signal, QThread
|
||||
from PySide6.QtCore import Qt, Slot, Signal, QThread, QTimer
|
||||
from src.Scrapper1 import Scrapper1
|
||||
from src.excel_export import ExcelExporter
|
||||
from src.post_processor import PostProcessor
|
||||
|
|
@ -117,7 +117,6 @@ class MainWindow(QWidget):
|
|||
# QR 이미지 표시를 위한 QLabel (초기에는 숨김)
|
||||
self.qr_label = QLabel()
|
||||
self.qr_label.setVisible(False)
|
||||
self.layout.addWidget(self.qr_label)
|
||||
|
||||
# base_dir 경로 가져오기
|
||||
base_dir = self.get_base_dir()
|
||||
|
|
@ -132,10 +131,13 @@ class MainWindow(QWidget):
|
|||
# PlaywrightThread에 전달할 검색어를 초기화하기 위해 빈 값 설정
|
||||
self.search_query = ""
|
||||
|
||||
# Scrapper1 QThread 인스턴스 생성 및 시작 (브라우저 초기화)
|
||||
self.scrapper1 = Scrapper1(self.logger, self.db_manager)
|
||||
self.scrapper1.data_collected.connect(self.on_data_collected)
|
||||
self.scrapper1.progress_signal.connect(self.update_progress_bar)
|
||||
self.scrapper1.login_ready.connect(self.on_qr_ready)
|
||||
self.scrapper1.login_complete.connect(self.on_login_complete)
|
||||
self.scrapper1.scraping_complete.connect(self.on_scraping_complete)
|
||||
self.scrapper1.progress_signal.connect(self.update_progress_bar)
|
||||
self.scrapper1.start() # run()에서 start_browser() 실행
|
||||
|
||||
self.categoryManager = CategoryManager(self.logger, self.xls_file_path)
|
||||
|
||||
|
|
@ -145,52 +147,74 @@ class MainWindow(QWidget):
|
|||
self.postProcessor = PostProcessor(self.logger, self.db_manager, self.config, self.categoryManager)
|
||||
self.keyword_manager = KeywordManager(logger=self.logger, config=self.config, parent=self)
|
||||
|
||||
|
||||
@Slot()
|
||||
def on_login_button_clicked(self):
|
||||
# qasync를 사용하여 비동기 로그인 수행
|
||||
qasync.ensure_future(self.perform_login())
|
||||
self.logger.log("로그인 버튼 클릭 - QR 로그인 요청", level=logging.INFO)
|
||||
# Scrapper1에 내장된 브라우저를 이용해 로그인 플로우 시작
|
||||
self.scrapper1.start_login()
|
||||
|
||||
async def perform_login(self):
|
||||
from playwright.async_api import async_playwright
|
||||
self.logger.log("QR 로그인 시작", level=20)
|
||||
async with async_playwright() as p:
|
||||
browser, page, login_url, qr_path = await self.scrapper1.perform_qr_login()
|
||||
if not qr_path:
|
||||
QMessageBox.warning(self, "오류", "QR 코드 캡쳐 실패")
|
||||
return
|
||||
# QR 이미지 파일 경로를 받아서 표시
|
||||
pixmap = QPixmap(qr_path)
|
||||
self.qr_label.setPixmap(pixmap)
|
||||
self.qr_label.setVisible(True)
|
||||
|
||||
# 90초 동안 QR 표시, 이후 자동으로 닫힘
|
||||
self.logger.log("QR 코드 표시 (최대 90초)", level=20)
|
||||
# 동시에 로그인 모니터링 시작
|
||||
login_task = asyncio.create_task(self.scrapper1.monitor_login(page, login_url, timeout=90))
|
||||
# 90초 후 자동 QR 창 닫기
|
||||
await asyncio.sleep(90)
|
||||
self.qr_label.setVisible(False)
|
||||
if await login_task:
|
||||
self.logger.log("로그인 완료 감지됨", level=20)
|
||||
self.start_button.setEnabled(True)
|
||||
self.login_button.setEnabled(False)
|
||||
else:
|
||||
self.logger.log("로그인 시간 초과", level=30)
|
||||
QMessageBox.warning(self, "로그인 실패", "로그인 시간 초과")
|
||||
await browser.close()
|
||||
|
||||
@Slot()
|
||||
def start_scraping(self):
|
||||
# 사용자가 로그인 완료 후 시작 버튼을 누르면,
|
||||
# 기존 로그인 세션이 유지된 상태에서 검색 페이지로 이동하여 데이터 수집 시작
|
||||
self.logger.log("시작 버튼 클릭 - 데이터 수집 시작", level=20)
|
||||
# 예를 들어, Scrapper1.collect_data() 실행
|
||||
self.scrapper1.start()
|
||||
@Slot(bytes)
|
||||
def on_qr_ready(self, qr_bytes):
|
||||
# Scrapper1에서 QR 이미지(바이트)를 전달받으면 화면에 표시
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(qr_bytes)
|
||||
self.qr_label.setPixmap(pixmap)
|
||||
self.qr_label.setVisible(True)
|
||||
# (추가: 타이머를 이용해 90초 후 자동 숨김 처리 가능)
|
||||
QTimer.singleShot(90000, self.qr_label.hide)
|
||||
|
||||
@Slot()
|
||||
def on_login_complete(self):
|
||||
# Scrapper1에서 로그인 완료 시 발생시키는 시그널 처리 (필요 시)
|
||||
self.logger.log("MainWindow: 로그인 완료 알림 받음", level=20)
|
||||
self.logger.log("로그인 완료 신호 수신", level=logging.INFO)
|
||||
self.start_button.setEnabled(True)
|
||||
self.qr_label.setVisible(False)
|
||||
@Slot()
|
||||
def on_start_button_clicked(self):
|
||||
if not self.selected_search_query:
|
||||
QMessageBox.warning(self, "오류", "상품분류를 올바르게 선택하세요.")
|
||||
return
|
||||
self.logger.log(f"시작 버튼 클릭 - 검색어 '{self.selected_search_query}'", level=logging.INFO)
|
||||
# Scrapper1의 기존 브라우저(로그인 세션 유지)를 재활용하여 스크래핑 시작
|
||||
self.scrapper1.start_scraping(self.selected_search_query)
|
||||
|
||||
@Slot(bool, str)
|
||||
def on_scraping_complete(self, success, message):
|
||||
if success:
|
||||
QMessageBox.information(self, "수집 완료", message)
|
||||
else:
|
||||
QMessageBox.warning(self, "수집 실패", message)
|
||||
|
||||
|
||||
# async def perform_login(self):
|
||||
# from playwright.async_api import async_playwright
|
||||
# self.logger.log("QR 로그인 시작", level=20)
|
||||
# async with async_playwright() as p:
|
||||
# browser, page, login_url, qr_path = await self.scrapper1.perform_qr_login()
|
||||
# if not qr_path:
|
||||
# QMessageBox.warning(self, "오류", "QR 코드 캡쳐 실패")
|
||||
# return
|
||||
# # QR 이미지 파일 경로를 받아서 표시
|
||||
# pixmap = QPixmap(qr_path)
|
||||
# self.qr_label.setPixmap(pixmap)
|
||||
# self.qr_label.setVisible(True)
|
||||
|
||||
# # 90초 동안 QR 표시, 이후 자동으로 닫힘
|
||||
# self.logger.log("QR 코드 표시 (최대 90초)", level=20)
|
||||
# # 동시에 로그인 모니터링 시작
|
||||
# login_task = asyncio.create_task(self.scrapper1.monitor_login(page, login_url, timeout=90))
|
||||
# # 90초 후 자동 QR 창 닫기
|
||||
# await asyncio.sleep(90)
|
||||
# self.qr_label.setVisible(False)
|
||||
# if await login_task:
|
||||
# self.logger.log("로그인 완료 감지됨", level=20)
|
||||
# self.start_button.setEnabled(True)
|
||||
# self.login_button.setEnabled(False)
|
||||
# else:
|
||||
# self.logger.log("로그인 시간 초과", level=30)
|
||||
# QMessageBox.warning(self, "로그인 실패", "로그인 시간 초과")
|
||||
# await browser.close()
|
||||
|
||||
|
||||
def load_config(self, file_path: str) -> configparser.ConfigParser:
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in New Issue