From 6a27c210082188262d0f96000be6216ffdccd81b Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Fri, 11 Sep 2026 16:24:58 +0200 Subject: [PATCH] [fix] engine: pinterest - fix empty titles and complete modernization (#6694) * [fix] engine: pinterest - fix empty titles and complete modernization The titles from the fields ``title`` and ``grid_title`` are mostly empty or have short strings without meaningful content. Various fields for the title are now being queried, which have more informative value. As part of the bug fix, the engine was completely revised and modernized. Related: - https://github.com/searxng/searxng/pull/6690#issuecomment-5631113121 Co-authored-by: @vojkovic --- searx/engines/pinterest.py | 95 ++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/searx/engines/pinterest.py b/searx/engines/pinterest.py index 7937743af..4cc2af812 100644 --- a/searx/engines/pinterest.py +++ b/searx/engines/pinterest.py @@ -2,72 +2,85 @@ """Pinterest (images)""" from json import dumps +import typing as t +from searx.result_types import EngineResults + +if t.TYPE_CHECKING: + from searx.extended_types import SXNG_Response + from searx.search.processors import OnlineParams about = { - "website": 'https://www.pinterest.com/', - "wikidata_id": 'Q255381', - "official_api_documentation": 'https://developers.pinterest.com/docs/api/v5/', + "website": "https://www.pinterest.com/", + "wikidata_id": "Q255381", + "official_api_documentation": "https://developers.pinterest.com/docs/api/v5/", "use_official_api": False, "require_api_key": False, - "results": 'JSON', + "results": "JSON", } -categories = ['images'] +categories = ["images"] paging = True -base_url = 'https://www.pinterest.com' +base_url = "https://www.pinterest.com" -def request(query, params): +def request(query: str, params: "OnlineParams") -> None: + args = { - 'options': { - 'query': query, - 'bookmarks': [params['engine_data'].get('bookmark', '')], + "options": { + "query": query, + "bookmarks": [params["engine_data"].get("bookmark", "")], }, - 'context': {}, + "context": {}, } - params['url'] = f"{base_url}/resource/BaseSearchResource/get/?data={dumps(args)}" - params['headers'] = { - 'X-Pinterest-AppState': 'active', - 'X-Pinterest-Source-Url': '/ideas/', - 'X-Pinterest-PWS-Handler': 'www/ideas.js', + params["url"] = f"{base_url}/resource/BaseSearchResource/get/?data={dumps(args)}" + params["headers"] = { + "X-Requested-With": "XMLHttpRequest", + "X-Pinterest-AppState": "active", + "X-Pinterest-Source-Url": "/ideas/", + "X-Pinterest-PWS-Handler": "www/ideas.js", } - return params +def response(resp: "SXNG_Response") -> EngineResults: + res = EngineResults() + json_resp: dict[str, t.Any] = resp.json() # type: ignore -def response(resp): - results = [] - - json_resp = resp.json() - - results.append( + res.add( { - 'engine_data': json_resp['resource_response']['bookmark'], + "engine_data": json_resp["resource_response"]["bookmark"], # it's called bookmark by pinterest, but it's rather a nextpage # parameter to get the next results - 'key': 'bookmark', + "key": "bookmark", } ) - for result in json_resp['resource_response']['data']['results']: + for result in json_resp["resource_response"]["data"]["results"]: - if result['type'] == 'story': + if result["type"] == "story": continue - main_image = result['images']['orig'] - results.append( - { - 'template': 'images.html', - 'url': result.get('link') or f"{base_url}/pin/{result['id']}/", - 'title': result.get('title') or result.get('grid_title'), - 'content': (result.get('rich_summary') or {}).get('display_description') or "", - 'img_src': main_image['url'], - 'thumbnail_src': result['images']['236x']['url'], - 'source': (result.get('rich_summary') or {}).get('site_name'), - 'resolution': f"{main_image['width']}x{main_image['height']}", - 'author': f"{result['pinner'].get('full_name')} ({result['pinner']['username']})", - } + main_image = result["images"]["orig"] + + title = result.get("title") or result.get("grid_title") or "" + if len(title) < 5: + visual_annotation = result.get("pin_join", {}).get("visual_annotation") + if visual_annotation: + title = visual_annotation[0] + else: + title = result.get("name") or result.get("auto_alt_text") or "" + + res.add( + res.types.Image( + url=result.get("link") or f"{base_url}/pin/{result['id']}/", + title=title, + content=(result.get("rich_summary") or {}).get("display_description") or "", + img_src=main_image["url"], + thumbnail_src=result["images"]["236x"]["url"], + source=(result.get("rich_summary") or {}).get("site_name") or "", + resolution=f"{main_image['width']}x{main_image['height']}", + author=f"{result['pinner'].get('full_name')} ({result['pinner']['username']})", + ) ) - return results + return res