bing_news.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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 urllib import urlencode
  12. from urlparse import urlparse, parse_qsl
  13. from datetime import datetime
  14. from dateutil import parser
  15. from lxml import etree
  16. from searx.utils import list_get
  17. # engine dependent config
  18. categories = ['news']
  19. paging = True
  20. language_support = True
  21. # search-url
  22. base_url = 'https://www.bing.com/'
  23. search_string = 'news/search?{query}&first={offset}&format=RSS'
  24. # remove click
  25. def url_cleanup(url_string):
  26. parsed_url = urlparse(url_string)
  27. if parsed_url.netloc == 'www.bing.com' and parsed_url.path == '/news/apiclick.aspx':
  28. query = dict(parse_qsl(parsed_url.query))
  29. return query.get('url', None)
  30. return url_string
  31. # replace the http://*bing4.com/th?id=... by https://www.bing.com/th?id=...
  32. def image_url_cleanup(url_string):
  33. parsed_url = urlparse(url_string)
  34. if parsed_url.netloc.endswith('bing4.com') and parsed_url.path == '/th':
  35. query = dict(parse_qsl(parsed_url.query))
  36. return "https://www.bing.com/th?id=" + query.get('id')
  37. return url_string
  38. # do search-request
  39. def request(query, params):
  40. offset = (params['pageno'] - 1) * 10 + 1
  41. if params['language'] == 'all':
  42. language = 'en-US'
  43. else:
  44. language = params['language'].replace('_', '-')
  45. search_path = search_string.format(
  46. query=urlencode({'q': query, 'setmkt': language}),
  47. offset=offset)
  48. params['url'] = base_url + search_path
  49. return params
  50. # get response from search-request
  51. def response(resp):
  52. results = []
  53. rss = etree.fromstring(resp.content)
  54. ns = rss.nsmap
  55. # parse results
  56. for item in rss.xpath('./channel/item'):
  57. # url / title / content
  58. url = url_cleanup(item.xpath('./link/text()')[0])
  59. title = list_get(item.xpath('./title/text()'), 0, url)
  60. content = list_get(item.xpath('./description/text()'), 0, '')
  61. # publishedDate
  62. publishedDate = list_get(item.xpath('./pubDate/text()'), 0)
  63. try:
  64. publishedDate = parser.parse(publishedDate, dayfirst=False)
  65. except TypeError:
  66. publishedDate = datetime.now()
  67. except ValueError:
  68. publishedDate = datetime.now()
  69. # thumbnail
  70. thumbnail = list_get(item.xpath('./News:Image/text()', namespaces=ns), 0)
  71. if thumbnail is not None:
  72. thumbnail = image_url_cleanup(thumbnail)
  73. # append result
  74. if thumbnail is not None:
  75. results.append({'template': 'videos.html',
  76. 'url': url,
  77. 'title': title,
  78. 'publishedDate': publishedDate,
  79. 'content': content,
  80. 'thumbnail': thumbnail})
  81. else:
  82. results.append({'url': url,
  83. 'title': title,
  84. 'publishedDate': publishedDate,
  85. 'content': content})
  86. # return results
  87. return results