autocomplete.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. '''
  2. searx is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU Affero General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. searx is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU Affero General Public License for more details.
  10. You should have received a copy of the GNU Affero General Public License
  11. along with searx. If not, see < http://www.gnu.org/licenses/ >.
  12. (C) 2013- by Adam Tauber, <asciimoo@gmail.com>
  13. '''
  14. from lxml import etree
  15. from json import loads
  16. from urllib.parse import urlencode
  17. from requests import RequestException
  18. from searx import settings
  19. from searx.poolrequests import get as http_get
  20. from searx.exceptions import SearxEngineResponseException
  21. def get(*args, **kwargs):
  22. if 'timeout' not in kwargs:
  23. kwargs['timeout'] = settings['outgoing']['request_timeout']
  24. kwargs['raise_for_httperror'] = True
  25. return http_get(*args, **kwargs)
  26. def dbpedia(query, lang):
  27. # dbpedia autocompleter, no HTTPS
  28. autocomplete_url = 'https://lookup.dbpedia.org/api/search.asmx/KeywordSearch?'
  29. response = get(autocomplete_url + urlencode(dict(QueryString=query)))
  30. results = []
  31. if response.ok:
  32. dom = etree.fromstring(response.content)
  33. results = dom.xpath('//Result/Label//text()')
  34. return results
  35. def duckduckgo(query, lang):
  36. # duckduckgo autocompleter
  37. url = 'https://ac.duckduckgo.com/ac/?{0}&type=list'
  38. resp = loads(get(url.format(urlencode(dict(q=query)))).text)
  39. if len(resp) > 1:
  40. return resp[1]
  41. return []
  42. def google(query, lang):
  43. # google autocompleter
  44. autocomplete_url = 'https://suggestqueries.google.com/complete/search?client=toolbar&'
  45. response = get(autocomplete_url + urlencode(dict(hl=lang, q=query)))
  46. results = []
  47. if response.ok:
  48. dom = etree.fromstring(response.text)
  49. results = dom.xpath('//suggestion/@data')
  50. return results
  51. def startpage(query, lang):
  52. # startpage autocompleter
  53. url = 'https://startpage.com/do/suggest?{query}'
  54. resp = get(url.format(query=urlencode({'query': query}))).text.split('\n')
  55. if len(resp) > 1:
  56. return resp
  57. return []
  58. def swisscows(query, lang):
  59. # swisscows autocompleter
  60. url = 'https://swisscows.ch/api/suggest?{query}&itemsCount=5'
  61. resp = loads(get(url.format(query=urlencode({'query': query}))).text)
  62. return resp
  63. def qwant(query, lang):
  64. # qwant autocompleter (additional parameter : lang=en_en&count=xxx )
  65. url = 'https://api.qwant.com/api/suggest?{query}'
  66. resp = get(url.format(query=urlencode({'q': query, 'lang': lang})))
  67. results = []
  68. if resp.ok:
  69. data = loads(resp.text)
  70. if data['status'] == 'success':
  71. for item in data['data']['items']:
  72. results.append(item['value'])
  73. return results
  74. def wikipedia(query, lang):
  75. # wikipedia autocompleter
  76. url = 'https://' + lang + '.wikipedia.org/w/api.php?action=opensearch&{0}&limit=10&namespace=0&format=json'
  77. resp = loads(get(url.format(urlencode(dict(search=query)))).text)
  78. if len(resp) > 1:
  79. return resp[1]
  80. return []
  81. backends = {'dbpedia': dbpedia,
  82. 'duckduckgo': duckduckgo,
  83. 'google': google,
  84. 'startpage': startpage,
  85. 'swisscows': swisscows,
  86. 'qwant': qwant,
  87. 'wikipedia': wikipedia
  88. }
  89. def search_autocomplete(backend_name, query, lang):
  90. backend = backends.get(backend_name)
  91. if backend is None:
  92. return []
  93. try:
  94. return backend(query, lang)
  95. except (RequestException, SearxEngineResponseException):
  96. return []