import time import requests import pandas as pd import gradio as gr import os from urllib.parse import urlparse # ===================================================== # CONFIGURATION (HF SAFE) # ===================================================== HASDATA_API_KEY = os.getenv("HASDATA_API_KEY") # ✅ From Hugging Face Secrets HASDATA_ENDPOINT = "https://api.hasdata.com/scrape/google/serp" TARGET_DOMAIN = "rishabhsoft.com" COUNTRY = "us" # "us" or "in" LANGUAGE = "en" LOCATION = "United States" if COUNTRY == "us" else "India" MAX_PAGES = 10 # Top 100 RESULTS_PER_PAGE = 10 SLEEP_TIME = 1 if not HASDATA_API_KEY: raise ValueError("HASDATA_API_KEY is missing. Add it in Hugging Face Secrets.") # ===================================================== # HELPERS # ===================================================== def normalize_domain(url: str) -> str: try: return urlparse(url).netloc.replace("www.", "").lower() except Exception: return "" # ===================================================== # CORE RANK CHECK # ===================================================== def check_domain_rank(keyword: str) -> pd.DataFrame: keyword = keyword.strip() results = [] headers = { "x-api-key": HASDATA_API_KEY } for page in range(MAX_PAGES): start = page * RESULTS_PER_PAGE params = { "q": keyword, "gl": COUNTRY, "hl": LANGUAGE, "domain": "google.com", "location": LOCATION, "start": start, "num": RESULTS_PER_PAGE, "deviceType": "desktop" } response = requests.get( HASDATA_ENDPOINT, headers=headers, params=params, timeout=30 ) if response.status_code != 200: print(f"API Error [{response.status_code}]: {response.text}") break data = response.json() organic_results = ( data.get("organic_results") or data.get("organicResults") or [] ) for idx, item in enumerate(organic_results, start=1): url = item.get("link") or item.get("url") or "" if not url: continue domain = normalize_domain(url) if domain.endswith(TARGET_DOMAIN): results.append({ "Keyword": keyword, "Domain": f"https://www.{TARGET_DOMAIN}/", "Page": page + 1, "Position on Page": idx, "Absolute Rank": start + idx, "URL": url, "Title": item.get("title") }) if results: break time.sleep(SLEEP_TIME) if results: return pd.DataFrame(results) return pd.DataFrame([{ "Keyword": keyword, "Domain": f"https://www.{TARGET_DOMAIN}/", "Page": "Not Found", "Position on Page": "Not Found", "Absolute Rank": "Not Found", "URL": None, "Title": "Not ranking in top 100" }]) # ===================================================== # BULK EXCEL HANDLER # ===================================================== def run_bulk_excel(file): if file is None: return None, None df = pd.read_excel(file) if "keyword" not in df.columns: raise ValueError("Excel must contain a 'keyword' column") all_results = [] for kw in df["keyword"].dropna().unique(): all_results.append(check_domain_rank(str(kw))) final_df = pd.concat(all_results, ignore_index=True) output_file = "hasdata_keyword_ranking.xlsx" final_df.to_excel(output_file, index=False) return final_df, output_file # ===================================================== # GRADIO UI # ===================================================== with gr.Blocks(title="Hasdata Google Rank Checker") as demo: gr.Markdown("## 🔍 Google Keyword Rank Checker (Hasdata)") gr.Markdown(f"**Target Domain:** https://www.{TARGET_DOMAIN}/") gr.Markdown(f"**Country:** {COUNTRY.upper()} | **Device:** Desktop") excel_input = gr.File( label="Upload Excel (.xlsx) with 'keyword' column", file_types=[".xlsx"] ) run_btn = gr.Button("Check Rankings") output_table = gr.Dataframe( headers=[ "Keyword", "Domain", "Page", "Position on Page", "Absolute Rank", "URL", "Title" ], wrap=True ) download_file = gr.File(label="Download Result Excel") run_btn.click( fn=run_bulk_excel, inputs=excel_input, outputs=[output_table, download_file] ) demo.queue() demo.launch()