Metadata-Version: 2.4
Name: storygraph-scraper
Version: 1.1.2
Summary: This package allows you to interact with and fetch data from the StoryGraph website.
Home-page: https://github.com/Tzahi12345/storygraph-api
Author: Tzahi12345
Author-email: tzahi2g@gmail.com
Keywords: storygraph,storygraph api,api storygraph,storygraph scraper
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: beautifulsoup4
Requires-Dist: selenium
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# storygraph-scraper
A python package to interact with and fetch data from the [StoryGraph](https://app.thestorygraph.com/) website.

This is a fork of [ym496/storygraph-api](https://github.com/ym496/storygraph-api), updated to work
around StoryGraph's Cloudflare bot-protection and to fix pagination on user reading lists (the original truncated
long lists to the first page).

## Features
- **Book Details**: Fetch detailed information about a book using its unique ID.
- **Search**: Perform a book search on StoryGraph and retrieve the results.
- **Fetch User lists** (fully paginated):
    -  currently reading
    -  to read
    -  books read

## Installation
```
pip install storygraph-scraper
```
The PyPI distribution is named `storygraph-scraper`, but the importable package is still `storygraph_api`:
```python
from storygraph_api import Book, User
```

### Requirements
- **Google Chrome must be installed.** StoryGraph sits behind a Cloudflare challenge that blocks plain HTTP
  requests and headless browsers (`--headless` gets detected and blocked), so every call in this package drives a
  real (non-headless) Chrome window via Selenium. The window is positioned off-screen so it won't visibly pop up
  on your desktop, but Chrome still needs an actual display to attach to - on a headless server/container, run it
  under a virtual display such as Xvfb.
- Each call takes a few seconds (single-page endpoints) up to roughly a minute or more for a user with a very
  large reading list, since long lists are paginated ~10-20 books per page and each page is a full browser
  navigation.

## Getting Started

The API is divided into two components, `Book` and `User`.

### Book Details

```python
from storygraph_api import Book

book = Book()

# Fetch details of a book using its ID (found in the book's URL:
# app.thestorygraph.com/books/<book_id>)
result = book.book_info("fbdd6b7c-f512-47f2-aa94-d8bf0d5f5175")
print(result)
```
#### Result:
```json
{
  "title": "Hagakure: The Book of the Samurai",
  "authors": [
    "Yamamoto Tsunetomo",
    "William Scott Wilson"
  ],
  "pages": "179",
  "first_pub": "1716",
  "tags": [
    "nonfiction",
    "history",
    "philosophy",
    "informative",
    "reflective",
    "slow-paced"
  ],
  "average_rating": "3.65",
  "description": "...",
  "warnings": {
    "graphic": ["Suicide", "Violence"],
    "moderate": ["Suicide", "Suicide attempt", "War"],
    "minor": ["Gore"]
  }
}
```

```python
# Search for books
result = book.search("pride and prejudice")
print(result)
```
#### Result:
```json
[
  {
    "title": "Pride and Prejudice",
    "author": "Jane Austen",
    "book_id": "d4bee89f-3fdd-4dd0-8d77-4316bed132e7",
    "link": "https://app.thestorygraph.com/books/d4bee89f-3fdd-4dd0-8d77-4316bed132e7"
  }
]
```

### User Lists

StoryGraph requires being logged in to view **any** profile, even public ones, so every `User` method needs your
`remember_user_token` cookie:
1. Log into [thestorygraph.com](https://app.thestorygraph.com) in your browser.
2. Open DevTools -> **Application** tab -> **Cookies** -> `https://app.thestorygraph.com`.
3. Copy the value of the `remember_user_token` cookie.

Treat that value like a password - it grants full access to that account for as long as it's valid (it's typically
signed with a far-future expiry, so it won't just expire on its own).

```python
import os
from dotenv import load_dotenv
from storygraph_api import User

load_dotenv()
cookie = os.getenv("COOKIE")  # keep the cookie in a local .env file, not in source
uname = "sampleuname"

user = User()
result = user.currently_reading(uname, cookie=cookie)
print(result)
```

#### Result:
```json
[
  {
    "title": "The Murder After the Night Before",
    "book_id": "38cb5b56-23f1-48fd-b4b3-a80e07a19775",
    "authors": ["Sylvia Bishop"],
    "link": "https://app.thestorygraph.com/books/38cb5b56-23f1-48fd-b4b3-a80e07a19775"
  },
  {
    "title": "The Graces",
    "book_id": "653b54b3-a79d-4c2e-ae40-eae281a91315",
    "authors": ["Laure Eve"],
    "link": "https://app.thestorygraph.com/books/653b54b3-a79d-4c2e-ae40-eae281a91315"
  }
]
```

Other list methods work the same way:
```python
user.to_read(uname, cookie=cookie)
user.books_read(uname, cookie=cookie)
```

`currently_reading` returns only actively-reading books (StoryGraph's separate "paused" section is excluded).
`books_read` deduplicates by book, so a reread only appears once even though StoryGraph counts it as two reading
sessions.

## Error Handling

Every method returns its result as a JSON string on success. On failure, it returns a JSON string of the form
`{"error": "..."}` instead of raising - check for an `"error"` key rather than wrapping calls in `try`/`except`.

## Further Information
*  Refer to [books_client.py](https://github.com/Tzahi12345/storygraph-api/tree/main/storygraph_api/books_client.py)
   and [users_client.py](https://github.com/Tzahi12345/storygraph-api/tree/main/storygraph_api/users_client.py) for
   full docstrings on every method.

## Contributing
Contributions are welcome! Fork the repository, make your changes, and submit a pull request.

Run the test suite with:
```
pip install pytest
pytest test/
```
These tests run against fixture HTML in `test/fixtures/` and don't need Chrome, a network connection, or a
StoryGraph account.

For bugs or feature requests, please open an issue on [GitHub](https://github.com/Tzahi12345/storygraph-api/issues).

## License

This project is licensed under the MIT License.
