interactive bots: Improve googlesearch bot.

This commit is contained in:
fredfishgames 2017-11-30 16:52:45 +00:00 committed by showell
parent 1d2d6c9cf7
commit b157b817ae
9 changed files with 118 additions and 33 deletions

View file

@ -0,0 +1,23 @@
# Google Search bot
This bot allows users to do Google search queries and have the bot
respond with the first search result. It is by default set to the
highest safe-search setting.
## Usage
Run this bot as described
[here](https://zulipchat.com/api/running-bots#running-a-bot).
Use this bot with the following command
`@mentioned-bot <search terms>`
This will return the first link found by Google for `<search terms>`
and print the resulting URL.
If no `<search terms>` are entered, a help message is printed instead.
If there was an error in the process of running the search (socket
errors, Google search function failed, or general failures), an error
message is returned.

View file

@ -0,0 +1,13 @@
{
"request": {
"api_url": "http://www.google.com/search",
"params": {
"q": "no res"
}
},
"response": "<head></head><body><div id='search'></div></body>",
"response-headers": {
"status": 200,
"content-type": "text/html; charset=utf-8"
}
}

View file

@ -0,0 +1,13 @@
{
"request": {
"api_url": "http://www.google.com/search",
"params": {
"q": "zulip"
}
},
"response": "<head></head><body><div id='search'><a href='/url?url=https%3A%2F%2Fzulipchat.com%2F'>Zulip</a></div></body>",
"response-headers": {
"status": 200,
"content-type": "text/html; charset=utf-8"
}
}

View file

@ -0,0 +1,103 @@
# See readme.md for instructions on running this code.
from __future__ import print_function
import logging
from six.moves.urllib import parse
import requests
from bs4 import BeautifulSoup
def google_search(keywords):
query = {'q': keywords}
# Gets the page
page = requests.get('http://www.google.com/search', params=query)
# Parses the page into BeautifulSoup
soup = BeautifulSoup(page.text, "lxml")
# Gets all search URLs
anchors = soup.find(id='search').findAll('a')
results = []
for a in anchors:
try:
# Tries to get the href property of the URL
link = a['href']
except KeyError:
continue
# Link must start with '/url?', as these are the search result links
if (not link.startswith('/url?')):
continue
# Makes sure a hidden 'cached' result isn't displayed
if (a.text.strip() == 'Cached' and 'webcache.googleusercontent.com'):
continue
if (a.text.strip() == ''):
continue
# a.text: The name of the page
result = {'url': "https://www.google.com{}".format(link),
'name': a.text}
results.append(result)
return results
def get_google_result(search_keywords):
help_message = "To use this bot, start messages with @mentioned-bot, \
followed by what you want to search for. If \
found, Zulip will return the first search result \
on Google.\
\
An example message that could be sent is:\
'@mentioned-bot zulip' or \
'@mentioned-bot how to create a chatbot'."
search_keywords = search_keywords.strip()
if search_keywords == 'help':
return help_message
elif search_keywords == '' or search_keywords is None:
return help_message
else:
try:
results = google_search(search_keywords)
if (len(results) == 0):
return "Found no results."
return "Found Result: [{}]({})".format(results[0]['name'], results[0]['url'])
except ConnectionError as c_err:
return "Error: Failed to connect. {}.".format(c_err)
except AttributeError as a_err:
# google.search query failed and urls is of object
# 'NoneType'
logging.exception(a_err)
return "Error: Google search failed with a NoneType result. {}.".format(a_err)
except TypeError as t_err:
# google.search query failed and returned None
# This technically should not happen but the prior
# error check assumed this behavior
logging.exception(t_err)
return "Error: Google search function failed. {}.".format(t_err)
except Exception as e:
return 'Error: Search failed. {}.'.format(e)
class GoogleSearchHandler(object):
'''
This plugin allows users to enter a search
term in Zulip and get the top URL sent back
to the context (stream or private) in which
it was called. It looks for messages starting
with @mentioned-bot.
'''
def usage(self):
return '''
This plugin will allow users to search
for a given search term on Google from
Zulip. Use '@mentioned-bot help' to get
more information on the bot usage. Users
should preface messages with
@mentioned-bot.
'''
def handle_message(self, message, bot_handler):
original_content = message['content']
result = get_google_result(original_content)
bot_handler.send_reply(message, result)
handler_class = GoogleSearchHandler

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,46 @@
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import print_function
import random
from six.moves.urllib import error
from zulip_bots.test_lib import BotTestCase
class TestGoogleSearchBot(BotTestCase):
bot_name = 'googlesearch'
# Simple query
def test_normal(self):
with self.mock_http_conversation('test_normal'):
self.assert_bot_response({'content': 'zulip'}, {'content': 'Found Result: [Zulip](https://www.google.com/url?url=https%3A%2F%2Fzulipchat.com%2F)'}, 'send_reply')
# Help without typing anything
def test_bot_help_none(self):
help_message = "To use this bot, start messages with @mentioned-bot, \
followed by what you want to search for. If \
found, Zulip will return the first search result \
on Google.\
\
An example message that could be sent is:\
'@mentioned-bot zulip' or \
'@mentioned-bot how to create a chatbot'."
self.assert_bot_response({'content': ''}, {'content': help_message}, 'send_reply')
# Help from typing 'help'
def test_bot_help(self):
help_message = "To use this bot, start messages with @mentioned-bot, \
followed by what you want to search for. If \
found, Zulip will return the first search result \
on Google.\
\
An example message that could be sent is:\
'@mentioned-bot zulip' or \
'@mentioned-bot how to create a chatbot'."
self.assert_bot_response({'content': 'help'}, {'content': help_message}, 'send_reply')
def test_bot_no_results(self):
with self.mock_http_conversation('test_no_result'):
self.assert_bot_response({'content': 'no res'}, {'content': 'Found no results.'}, 'send_reply')