Google Sheets Parser
Project description
GSParse
GSParse is a lightweight library for extracting data from public Google Sheets by URL — no API keys, no OAuth, no service accounts. It downloads a spreadsheet's export, parses every worksheet, and gives you a clean, convenient API for cells, rows, columns, ranges, search, and export.
from gsparse import GSParseClient
client = GSParseClient()
spreadsheet = client.load_spreadsheet("https://docs.google.com/spreadsheets/d/<SHEET_ID>/edit")
for worksheet in spreadsheet:
print(worksheet.name, worksheet.row_count, "x", worksheet.column_count)
Table of Contents
- Features
- Installation
- Quick Start
- Usage
- API Reference
- Notes & Limitations
- Development
- Contributing
- License
Features
- 📊 Reads all worksheets of a spreadsheet in one call (XLSX)
- 🔗 Loads directly by Google Sheets URL — no credentials required
- 🧩 Convenient object model:
Spreadsheet→Worksheet→Cell/Range - 🔍 Search by exact value or regular expression
- 📋 Export worksheets to lists of dictionaries (records)
- 🧹 Helpers to strip empty rows/columns
- 🔤 Optional
preserve_stringsmode to keep every value as text - 🔄 Automatic retries and encoding auto-detection
- ⚡ Supports both XLSX (default) and CSV formats
Installation
pip install gsparse
Or with uv:
uv add gsparse
Requirements: Python ≥ 3.10 · requests · chardet · openpyxl
Quick Start
from gsparse import GSParseClient
client = GSParseClient()
url = "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
spreadsheet = client.load_spreadsheet(url)
# Inspect the workbook
print("Title:", spreadsheet.title)
print("Sheets:", spreadsheet.worksheet_names)
# Grab the first worksheet
worksheet = spreadsheet.get_first_worksheet()
# Read a single cell (1-based coordinates)
cell = worksheet.get_cell(1, 1) # A1
print(cell.address, "=", cell.value)
# Export rows as dictionaries (first row is used as headers)
for row in worksheet.get_data_as_dict():
print(row)
Usage
Loading data
# Load the whole spreadsheet (XLSX — reads every worksheet)
spreadsheet = client.load_spreadsheet(url)
# Load a single worksheet by name
worksheet = client.load_worksheet(url, "Sheet1")
# Load the first worksheet
worksheet = client.load_worksheet(url)
By default values keep their native types (numbers stay numbers). Pass
preserve_strings=True to the client if you want every cell returned as a string:
client = GSParseClient(preserve_strings=True)
Worksheets
spreadsheet.worksheet_count # number of sheets
spreadsheet.worksheet_names # ["Sheet1", "Data", ...]
spreadsheet.get_worksheet("Data") # by name (or None)
spreadsheet.get_worksheet_by_index(0)
spreadsheet.get_first_worksheet()
spreadsheet.get_last_worksheet()
# Dict-like and iterable access
sheet = spreadsheet["Data"]
if "Data" in spreadsheet:
...
for sheet in spreadsheet:
print(sheet.name)
Cells and ranges
worksheet = spreadsheet.get_first_worksheet()
# Single cell (row, column), both starting at 1
cell = worksheet.get_cell(2, 3) # C2
print(cell.address, cell.value, cell.is_empty)
# A range: get_range(start_row, end_row, start_column, end_column)
rng = worksheet.get_range(1, 10, 1, 3) # A1:C10
cells = worksheet.get_cells_in_range(rng)
# ...or build a range from an A1 address
rng = worksheet.get_range_by_address("A1:C10")
# Whole rows / columns
first_row = worksheet.get_row(1)
first_col = worksheet.get_column(1)
# Raw values as lists of lists
rows = worksheet.get_rows()
columns = worksheet.get_columns()
Exporting to dictionaries
# A single worksheet -> list of records
records = worksheet.get_data_as_dict(headers_row=1)
# Every worksheet at once -> {sheet_name: [records, ...]}
data = spreadsheet.export_to_dict(headers_row=1)
# Straight from a URL
data = client.export_to_dict(url, headers_row=1)
Searching
# Exact value across all worksheets
cells = client.find_data(url, "Moscow")
# Regular expression
numbers = client.find_by_pattern(url, r"^\d+$")
# Or on already-loaded objects
worksheet.find_cells_by_value("Moscow")
worksheet.find_cells_by_pattern(r"@\w+\.\w+") # emails
spreadsheet.find_cells_by_value(42)
Cleaning data
# Return a new, cleaned worksheet (originals untouched)
clean = worksheet.remove_empty_rows()
clean = worksheet.remove_empty_columns()
clean = worksheet.clean_data() # both
# ...or mutate in place
worksheet.clean_data_inplace()
Parsing from a CSV string
Useful for tests or data you already have in memory. The delimiter is auto-detected:
csv_data = """Name,Age,City
John,25,Moscow
Mary,30,St. Petersburg"""
worksheet = client.load_from_csv_string(csv_data, "My Data")
print(worksheet.get_data_as_dict())
API Reference
GSParseClient(timeout=30, max_retries=3, preserve_strings=False)
| Method | Description |
|---|---|
load_spreadsheet(url, format_type="xlsx") |
Load the whole spreadsheet |
load_worksheet(url, worksheet_name=None, format_type="xlsx") |
Load one worksheet (first if name is None) |
load_from_csv_string(csv_string, worksheet_name="Sheet1") |
Parse a worksheet from a CSV string |
export_to_dict(url, headers_row=1, format_type="xlsx") |
Export all worksheets to records |
find_data(url, value, format_type="xlsx") |
Find cells by exact value |
find_by_pattern(url, pattern, format_type="xlsx") |
Find cells by regular expression |
get_sheet_info(url) |
Basic info about the spreadsheet |
list_worksheets(url) |
Map of {worksheet_name: gid} |
Spreadsheet
Properties: title, worksheets, url, worksheet_count, worksheet_names
Methods: get_worksheet(name), get_worksheet_by_index(index), get_first_worksheet(), get_last_worksheet(), add_worksheet(ws), remove_worksheet(name), get_all_cells(), get_data_summary(), find_cells_by_value(value), find_cells_by_pattern(pattern), export_to_dict(headers_row=1)
Also supports iteration (for ws in spreadsheet), membership (name in spreadsheet) and indexing (spreadsheet[name]).
Worksheet
Properties: name, data, row_count, column_count
Methods: get_cell(row, column), get_range(start_row, end_row, start_column, end_column), get_range_by_address(address), get_all_cells(), get_cells_in_range(range_obj), get_row(n), get_column(n), get_rows(), get_columns(), get_data_as_dict(headers_row=1), find_cells_by_value(value), find_cells_by_pattern(pattern), remove_empty_rows(), remove_empty_columns(), clean_data() (plus *_inplace() variants)
Cell
Properties: row, column, value, formatted_value, formula, address (e.g. "B2"), is_empty
Range
Properties: start_row, end_row, start_column, end_column, worksheet_name, address, row_count, column_count, cell_count
Methods: contains_cell(row, column), get_cells(data), Range.from_address("Sheet1!A1:B2")
Notes & Limitations
- The spreadsheet must be publicly accessible ("Anyone with the link"). GSParse reads the public export endpoint and does not authenticate.
- All coordinates are 1-based —
get_cell(1, 1)isA1. - Prefer XLSX (the default): it reads every worksheet. The
csvformat is deprecated — Google's CSV export only returns a single sheet, so it emits aDeprecationWarning. - If an XLSX download fails, the client automatically falls back to CSV.
Development
# Install the project with its dev dependency group
uv sync # installs the "dev" group by default
# Run the test suite
uv run pytest # or just: pytest
# Lint
uv run ruff check src/ # or just: ruff check src/
Using plain
pip? Install the package in editable mode and add the tools manually:pip install -e . pytest ruff(the dev tools live in a PEP 735[dependency-groups]block, whichuv syncpicks up automatically).
Contributing
Contributions are welcome! Feel free to open an issue or submit a pull request on GitHub.
License
Released under the MIT License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gsparse-0.2.3.tar.gz.
File metadata
- Download URL: gsparse-0.2.3.tar.gz
- Upload date:
- Size: 26.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d1b529daa42328c2d3f5c1ae14ac7330b5cb52cce1f68e8d8b0468e6696c50d
|
|
| MD5 |
304f75d63d8f277e176af71069b8f2e0
|
|
| BLAKE2b-256 |
9149dd3399e60aec1e9924e00d8226ee6693a7234361fc9ef70ec37c5d3e6c06
|
File details
Details for the file gsparse-0.2.3-py3-none-any.whl.
File metadata
- Download URL: gsparse-0.2.3-py3-none-any.whl
- Upload date:
- Size: 25.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7cfdb7896bb1b5bebdc5175f8568d578dc53b480aadb3fc772ffeff90ef4a8bf
|
|
| MD5 |
0e39171f6cecbedc55d574282744a31d
|
|
| BLAKE2b-256 |
d99d5f179ff82af3a9c6befd0d1eac3bd4a72b5ee5d244c60a9778e86e62b3eb
|