File size: 11,940 Bytes
c2e82db
 
e6219bc
be40855
 
3d5bbcf
 
be40855
 
3d5bbcf
be40855
 
3d5bbcf
 
 
 
 
 
 
 
c2e82db
3d5bbcf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97cb158
3d5bbcf
 
 
 
 
 
97cb158
3d5bbcf
97cb158
3d5bbcf
 
97cb158
 
3d5bbcf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97cb158
3d5bbcf
 
 
 
 
 
 
 
 
 
 
 
 
97cb158
c2e82db
3d5bbcf
c2e82db
97cb158
3d5bbcf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c2e82db
3d5bbcf
 
 
 
 
 
 
 
 
97cb158
3d5bbcf
 
 
 
 
 
 
97cb158
3d5bbcf
 
 
 
 
 
c2e82db
97cb158
3d5bbcf
e6219bc
 
97cb158
3d5bbcf
 
97cb158
 
3d5bbcf
 
 
97cb158
 
3d5bbcf
 
 
 
97cb158
 
 
3d5bbcf
97cb158
 
 
 
3d5bbcf
97cb158
 
 
3d5bbcf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97cb158
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# 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()