Documentation
¶
Overview ¶
Package douban is the library behind the douban command: the HTTP client, request shaping, and typed data models for Douban (豆瓣).
The client reads Douban through the public web surfaces that serve without a login: subject search, the j/subject_suggest JSON endpoints, book subject pages, the Top 250 / chart / now-playing film lists, and curated doulists. No API key or authentication is required. It sets a real User-Agent, paces requests, and retries transient 429/5xx errors with exponential backoff.
Douban's subdomains differ in anti-bot posture: book subject pages serve fully, but movie subject and celebrity pages redirect to a sec.douban.com challenge. Film data is therefore reached through suggest and the list pages rather than per-film detail pages.
Index ¶
- Constants
- Variables
- type Book
- type Client
- func (c *Client) Book(ctx context.Context, idOrURL string) (*Book, error)
- func (c *Client) Chart(ctx context.Context) ([]Movie, error)
- func (c *Client) Doulist(ctx context.Context, idOrURL string, limit int) ([]DoulistItem, error)
- func (c *Client) Get(ctx context.Context, rawURL string) ([]byte, error)
- func (c *Client) NowPlaying(ctx context.Context, city string, coming bool, limit int) ([]Movie, error)
- func (c *Client) Search(ctx context.Context, query, searchType string, limit int) ([]Result, error)
- func (c *Client) Suggest(ctx context.Context, query, suggestType string, limit int) ([]Suggestion, error)
- func (c *Client) Top250(ctx context.Context, limit int) ([]Movie, error)
- type Config
- type DoulistItem
- type FrodoClient
- func (f *FrodoClient) Book(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Celebrities(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Game(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Get(ctx context.Context, path string, params url.Values) ([]byte, error)
- func (f *FrodoClient) Interests(ctx context.Context, typ, id string, start, count int) ([]byte, error)
- func (f *FrodoClient) Movie(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Music(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Personage(ctx context.Context, id string) ([]byte, error)
- func (f *FrodoClient) Photos(ctx context.Context, typ, id string, start, count int) ([]byte, error)
- func (f *FrodoClient) Rating(ctx context.Context, typ, id string) ([]byte, error)
- func (f *FrodoClient) Reviews(ctx context.Context, typ, id string, start, count int) ([]byte, error)
- func (f *FrodoClient) SearchSubjects(ctx context.Context, q string, start, count int) ([]byte, error)
- func (f *FrodoClient) Subject(ctx context.Context, typ, id string) ([]byte, error)
- func (f *FrodoClient) UserAgent() string
- type FrodoConfig
- type FrodoError
- type Movie
- type Result
- type Suggestion
Constants ¶
const ( // DefaultFrodoBase is the Frodo API origin. DefaultFrodoBase = "https://frodo.douban.com" // DefaultFrodoKey and DefaultFrodoSecret are a recognized Frodo app key pair. // They can be overridden via FrodoConfig (or CLI flags) if Douban rotates them. DefaultFrodoKey = "0dad551ec0f84ed02907ff5c42e8ec70" DefaultFrodoSecret = "bf7dddc7c9cfe6f7" // DefaultFrodoUA is the Frodo Android client User-Agent. The host rejects // any request whose UA does not identify the app (it answers // invalid_apikey, code 1062), so this string is not cosmetic. The // "api-client/1 " prefix matches the form the live app sends. DefaultFrodoUA = "" /* 144-byte string literal not displayed */ )
const DefaultUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
DefaultUserAgent is the browser-like User-Agent sent with every request.
Variables ¶
var ErrForbidden = errors.New("douban: forbidden")
ErrForbidden is returned for a 403, which on Douban means a wall (login-gated or anti-bot) rather than a transient error. Callers record it as blocked so it is not retried like a recoverable failure.
var ErrNotFound = errors.New("douban: not found")
ErrNotFound is returned when Douban has no subject, list, or page for an id.
Functions ¶
This section is empty.
Types ¶
type Book ¶ added in v0.2.0
type Book struct {
ID string `json:"id"`
Title string `json:"title"`
OriginalTitle string `json:"original_title,omitempty"`
Author string `json:"author,omitempty"`
Translator string `json:"translator,omitempty"`
Publisher string `json:"publisher,omitempty"`
Producer string `json:"producer,omitempty"`
PubDate string `json:"pubdate,omitempty"`
Pages string `json:"pages,omitempty"`
Price string `json:"price,omitempty"`
Binding string `json:"binding,omitempty"`
Series string `json:"series,omitempty"`
ISBN string `json:"isbn,omitempty"`
Rating string `json:"rating"`
Summary string `json:"summary,omitempty"`
URL string `json:"url"`
Cover string `json:"cover,omitempty"`
}
Book is the full record for one book subject.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to Douban's public web surfaces.
func (*Client) Book ¶ added in v0.2.0
Book fetches the full record for one book subject. The argument may be a bare id or a pasted book.douban.com URL.
func (*Client) Chart ¶ added in v0.2.0
Chart returns the current Douban film ranking board (/chart).
func (*Client) Doulist ¶ added in v0.2.0
Doulist returns the subjects in a curated list (豆列) in list order. The argument may be a bare id or a pasted www.douban.com/doulist URL. It walks the paged ?start= listing until limit items are collected (default 100).
func (*Client) Get ¶ added in v0.2.0
Get fetches a URL and returns the body, pacing and retrying as configured. It is the exported entry point used by the mirror crawler to fetch arbitrary Douban URLs (sitemaps, subject pages); the lookup commands use the typed helpers built on the same internal get.
func (*Client) NowPlaying ¶ added in v0.2.0
func (c *Client) NowPlaying(ctx context.Context, city string, coming bool, limit int) ([]Movie, error)
NowPlaying returns the films in cinemas now for a city (default beijing). When coming is true it returns the upcoming list from the same page instead.
func (*Client) Search ¶
Search fetches Douban subject-search results for query and searchType. searchType must be one of "book", "movie", or "music". Up to limit results are returned; pass 0 to use a reasonable default (15).
func (*Client) Suggest ¶ added in v0.2.0
func (c *Client) Suggest(ctx context.Context, query, suggestType string, limit int) ([]Suggestion, error)
Suggest queries Douban's j/subject_suggest typeahead. suggestType selects the catalog ("movie" or "book"); movie is the reliable way to resolve a film id, since movie subject pages are sealed. Up to limit results are returned.
type Config ¶
type Config struct {
// BaseURL overrides the host for tests. When empty the client talks to the
// real https://<sub>.douban.com subdomains; when set, every host resolves to
// this single base and is dispatched by path.
BaseURL string
UserAgent string
Rate time.Duration
Timeout time.Duration
Retries int
}
Config holds constructor parameters.
type DoulistItem ¶ added in v0.2.0
type DoulistItem struct {
Rank int `json:"rank"`
ID string `json:"id"`
Title string `json:"title"`
Rating string `json:"rating"`
Abstract string `json:"abstract,omitempty"`
URL string `json:"url"`
Cover string `json:"cover,omitempty"`
}
DoulistItem is one subject in a curated list.
type FrodoClient ¶ added in v0.2.0
type FrodoClient struct {
// contains filtered or unexported fields
}
FrodoClient calls the signed Frodo API.
func NewFrodoClient ¶ added in v0.2.0
func NewFrodoClient(cfg FrodoConfig) *FrodoClient
NewFrodoClient returns a FrodoClient. Empty config fields fall back to the DefaultFrodoConfig values.
func (*FrodoClient) Celebrities ¶ added in v0.2.0
Celebrities returns the directors/actors credit list for a movie.
func (*FrodoClient) Get ¶ added in v0.2.0
Get fetches a signed API path and returns the raw JSON body. It paces and retries transient failures; a 404 maps to ErrNotFound and an API error envelope to *FrodoError.
func (*FrodoClient) Interests ¶ added in v0.2.0
func (f *FrodoClient) Interests(ctx context.Context, typ, id string, start, count int) ([]byte, error)
Interests returns the public per-user ratings and short comments for a subject.
func (*FrodoClient) Movie ¶ added in v0.2.0
Movie, Book, Music, Game fetch a subject detail of that type.
func (*FrodoClient) Personage ¶ added in v0.2.0
Personage fetches the rich celebrity/personage profile (elessar subject).
func (*FrodoClient) Rating ¶ added in v0.2.0
Rating returns the rating breakdown (star distribution, wish/doing/done) for a subject.
func (*FrodoClient) Reviews ¶ added in v0.2.0
func (f *FrodoClient) Reviews(ctx context.Context, typ, id string, start, count int) ([]byte, error)
Reviews returns the long reviews for a subject.
func (*FrodoClient) SearchSubjects ¶ added in v0.2.0
func (f *FrodoClient) SearchSubjects(ctx context.Context, q string, start, count int) ([]byte, error)
SearchSubjects searches across subjects; filter results by item.target_type.
func (*FrodoClient) Subject ¶ added in v0.2.0
Subject fetches a subject of the given Frodo type ("movie", "book", "music", "game"). Movie covers TV as well.
func (*FrodoClient) UserAgent ¶ added in v0.2.0
func (f *FrodoClient) UserAgent() string
UserAgent returns the User-Agent the client sends. Frodo rejects requests that do not identify the app, so this must remain an app UA.
type FrodoConfig ¶ added in v0.2.0
type FrodoConfig struct {
// BaseURL overrides the API origin for tests. Empty means DefaultFrodoBase.
BaseURL string
APIKey string
Secret string
UserAgent string
Rate time.Duration
Timeout time.Duration
Retries int
}
FrodoConfig configures a FrodoClient.
func DefaultFrodoConfig ¶ added in v0.2.0
func DefaultFrodoConfig() FrodoConfig
DefaultFrodoConfig returns a working configuration. The Frodo host tolerates a faster pace than the web hosts, so Rate defaults below the web Crawl-delay.
type FrodoError ¶ added in v0.2.0
type FrodoError struct {
Status int `json:"-"`
Code int `json:"code"`
Request string `json:"request"`
Msg string `json:"msg"`
Localized string `json:"localized_message"`
}
FrodoError is the API's error envelope: a JSON body carrying a numeric code, e.g. 996 (signature error), 997 (unknown apikey), 1062 (rate limited).
func (*FrodoError) Error ¶ added in v0.2.0
func (e *FrodoError) Error() string
type Movie ¶ added in v0.2.0
type Movie struct {
Rank int `json:"rank,omitempty"`
ID string `json:"id"`
Title string `json:"title"`
AKA string `json:"aka,omitempty"`
Year string `json:"year,omitempty"`
Region string `json:"region,omitempty"`
Genres string `json:"genres,omitempty"`
Directors string `json:"directors,omitempty"`
Cast string `json:"cast,omitempty"`
Duration string `json:"duration,omitempty"`
Rating string `json:"rating"`
URL string `json:"url"`
Cover string `json:"cover,omitempty"`
Quote string `json:"quote,omitempty"`
}
Movie is a unified film record; fields a given surface does not carry are omitted from output.
type Result ¶
type Result struct {
Rank int `json:"rank"`
ID string `json:"id"`
Type string `json:"type"`
Title string `json:"title"`
Rating string `json:"rating"`
Abstract string `json:"abstract"`
URL string `json:"url"`
Cover string `json:"cover,omitempty"`
}
Result is the record emitted for every search hit.
type Suggestion ¶ added in v0.2.0
type Suggestion struct {
ID string `json:"id"`
Type string `json:"type"`
Title string `json:"title"`
SubTitle string `json:"sub_title,omitempty"`
Year string `json:"year,omitempty"`
URL string `json:"url"`
Img string `json:"img,omitempty"`
}
Suggestion is the record emitted for every suggest hit.