| import time |
| import requests |
| import pandas as pd |
| import gradio as gr |
| import os |
| from urllib.parse import urlparse |
|
|
| |
| |
| |
| HASDATA_API_KEY = os.getenv("HASDATA_API_KEY") |
| HASDATA_ENDPOINT = "https://api.hasdata.com/scrape/google/serp" |
|
|
| TARGET_DOMAIN = "rishabhsoft.com" |
| COUNTRY = "us" |
| LANGUAGE = "en" |
| LOCATION = "United States" if COUNTRY == "us" else "India" |
|
|
| MAX_PAGES = 10 |
| 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.") |
|
|
| |
| |
| |
| def normalize_domain(url: str) -> str: |
| try: |
| return urlparse(url).netloc.replace("www.", "").lower() |
| except Exception: |
| return "" |
|
|
| |
| |
| |
| 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" |
| }]) |
|
|
| |
| |
| |
| 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 |
|
|
| |
| |
| |
| 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() |
|
|