import gradio as gr import requests from bs4 import BeautifulSoup # For pretty-printing HTML # --- Function to extract HTML --- def get_html_content(url: str): if not url: return "Please enter a URL.", "Status: No URL provided." original_url_for_error = url # Keep original input for error messages # Add https:// if no scheme is present, as requests requires it. if not (url.startswith("http://") or url.startswith("https://")): # Try https first as it's more common and secure url_https = "https://" + url url_http = "http://" + url # Briefly check if HTTPS is responsive before defaulting to it for the main request try: print(f"No scheme provided for '{original_url_for_error}', trying to determine scheme (HTTPS first)...") # Using a HEAD request to be lighter, with a short timeout response_head = requests.head(url_https, timeout=5, allow_redirects=True, headers={'User-Agent': 'HuggingFaceSpaceHTMLSchemeChecker/1.0'}) if response_head.status_code < 400: url = url_https print(f"HTTPS seems responsive for '{original_url_for_error}'. Proceeding with {url}") else: # If HTTPS gives an error or non-success, try HTTP print(f"HTTPS check for '{original_url_for_error}' returned {response_head.status_code}. Trying HTTP.") response_head_http = requests.head(url_http, timeout=5, allow_redirects=True, headers={'User-Agent': 'HuggingFaceSpaceHTMLSchemeChecker/1.0'}) if response_head_http.status_code < 400: url = url_http print(f"HTTP seems responsive for '{original_url_for_error}'. Proceeding with {url}") else: # If both fail, default to HTTPS for the main GET request to provide a potentially more useful error from the GET print(f"HTTP check for '{original_url_for_error}' also returned {response_head_http.status_code}. Defaulting to HTTPS for the main fetch attempt.") url = url_https # Stick with HTTPS for the main request except requests.RequestException as e: print(f"Error during scheme probing for '{original_url_for_error}': {e}. Defaulting to HTTPS for the main fetch attempt: {url_https}") url = url_https status_message = f"Attempting to fetch HTML from: {url}" print(status_message) try: # It's good practice to set a User-Agent. Some sites may block default Python/requests UAs. headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 HuggingFaceSpaceHTMLScraper/1.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br' # Requests handles decompression } # Allow a reasonable timeout for the request response = requests.get(url, headers=headers, timeout=20) # 20 seconds timeout # This will raise an HTTPError if the HTTP request returned an unsuccessful status code (4xx or 5xx) response.raise_for_status() # Use BeautifulSoup to parse and prettify the HTML for better readability # response.content is used instead of response.text to let BS handle encoding detection better soup = BeautifulSoup(response.content, 'html.parser') pretty_html = soup.prettify() status_message = f"Successfully fetched and parsed HTML from {url} (Status: {response.status_code})." print(status_message) return pretty_html, status_message except requests.exceptions.HTTPError as e: error_detail = f"HTTP Error: {e.response.status_code} for URL: {url}." if e.response.text: # Include some of the response body if available and error is client/server error_detail += f" Response preview: {e.response.text[:200]}" print(error_detail) return f"Error fetching HTML: {error_detail}", error_detail except requests.exceptions.ConnectionError as e: error_detail = f"Connection Error: Could not connect to {url}. The server may be down or the domain name incorrect. (Details: {e})" print(error_detail) return f"Error fetching HTML: {error_detail}", error_detail except requests.exceptions.Timeout as e: error_detail = f"Timeout Error: The request to {url} timed out. The server might be too slow or unreachable. (Details: {e})" print(error_detail) return f"Error fetching HTML: {error_detail}", error_detail except requests.exceptions.RequestException as e: # Catch any other requests-related errors error_detail = f"Request Error: An error occurred while trying to fetch {url}. (Details: {e})" print(error_detail) return f"Error fetching HTML: {error_detail}", error_detail except Exception as e: # Catch any other unexpected errors, including potential BeautifulSoup errors during parsing error_detail = f"An unexpected error occurred during processing: {str(e)}" print(error_detail) return f"Error processing HTML: {error_detail}", error_detail # --- Gradio Interface --- iface = gr.Interface( fn=get_html_content, inputs=gr.Textbox( label="Website URL", placeholder="e.g., https://www.example.com or example.com" ), outputs=[ gr.Textbox(label="Extracted HTML Code", lines=25, show_copy_button=True, interactive=False), gr.Textbox(label="Status", interactive=False) ], title="HTML Content Extractor 🌐", description=( "Enter a website URL to extract its raw HTML content. " "The tool fetches the HTML as served by the server and uses BeautifulSoup to prettify it. " "It will **not** execute JavaScript. For websites that build their content dynamically with JavaScript, " "the extracted HTML will be the initial source before JavaScript execution. " "Please be respectful of website terms of service and robots.txt." ), examples=[ ["en.wikipedia.org/wiki/Python_(programming_language)"], ["httpbin.org/html"], ["example.com"] ], cache_examples=False, # <--- ADD THIS LINE TO DISABLE EXAMPLE CACHING flagging_options=None, css=".gradio-container {max-width: 1024px !important; margin: auto !important;}" ) # --- Main launch --- if __name__ == "__main__": print("Starting Gradio HTML Extractor application...") iface.launch(ssr_mode=False)