# app.py import gradio as gr import sys import os import subprocess import json # Có thể cần nếu script scraper output JSON # Thêm đường dẫn thư mục hiện tại vào sys.path để Python có thể tìm thấy script scraper # Điều này hoạt động tốt khi script scraper được import trực tiếp sys.path.append(os.path.dirname(os.path.abspath(__file__))) # --- Tùy chọn 1: Thử import hàm trực tiếp từ script scraper --- # Đây là cách ƯU TIÊN nếu script scraper của bạn có hàm dễ gọi (ví dụ: parse_listing) # Thay thế 'yellowpages' bằng tên file .py thật của script scraper của bạn (KHÔNG có .py) # Thay thế 'parse_listing_function' bằng tên hàm trong script của bạn nhận keyword và location yellowpages_script_name = 'yellowpages' # Tên file script không kèm .py scraper_function_name = 'parse_listing_function' # Tên hàm trong script scraper_function = None try: # Import module (tên file) scraper_module = __import__(yellowpages_script_name) # Lấy hàm từ module scraper_function = getattr(scraper_module, scraper_function_name, None) if scraper_function is None: print(f"Cảnh báo: Không tìm thấy hàm '{scraper_function_name}' trong file '{yellowpages_script_name}.py'.") # Nếu không tìm thấy hàm, scraper_function vẫn là None else: print(f"Đã import thành công hàm '{scraper_function_name}' từ '{yellowpages_script_name}.py'.") except ModuleNotFoundError: print(f"Cảnh báo: Không tìm thấy file '{yellowpages_script_name}.py'. Sẽ thử chạy bằng subprocess.") scraper_function = None # Đảm bảo hàm là None nếu import lỗi except AttributeError: print(f"Cảnh báo: Lỗi AttributeError khi import hàm '{scraper_function_name}' từ file '{yellowpages_script_name}.py'.") scraper_function = None except Exception as e: print(f"Lỗi không xác định khi import script scraper: {e}") scraper_function = None # --- Tùy chọn 2: Hàm chạy script bằng subprocess (Nếu không import được hàm) --- def run_scraper_via_cli(script_name_with_py, *args): """ Chạy script scraper như một tiến trình con từ dòng lệnh. Args: script_name_with_py: Tên file script bao gồm đuôi .py (ví dụ: 'yellowpages.py'). *args: Các đối số dòng lệnh cần truyền cho script. Returns: Output từ script (stdout) hoặc thông báo lỗi. """ print(f"Đang thử chạy script '{script_name_with_py}' qua command line với args: {args}") try: # Lệnh để chạy script # subprocess.run sẽ tìm script trong PYTHONPATH hoặc PATH. # Do đã thêm thư mục hiện tại vào sys.path, hy vọng python có thể tìm thấy script_name_with_py command = [sys.executable, script_name_with_py] + list(args) # sys.executable đảm bảo dùng đúng python print(f"Lệnh chạy: {' '.join(command)}") result = subprocess.run( command, capture_output=True, text=True, # Bắt output dưới dạng text check=False # KHÔNG báo lỗi nếu script trả về mã lỗi khác 0, chỉ bắt output/error ) # Kiểm tra mã trả về (return code) if result.returncode != 0: # Nếu có lỗi khi chạy script (ví dụ: lỗi cú pháp trong script, lỗi runtime trong script) print(f"Script '{script_name_with_py}' trả về mã lỗi {result.returncode}") print(f"Stderr:\n{result.stderr}") print(f"Stdout:\n{result.stdout}") # Cố gắng trả về lỗi từ stderr hoặc stdout return f"Lỗi khi chạy script '{script_name_with_py}' (code {result.returncode}):\n{result.stderr or result.stdout or 'Không có thông báo lỗi cụ thể.'}" # Trả về output chuẩn của script # Script có thể in kết quả trực tiếp hoặc in JSON/CSV print(f"Script '{script_name_with_py}' chạy thành công.") print(f"Stdout:\n{result.stdout}") # Có thể cần xử lý result.stdout ở đây nếu script in ra dữ liệu cấu trúc (JSON) return result.stdout # Trả về toàn bộ stdout except FileNotFoundError: # Lỗi này xảy ra nếu 'python' hoặc 'script_name_with_py' không tìm thấy # Lỗi 'script_name_with_py' không tìm thấy đã được báo ở trên nếu dùng import # Nhưng vẫn giữ lại đây để an toàn return f"Lỗi: Không tìm thấy file script '{script_name_with_py}' để chạy. Vui lòng đảm bảo file đã được upload." except Exception as e: # Các lỗi khác không mong muốn import traceback traceback.print_exc() return f"Đã xảy ra lỗi không xác định khi chạy subprocess: {e}" # Hàm chính được gọi từ Gradio interface def scrape_data(scraper_choice, input1, input2=None): """ Hàm này nhận lựa chọn scraper và các input tương ứng, sau đó gọi phương thức cạo phù hợp. """ if scraper_choice == "Yellow Pages": if not input1 or not input2: return "Vui lòng nhập cả Từ khóa tìm kiếm và Địa điểm cho Yellow Pages." print(f"Yêu cầu cạo Yellow Pages: Từ khóa='{input1}', Địa điểm='{input2}'") # Ưu tiên dùng hàm import nếu có if scraper_function: print("Đang chạy bằng cách import hàm trực tiếp...") try: scraped_data = scraper_function(input1, input2) # Định dạng kết quả từ list of dicts sang string output_text = "Kết quả từ Yellow Pages:\n\n" if not scraped_data: return output_text + "Không tìm thấy kết quả nào." # Nếu hàm trả về list of dicts, định dạng nó if isinstance(scraped_data, list) and all(isinstance(item, dict) for item in scraped_data): for i, item in enumerate(scraped_data): output_text += f"--- {i+1} ---\n" # Điều chỉnh các key này ('business_name', 'telephone', v.v.) # để phù hợp với các key mà script scraper của bạn sử dụng output_text += f"Name: {item.get('business_name', 'N/A')}\n" output_text += f"Phone: {item.get('telephone', 'N/A')}\n" output_text += f"Address: {item.get('street', 'N/A')}, {item.get('locality', 'N/A')}, {item.get('region', 'N/A')} {item.get('zipcode', 'N/A')}\n" output_text += f"Website: {item.get('website', 'N/A')}\n" output_text += f"Rating: {item.get('rating', 'N/A')}\n" output_text += f"Rank: {item.get('rank', 'N/A')}\n" output_text += f"URL: {item.get('url', 'N/A')}\n" output_text += "------------\n" return output_text else: # Nếu hàm trả về dạng khác (ví dụ: string báo lỗi) return f"Kết quả trực tiếp từ hàm scraper:\n{scraped_data}" except Exception as e: import traceback traceback.print_exc() return f"Lỗi xảy ra khi gọi hàm scraper trực tiếp: {e}" else: # Nếu không import được hàm, dùng subprocess để chạy file .py print("Đang chạy bằng subprocess...") # Đảm bảo tên file đúng và đối số truyền vào phù hợp với script CLI # Đối với script yellowpages.py trong repo ScrapeDataCom, cú pháp CLI có thể là: # python yellowpages.py "keyword" "location" return run_scraper_via_cli(f"{yellowpages_script_name}.py", input1, input2) # --- Thêm các trường hợp cho scraper khác tại đây --- # elif scraper_choice == "Google Search": # if not input1: # return "Vui lòng nhập Từ khóa tìm kiếm cho Google Search." # print(f"Yêu cầu cạo Google Search: Từ khóa='{input1}'") # # Cần tích hợp logic gọi script Google Search tương tự Yellow Pages # # Ví dụ: return run_scraper_via_cli("googlesearch_results.py", input1) # return "Chức năng Google Search chưa được tích hợp hoàn chỉnh." # # elif scraper_choice == "Amazon": # if not input1: # return "Vui lòng nhập URL sản phẩm hoặc từ khóa cho Amazon." # print(f"Yêu cầu cạo Amazon: Input='{input1}'") # # Cần tích hợp logic gọi script Amazon # # Ví dụ: return run_scraper_via_cli("amazon_products.py", input1) # Giả định script Amazon nhận 1 đối số # return "Chức năng Amazon chưa được tích hợp hoàn chỉnh." else: return "Vui lòng chọn một Scraper từ danh sách." # Tạo giao diện Gradio with gr.Blocks() as demo: gr.Markdown("# Demo Các Web Scraper từ ScrapeDataCom") gr.Markdown("Chọn một scraper và nhập các thông tin cần thiết. Kết quả sẽ hiển thị bên dưới.") scraper_dropdown = gr.Dropdown( ["Yellow Pages"], # Thêm tên các scraper khác vào list này sau khi tích hợp label="Chọn Scraper", value="Yellow Pages" # Giá trị mặc định ) # Các input fields. Có thể cần điều chỉnh hiển thị dựa trên lựa chọn dropdown input_keyword = gr.Textbox(label="Từ khóa", placeholder="Ví dụ: restaurants") input_location = gr.Textbox(label="Địa điểm", placeholder="Ví dụ: Boston,MA") # input_generic = gr.Textbox(label="Input (URL hoặc Từ khóa)", placeholder="Nhập URL hoặc từ khóa tùy scraper", visible=False) # Input chung run_button = gr.Button("Chạy Scraper") output_text = gr.Textbox(label="Kết quả", lines=20, max_lines=50, interactive=False) # interactive=False để không cho chỉnh sửa # Định nghĩa hành động khi nút được nhấn run_button.click( scrape_data, inputs=[scraper_dropdown, input_keyword, input_location], # Truyền tất cả các input tiềm năng outputs=output_text ) # Ví dụ về cách thay đổi hiển thị input dựa trên dropdown (có thể phức tạp tùy vào số lượng scraper) # def update_inputs(choice): # if choice == "Yellow Pages": # return gr.update(visible=True, label="Từ khóa"), gr.update(visible=True, label="Địa điểm"), gr.update(visible=False) # elif choice == "Google Search": # return gr.update(visible=True, label="Từ khóa"), gr.update(visible=False), gr.update(visible=False) # Giả sử Google chỉ cần từ khóa # # Thêm các trường hợp khác # return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True, label=f"Input cho {choice}") # Default case # # scraper_dropdown.change( # update_inputs, # inputs=scraper_dropdown, # outputs=[input_keyword, input_location, input_generic] # Liệt kê tất cả input có thể thay đổi # ) # Chạy ứng dụng Gradio # Trong Hugging Face Space, dòng này sẽ tự động được gọi # Khi chạy cục bộ, nó sẽ mở giao diện trong trình duyệt iface = demo # Gán demo cho iface để tương thích với iface.launch() nếu cần, hoặc chỉ dùng demo.launch() demo.launch()