FKScraper / app.py
DsJASPREET's picture
Rename Gradio version.py to app.py
90905d3 verified
Raw History Blame Contribute Delete
5.9 kB
"""Gradio version of the Flipkart ISBN price scraper.
Run with:
python "Gradio version.py"
"""
from __future__ import annotations
import random
import tempfile
import time
from pathlib import Path
from typing import Optional
import gradio as gr
import pandas as pd
import requests
from bs4 import BeautifulSoup
USER_AGENTS = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:141.0) "
"Gecko/20100101 Firefox/141.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 15_5) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 "
"(KHTML, like Gecko) Version/18.5 Safari/605.1.15",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 15_5; rv:141.0) "
"Gecko/20100101 Firefox/141.0",
"Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Edge/138.0.0.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 15_5) AppleWebKit/537.36 "
"(KHTML, like Gecko) Edge/138.0.0.0",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
)
REQUEST_TIMEOUT_SECONDS = 20
REQUEST_DELAY_SECONDS = 0.01 # Retains the small delay used by the Streamlit app.
def load_workbook(file_path: Optional[str]):
"""Read the ISBN column once, when the user uploads a workbook."""
if not file_path:
return "Upload an Excel file to begin.", None
try:
source = pd.read_excel(
file_path,
header=None,
dtype={0: "string"},
keep_default_na=False,
)
except Exception as exc:
return f"Could not read the workbook: {exc}", None
if source.empty:
return "The workbook does not contain any ISBN rows.", None
# The original app expects one input column. Ignore accidental extra columns
# rather than letting them overwrite the position reserved for Price.
dataframe = source.iloc[:, [0]].copy()
dataframe.columns = ["ISBN"]
return f"File loaded successfully ({len(dataframe)} rows). Click Start processing.", dataframe
def get_flipkart_price(session: requests.Session, isbn: str) -> Optional[str]:
"""Return the last price found by the selector used in the original app."""
response = session.get(
"https://www.flipkart.com/books/pr",
params={
"sid": "bks",
"q": isbn,
"otracker": "categorytree",
},
headers={"User-Agent": random.choice(USER_AGENTS)},
timeout=REQUEST_TIMEOUT_SECONDS,
)
response.raise_for_status()
prices = [
price.get_text(strip=True).lstrip("₹")
for price in BeautifulSoup(response.text, "lxml").select("div.hZ3P6w")
]
return prices[-1] if prices else None
def process_isbns(dataframe, progress=gr.Progress(track_tqdm=False)):
"""Fetch prices and produce an ISBN/Price CSV file."""
if dataframe is None or len(dataframe) == 0:
return "Please upload a non-empty Excel file first.", None, gr.DownloadButton(visible=False)
result = dataframe.copy()
result["Price"] = pd.NA
failures = 0
total_rows = len(result)
with requests.Session() as session:
for row_number, (index, isbn) in enumerate(result["ISBN"].items(), start=1):
isbn_text = str(isbn).strip()
if isbn_text:
try:
result.at[index, "Price"] = get_flipkart_price(session, isbn_text)
except requests.RequestException:
failures += 1
progress(
(row_number, total_rows),
desc=f"Processing row {row_number} of {total_rows}",
)
time.sleep(REQUEST_DELAY_SECONDS)
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".csv",
prefix="flipkart_prices_",
encoding="utf-8-sig",
newline="",
delete=False,
) as output_file:
result.to_csv(output_file, index=False)
output_path = Path(output_file.name)
message = "Processing complete!"
if failures:
message += f" {failures} request(s) could not be completed; their prices are blank."
return message, result, gr.DownloadButton(
value=str(output_path),
label="Download processed file",
visible=True,
)
with gr.Blocks(title="Flipkart Scraper") as app:
gr.Markdown(
"""
# Flipkart Scraper
### Instructions
- Upload an **Excel (.xlsx, .xls, or .xlsm)** file.
- The workbook should have ISBNs in the first column, with no header row.
- Use one ISBN per row.
- Click **Start processing**, then download the resulting CSV.
- Uploaded data is used only for the current session.
"""
)
workbook_state = gr.State(value=None)
workbook = gr.File(
label="Upload an Excel file",
file_types=[".xlsx", ".xls", ".xlsm"],
type="filepath",
)
status = gr.Markdown("Upload an Excel file to begin.")
start_button = gr.Button("Start processing", variant="primary")
preview = gr.Dataframe(label="Processed data", interactive=False)
download = gr.DownloadButton("Download processed file", visible=False)
workbook.change(
load_workbook,
inputs=workbook,
outputs=[status, workbook_state],
)
start_button.click(
process_isbns,
inputs=workbook_state,
outputs=[status, preview, download],
)
if __name__ == "__main__":
app.queue().launch()