.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
springer.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2"""`Springer Nature`_ is a global publisher dedicated to providing service to
3research community with official Springer-API_ (API-Playground_).
4
5.. note::
6
7 The Springer engine requires an API key, which can be obtained via the
8 `Springer subscription`_.
9
10Since the search term is passed 1:1 to the API, SearXNG users can use the
11`Supported Query Parameters`_.
12
13- ``!springer (doi:10.1007/s10948-025-07019-1 OR doi:10.1007/s10948-025-07035-1)``
14- ``!springer keyword:ybco``
15
16However, please note that the available options depend on the subscription type.
17
18For example, the ``year:`` filter requires a *Premium Plan* subscription.
19
20- ``!springer keyword:ybco year:2024``
21
22The engine uses the REST Meta-API_ `v2` endpoint, but there is also a `Python
23API Wrapper`_.
24
25.. _Python API Wrapper: https://pypi.org/project/springernature-api-client/
26.. _Springer Nature: https://www.springernature.com/
27.. _Springer subscription: https://dev.springernature.com/subscription/
28.. _Springer-API: https://dev.springernature.com/docs/introduction/
29.. _API-Playground: https://dev.springernature.com/docs/live-documentation/
30.. _Meta-API: https://dev.springernature.com/docs/api-endpoints/meta-api/
31.. _Supported Query Parameters: https://dev.springernature.com/docs/supported-query-params/
32
33
34Configuration
35=============
36
37The engine has the following additional settings:
38
39- :py:obj:`api_key`
40
41.. code:: yaml
42
43 - name: springer nature
44 api_key: "..."
45 inactive: false
46
47
48Implementations
49===============
50
51"""
52
53import typing as t
54
55from datetime import datetime
56from urllib.parse import urlencode
57
58from searx.network import raise_for_httperror
59from searx.result_types import EngineResults
60
61if t.TYPE_CHECKING:
62 from searx.extended_types import SXNG_Response
63 from searx.search.processors import OnlineParams
64
65about = {
66 "website": "https://www.springernature.com/",
67 "wikidata_id": "Q21096327",
68 "official_api_documentation": "https://dev.springernature.com/docs/live-documentation/",
69 "use_official_api": True,
70 "require_api_key": True,
71 "results": "JSON",
72}
73
74categories = ["science", "scientific publications"]
75
76paging = True
77nb_per_page = 10
78"""Number of results to return in the request, see `Pagination and Limits`_ for
79more details.
80
81.. _Pagination and Limits:
82 https://dev.springernature.com/docs/advanced-querying/pagination-limits/
83"""
84
85api_key = ""
86"""Key used for the Meta-API_. Get your API key from: `Springer subscription`_"""
87
88base_url = "https://api.springernature.com/meta/v2/json"
89"""An enhanced endpoint with additional metadata fields and optimized queries
90for more efficient and comprehensive retrieval (Meta-API_ `v2`).
91"""
92
93
94def setup(engine_settings: dict[str, t.Any]) -> bool:
95 """Initialization of the Springer engine, checks whether the
96 :py:obj:`api_key` is set, otherwise the engine is inactive.
97 """
98 key: str = engine_settings.get("api_key", "")
99 try:
100 # Springer's API key is a hex value
101 int(key, 16)
102 return True
103 except ValueError:
104 logger.error("Springer's API key is not set or invalid.")
105 return False
106
107
108def request(query: str, params: "OnlineParams") -> None:
109 args = {
110 "api_key": api_key,
111 "q": query,
112 "s": nb_per_page * (params["pageno"] - 1),
113 "p": nb_per_page,
114 }
115 params["url"] = f"{base_url}?{urlencode(args)}"
116 # For example, the ``year:`` filter requires a *Premium Plan* subscription.
117 params["raise_for_httperror"] = False
118
119
120def response(resp: "SXNG_Response") -> EngineResults:
121
122 res = EngineResults()
123 json_data = resp.json()
124
125 if (
126 resp.status_code == 403
127 and json_data["status"].lower() == "fail"
128 and "premium feature" in json_data["message"].lower()
129 ):
130 return res
131 raise_for_httperror(resp)
132
133 def field(k: str) -> str:
134 return str(record.get(k, ""))
135
136 for record in json_data["records"]:
137 published = datetime.strptime(record["publicationDate"], "%Y-%m-%d")
138 authors: list[str] = [" ".join(author["creator"].split(", ")[::-1]) for author in record["creators"]]
139
140 pdf_url = ""
141 html_url = ""
142 url_list: list[dict[str, str]] = record["url"]
143
144 for item in url_list:
145 if item["platform"] != "web":
146 continue
147 val = item["value"].replace("http://", "https://", 1)
148 if item["format"] == "html":
149 html_url = val
150 elif item["format"] == "pdf":
151 pdf_url = val
152
153 paper = res.types.Paper(
154 url=html_url,
155 # html_url=html_url,
156 pdf_url=pdf_url,
157 title=field("title"),
158 content=field("abstract"),
159 comments=field("publicationName"),
160 tags=record.get("keyword", []),
161 publishedDate=published,
162 type=field("contentType"),
163 authors=authors,
164 publisher=field("publisher"),
165 journal=field("publicationName"),
166 volume=field("volume"),
167 pages="-".join([x for x in [field("startingPage"), field("endingPage")] if x]),
168 number=field("number"),
169 doi=field("doi"),
170 issn=[x for x in [field("issn")] if x],
171 isbn=[x for x in [field("isbn")] if x],
172 )
173 res.add(paper)
174
175 return res
EngineResults response("SXNG_Response" resp)
Definition springer.py:120
bool setup(dict[str, t.Any] engine_settings)
Definition springer.py:94
None request(str query, "OnlineParams" params)
Definition springer.py:108