Bliss is a book price monitoring web scraper written in Go
1.4K

Bliss is a book price monitoring application written in Go to collect, store, and process price listings from online retailers. The collected price data is stored in a local database (InfluxDB) and can be viewed on the supplied dashboard (Grafana). State is saved in in-memory storage (Redis). Bliss also supports sending push notifications using the Pushover mobile app so you can get notified on your phone when prices drop, books become available for order and more.
Bliss on Gitlab
Bliss on Docker Hub
Pushover notifications on mobile
Grafana dashboard in browser
The following topics explain how to use Bliss, what features are available, and the overall structure of the system. Bliss is packaged to run in docker, and set up to start "out of the box" using the default docker-compose.yml file in the repository with no changes needed to try it out.
Run docker-compose up --detach to start Bliss. Logs can be read with docker logs --follow bliss, log verbosity is set with BLISS_LOG_LEVEL.
Edit the lines of the BLISS_BOOKS variable to add or remove books and restart Bliss by running docker-compose up --detach again. The line format for BLISS_BOOKS is <ISBN> <Format> <Title>, where <ISBN> is an ISBN-13 number and <Format> is optional and one of SC (softcover) or HC (hardcover). Optionally it's possible to use BLISS_BOOKS_FILE to load the books list from a yaml file instead, see docker-compose.yml and books.example.yml for an example. If both BLISS_BOOKS and BLISS_BOOKS_FILE are defined BLISS_BOOKS will take precendence.
Note: indentation is important in yaml. See the default docker-compose.yml for examples.
To stop Bliss run docker-compose down and clean up docker images and volumes with docker system prune --all --volumes if uninstalling and removing all data.
Why should I specify the book format when Bliss uses ISBN anyway?
Some sites, like Amazon, list multiple formats of a book as purchase options even when searching for a specific ISBN. Specifying which format the book is in allows Bliss to fetch the correct price even if other formats are returned in the search results. If the book format is not specified in the configuration Bliss will fetch it automatically, in case Bliss fetches the wrong format for a book it can be overridden by adding the format to the configuration and restarting Bliss.
Grafana is the supplied dashboard for visualizing the data collected by Bliss. The dashboard is reached at localhost:3000 by default.
Bliss exposes Prometheus metrics at localhost:8085/metrics by default (the http server listens to BLISS_HTTP_PORT).
Metrics are only exposed for books which Bliss has been able to find listings for, i.e. if a metric is not exposed for a book it either hasn't been scraped yet, or the book is not available at any retailers.
Consequently previously exposed lowest price metrics will be removed if books go out of stock.
The table below lists all configuration parameters that can be set for Bliss and what values are expected.
For example configuration, see the docker-compose.yml file.
| Environment variable | Description | Type | Accepted values |
|---|---|---|---|
| TZ | Linux time zone | String | See list of tz database time zones |
| BLISS_PROXY_ADDRESS | Proxy address for listing requests (optional) | String | "socks5://localhost:2000" |
| BLISS_DEVELOPER_LOGS | Enable detailed developer log output | Boolean | "true", "false" |
| BLISS_LOG_LEVEL | Set log output verbosity | String | "DEBUG", "INFO", "WARN", "ERROR" |
| BLISS_BOOKS | List of books for price monitoring | String | New line separated items with space separated fields for ISBN-13, format and title. Takes precedence over BLISS_BOOKS_FILE. |
| BLISS_BOOKS_FILE | File containint list of books for price monitoring | String | Yaml file containing books to monitor, this is an alternative to using BLISS_BOOKS |
| BLISS_CURRENCY | Currency to convert all fetched prices to | String | ISO 4217 currency code |
| BLISS_INTERVAL | Interval in minutes for requests to each site | Integer | Positive integer greater than 0 |
| BLISS_ENABLE_ADLIBRIS | Enable monitoring of adlibris.com | Boolean | "true", "false" |
| BLISS_ENABLE_AKADEMIBOKHANDELN | Enable monitoring of akademibokhandeln.se | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_AE | Enable monitoring of amazon.ae | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_CA | Enable monitoring of amazon.ca | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_COM | Enable monitoring of amazon.com | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_COM_AU | Enable monitoring of amazon.com.au | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_CO_UK | Enable monitoring of amazon.co.uk | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_DE | Enable monitoring of amazon.de | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_ES | Enable monitoring of amazon.es | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_FR | Enable monitoring of amazon.fr | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_IN | Enable monitoring of amazon.in | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_IT | Enable monitoring of amazon.it | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_NL | Enable monitoring of amazon.nl | Boolean | "true", "false" |
| BLISS_ENABLE_AMAZON_SE | Enable monitoring of amazon.se | Boolean | "true", "false" |
| BLISS_ENABLE_BLACKWELLS | Enable monitoring of blackwells.co.uk | Boolean | "true", "false" |
| BLISS_ENABLE_BOKUS | Enable monitoring of bokus.se | Boolean | "true", "false" |
| BLISS_ENABLE_BOOKDEPOSITORY | Enable monitoring of bookdepository.com | Boolean | "true", "false" |
| BLISS_ENABLE_BOOKSWAGON | Enable monitoring of bookswagon.com | Boolean | "true", "false" |
| BLISS_ENABLE_CDON | Enable monitoring of cdon.com | Boolean | "true", "false" |
| BLISS_ENABLE_FLIPKART | Enable monitoring of flipkart.com | Boolean | "true", "false" |
| BLISS_ENABLE_FORBIDDEN_PLANET | Enable monitoring of forbiddenplanet.com | Boolean | "true", "false" |
| BLISS_ENABLE_SCIFIBOKHANDELN | Enable monitoring of sfbok.se | Boolean | "true", "false" |
| BLISS_ENABLE_WALTS_COMIC_SHOP | Enable monitoring of waltscomicshop.com | Boolean | "true", "false" |
| BLISS_ENABLE_WATERSTONES | Enable monitoring of waterstones.co.uk | Boolean | "true", "false" |
| BLISS_ENABLE_WORDERY | Enable monitoring of wordery.com | Boolean | "true", "false" |
| BLISS_DB_ADDRESS | InfluxDB address | String | "host:port" |
| BLISS_DB_USER | InfluxDB username | String | |
| BLISS_DB_PASSWORD | InfluxDB password | String | |
| BLISS_DB_NAME | InfluxDB database name | String | |
| BLISS_DB_RETENTION | InfluxDB retention policy (how long to keep records) | String | "one_day", "one_week", "one_month", "three_months", "six_months", "one_year" |
| BLISS_REDIS_ADDRESS | Redis address | String | "host:port" |
| BLISS_REDIS_PASSWORD | Redis password | String | |
| BLISS_REDIS_DATABASE | Redis database | String | Positive integer |
| BLISS_HTTP_PORT | Port for Bliss http server to listen on | Integer | 1 to 65535 |
| BLISS_NOTIFY_DROP_THRESHOLD | Price drop notification percentage threshold | Integer | 0 to 100 |
| BLISS_NOTIFY_LOW_STOCK | Enable low stock notifications | Boolean | "true", "false" |
| BLISS_NOTIFY_AVAILABLE | Enable availability notifications | Boolean | "true", "false" |
| BLISS_PUSHOVER_USER_KEY | Pushover API user key | String | 30 character hash supplied by Pushover API (leave empty to disable) |
| BLISS_PUSHOVER_API_TOKEN | Pushover API application token | String | 30 character hash supplied by Pushover API (leave empty to disable) |
Bliss as a system is composed out of 3 main components:
Optionally (but highly recommended) a user can set up the Pushover mobile app to receive event notifications from Bliss (see Notifications). Pushover is the only component of Bliss which is not free, the cost of the app however is a small one-time charge.
flowchart LR
A(Bliss) -->|Listing| B{Bliss}
B{Bliss} -->|Request| A(Retailer)
B <-->|State| G(Redis)
B -->|Notifications| D(Pushover)
B -->|Metrics| E(HTTP /metrics)
B -->|Listings| F(InfluxDB)
F -->|Display| H(Grafana)
H o--o I(User)
D o--o I(User)
Bliss scrapes book prices from enabled sites by continuously iterating over the books defined in the BLISS_BOOKS variable or in a yaml file at the path defined by BLISS_BOOKS_FILE.
The order of scraping depends on the existence of previous listings as detailed below. The prioritization of listings to be scraped optimizes the time to establish the baseline (see Listings Baseline).
Books are scraped with a time interval between requests, set as minutes with BLISS_INTERVAL. The number of books in the books list multiplied by the number of minutes in BLISS_INTERVAL make up a scrape cycle. The scrape cycle is the longest amount of time it can take to scrape all the books listed before starting over on a new cycle. The calculated cycle time is logged when Bliss starts up.
A random time jitter is used to shorten each scrape interval in order to add some irregularity to request times.
Example: A list of 10 books with a scrape interval of 6 minutes will take at most 10*6=60 minutes to scrape before starting over on a new cycle. The random time jitter always shortens the interval, meaning that the cycle will never be longer than 60 minutes in this case, but likely a bit shorter.
NOTE: BLISS_INTERVAL has a lowest accepted value of 1 minute to prevent excessive requests to sites.
Bliss can send notifications using the Pushover API. Enable notifications by setting the BLISS_PUSHOVER_USER_KEY and BLISS_PUSHOVER_API_TOKEN variables, or omit them to leave notifications disabled.
Event notifications will not be sent until baseline listings have been established. All enabled scrapers need to scrape all the books listed in BLISS_BOOKS at least once (or have a previous listing loaded from the database at startup) to complete the baseline. Once the baseline is established a notification will be sent to inform that event notifications have been enabled.
These are the types of notifications sent by Bliss:
| Notification | Type | Description |
|---|---|---|
| Book Monitoring Started | Info | Notification when Bliss starts up, displays the expected time within which the baseline scraping will be completed. |
| Event Notifications Enabled | Info | Notification when the baseline has been established, enabling event notifications. |
| Book Stock Running Low | Event | Event notification when a book drops down to being in stock at only one retailer. |
| Book Available | Event | Event notification when a book has been out of stock at all retailers, but is now available for order again. |
| Book Price Drop | Event | Event notification when a book price drops more than BLISS_NOTIFY_DROP_THRESHOLD. |
Bliss can be configured to only send price drop notifications at and above a certain threshold. This can be useful to prevent excessive notifications being sent due to small price adjustments at retailers. Setting BLISS_NOTIFY_DROP_THRESHOLD to 10 will only send notifications when a price drops 10% or more.
Bliss is licensed under the terms of GNU GPLv3
Did you find Bliss useful, and perhaps managed to snag a book at a great price?
Consider showing your appreciation by donating!
Copyright © 2020 Tommy Alatalo
Content type
Image
Digest
sha256:578bd8f9f…
Size
8.9 MB
Last updated
almost 4 years ago
docker pull altosys/bliss