import re class ShoppingLensScraper: def __init__(self, app, logger): self.app = app self.logger = logger def extract_product_data(self, list_box): """ ListBox에서 제품 데이터를 추출합니다. Args: list_box: ListBox 객체 Returns: list: 추출된 제품 정보의 리스트 """ product_data = [] try: # ListBox 내부의 모든 ListItem 순회 list_items = list_box.descendants(control_type="ListItem") for item in list_items: # 첫 번째 Hyperlink를 찾기 hyperlink = item.child_window(control_type="Hyperlink", found_index=0) if hyperlink.exists(): title = hyperlink.window_text() product_info = self.parse_product_info(title) if product_info: product_data.append(product_info) except Exception as e: self.logger.error(f"데이터 추출 중 오류 발생: {e}", exc_info=True) return product_data # @staticmethod def parse_product_info(self, titles): """ 쇼핑 렌즈 결과에서 상품 정보를 파싱합니다. :param titles: Hyperlink title의 리스트 :return: 구조화된 상품 정보 리스트 """ products = [] for title in titles: try: # 정규식으로 상품명, 가격, 배송비, 판매처 정보 추출 match = re.search( r"(?P.+?)\s(?P최저\s[0-9,]+원|[0-9,]+원)\s(?P무료|배송비\s무료|배송비\s[0-9,]+원)(?:\s판매처\s(?P\d+))?(?:\s별점\s(?P[0-9.]+))?", title ) if match: product_info = { "name": match.group("name"), "price": match.group("price"), "shipping": match.group("shipping"), "seller_count": match.group("seller_count") or "1", "rating": match.group("rating") or None, } # 필터링된 상품명에서 중복 제거 filtered_name = self._filter_duplicate_name(product_info["name"]) product_info["filtered_name"] = filtered_name products.append(product_info) else: self.logger.warning(f"상품 정보를 파싱할 수 없습니다: {title}") except Exception as e: self.logger.error(f"상품 정보 파싱 중 오류 발생: {title} -> {e}", exc_info=True) return products @staticmethod def _filter_duplicate_name(name): """ 상품명에서 중복된 내용을 제거합니다. :param name: 원본 상품명 :return: 중복 제거된 상품명 """ words = name.split() seen = set() filtered_words = [] for word in words: if word not in seen: filtered_words.append(word) seen.add(word) return " ".join(filtered_words) def filter_titles(self, titles): """ 주어진 제목 리스트에서 '다른 사이트 더보기' 이후 '더보기' 이전의 데이터를 필터링합니다. Args: titles (list): 전체 제목 리스트 Returns: list: 필터링된 제목 리스트 """ try: # 시작과 끝 인덱스를 찾기 start_index = titles.index("다른 사이트 더보기") + 1 end_index = titles.index("더보기") # 필터링된 데이터 추출 filtered_titles = titles[start_index:end_index] return filtered_titles except ValueError as e: # '다른 사이트 더보기' 또는 '더보기'가 없을 경우 예외 처리 self.logger.error(f"필터링 중 오류 발생: {e}") return []