PageRenderTime 44ms CodeModel.GetById 38ms app.highlight 5ms RepoModel.GetById 0ms app.codeStats 0ms

/sopel/modules/search.py

https://gitlab.com/daniellawrence/sopel
Python | 133 lines | 119 code | 4 blank | 10 comment | 4 complexity | fe8baa41ae73ac2de2c070cf0cf89680 MD5 | raw file
  1# coding=utf-8
  2"""
  3search.py - Sopel Web Search Module
  4Copyright 2008-9, Sean B. Palmer, inamidst.com
  5Copyright 2012, Edward Powell, embolalia.net
  6Licensed under the Eiffel Forum License 2.
  7
  8http://sopel.chat
  9"""
 10from __future__ import unicode_literals, absolute_import, print_function, division
 11
 12import re
 13from sopel import web
 14from sopel.module import commands, example
 15import json
 16import sys
 17
 18if sys.version_info.major < 3:
 19    from urllib import quote_plus
 20else:
 21    from urllib.parse import quote_plus
 22
 23
 24def formatnumber(n):
 25    """Format a number with beautiful commas."""
 26    parts = list(str(n))
 27    for i in range((len(parts) - 3), 0, -3):
 28        parts.insert(i, ',')
 29    return ''.join(parts)
 30
 31r_bing = re.compile(r'<h3><a href="([^"]+)"')
 32
 33
 34def bing_search(query, lang='en-GB'):
 35    base = 'http://www.bing.com/search?mkt=%s&q=' % lang
 36    bytes = web.get(base + query)
 37    m = r_bing.search(bytes)
 38    if m:
 39        return m.group(1)
 40
 41r_duck = re.compile(r'nofollow" class="[^"]+" href="(.*?)">')
 42
 43
 44def duck_search(query):
 45    query = query.replace('!', '')
 46    uri = 'http://duckduckgo.com/html/?q=%s&kl=uk-en' % query
 47    bytes = web.get(uri)
 48    if 'web-result"' in bytes:  # filter out the adds on top of the page
 49        bytes = bytes.split('web-result"')[1]
 50    m = r_duck.search(bytes)
 51    if m:
 52        return web.decode(m.group(1))
 53
 54# Alias google_search to duck_search
 55google_search = duck_search
 56
 57
 58def duck_api(query):
 59    if '!bang' in query.lower():
 60        return 'https://duckduckgo.com/bang.html'
 61
 62    # This fixes issue #885 (https://github.com/sopel-irc/sopel/issues/885)
 63    # It seems that duckduckgo api redirects to its Instant answer API html page
 64    # if the query constains special charactares that aren't urlencoded.
 65    # So in order to always get a JSON response back the query is urlencoded
 66    query = quote_plus(query)
 67    uri = 'http://api.duckduckgo.com/?q=%s&format=json&no_html=1&no_redirect=1' % query
 68    results = json.loads(web.get(uri))
 69    if results['Redirect']:
 70        return results['Redirect']
 71    else:
 72        return None
 73
 74
 75@commands('duck', 'ddg', 'g')
 76@example('.duck privacy or .duck !mcwiki obsidian')
 77def duck(bot, trigger):
 78    """Queries Duck Duck Go for the specified input."""
 79    query = trigger.group(2)
 80    if not query:
 81        return bot.reply('.ddg what?')
 82
 83    # If the API gives us something, say it and stop
 84    result = duck_api(query)
 85    if result:
 86        bot.reply(result)
 87        return
 88
 89    # Otherwise, look it up on the HTMl version
 90    uri = duck_search(query)
 91
 92    if uri:
 93        bot.reply(uri)
 94        if 'last_seen_url' in bot.memory:
 95            bot.memory['last_seen_url'][trigger.sender] = uri
 96    else:
 97        bot.reply("No results found for '%s'." % query)
 98
 99
100@commands('search')
101@example('.search nerdfighter')
102def search(bot, trigger):
103    """Searches Bing and Duck Duck Go."""
104    if not trigger.group(2):
105        return bot.reply('.search for what?')
106    query = trigger.group(2)
107    bu = bing_search(query) or '-'
108    du = duck_search(query) or '-'
109
110    if bu == du:
111        result = '%s (b, d)' % bu
112    else:
113        if len(bu) > 150:
114            bu = '(extremely long link)'
115        if len(du) > 150:
116            du = '(extremely long link)'
117        result = '%s (b), %s (d)' % (bu, du)
118
119    bot.reply(result)
120
121
122@commands('suggest')
123def suggest(bot, trigger):
124    """Suggest terms starting with given input"""
125    if not trigger.group(2):
126        return bot.reply("No query term.")
127    query = trigger.group(2)
128    uri = 'http://websitedev.de/temp-bin/suggest.pl?q='
129    answer = web.get(uri + query.replace('+', '%2B'))
130    if answer:
131        bot.say(answer)
132    else:
133        bot.reply('Sorry, no result.')