logo

searx

My custom branche(s) on searx, a meta-search engine git clone https://hacktivis.me/git/searx.git

bing_news.py (4047B)


  1. """
  2. Bing (News)
  3. @website https://www.bing.com/news
  4. @provide-api yes (http://datamarket.azure.com/dataset/bing/search),
  5. max. 5000 query/month
  6. @using-api no (because of query limit)
  7. @results RSS (using search portal)
  8. @stable yes (except perhaps for the images)
  9. @parse url, title, content, publishedDate, thumbnail
  10. """
  11. from datetime import datetime
  12. from dateutil import parser
  13. from lxml import etree
  14. from searx.utils import list_get, match_language
  15. from searx.engines.bing import _fetch_supported_languages, supported_languages_url, language_aliases
  16. from searx.url_utils import urlencode, urlparse, parse_qsl
  17. # engine dependent config
  18. categories = ['news']
  19. paging = True
  20. language_support = True
  21. time_range_support = True
  22. # search-url
  23. base_url = 'https://www.bing.com/'
  24. search_string = 'news/search?{query}&first={offset}&format=RSS'
  25. search_string_with_time = 'news/search?{query}&first={offset}&qft=interval%3d"{interval}"&format=RSS'
  26. time_range_dict = {'day': '7',
  27. 'week': '8',
  28. 'month': '9'}
  29. # remove click
  30. def url_cleanup(url_string):
  31. parsed_url = urlparse(url_string)
  32. if parsed_url.netloc == 'www.bing.com' and parsed_url.path == '/news/apiclick.aspx':
  33. query = dict(parse_qsl(parsed_url.query))
  34. return query.get('url', None)
  35. return url_string
  36. # replace the http://*bing4.com/th?id=... by https://www.bing.com/th?id=...
  37. def image_url_cleanup(url_string):
  38. parsed_url = urlparse(url_string)
  39. if parsed_url.netloc.endswith('bing4.com') and parsed_url.path == '/th':
  40. query = dict(parse_qsl(parsed_url.query))
  41. return "https://www.bing.com/th?id=" + query.get('id')
  42. return url_string
  43. def _get_url(query, language, offset, time_range):
  44. if time_range in time_range_dict:
  45. search_path = search_string_with_time.format(
  46. query=urlencode({'q': query, 'setmkt': language}),
  47. offset=offset,
  48. interval=time_range_dict[time_range])
  49. else:
  50. search_path = search_string.format(
  51. query=urlencode({'q': query, 'setmkt': language}),
  52. offset=offset)
  53. return base_url + search_path
  54. # do search-request
  55. def request(query, params):
  56. if params['time_range'] and params['time_range'] not in time_range_dict:
  57. return params
  58. offset = (params['pageno'] - 1) * 10 + 1
  59. language = match_language(params['language'], supported_languages, language_aliases)
  60. params['url'] = _get_url(query, language, offset, params['time_range'])
  61. return params
  62. # get response from search-request
  63. def response(resp):
  64. results = []
  65. rss = etree.fromstring(resp.content)
  66. ns = rss.nsmap
  67. # parse results
  68. for item in rss.xpath('./channel/item'):
  69. # url / title / content
  70. url = url_cleanup(item.xpath('./link/text()')[0])
  71. title = list_get(item.xpath('./title/text()'), 0, url)
  72. content = list_get(item.xpath('./description/text()'), 0, '')
  73. # publishedDate
  74. publishedDate = list_get(item.xpath('./pubDate/text()'), 0)
  75. try:
  76. publishedDate = parser.parse(publishedDate, dayfirst=False)
  77. except TypeError:
  78. publishedDate = datetime.now()
  79. except ValueError:
  80. publishedDate = datetime.now()
  81. # thumbnail
  82. thumbnail = list_get(item.xpath('./News:Image/text()', namespaces=ns), 0)
  83. if thumbnail is not None:
  84. thumbnail = image_url_cleanup(thumbnail)
  85. # append result
  86. if thumbnail is not None:
  87. results.append({'url': url,
  88. 'title': title,
  89. 'publishedDate': publishedDate,
  90. 'content': content,
  91. 'img_src': thumbnail})
  92. else:
  93. results.append({'url': url,
  94. 'title': title,
  95. 'publishedDate': publishedDate,
  96. 'content': content})
  97. # return results
  98. return results