|
@@ -8,12 +8,14 @@
|
|
|
#
|
|
|
##################################################
|
|
|
|
|
|
-import urllib
|
|
|
-import urllib2
|
|
|
-import sys
|
|
|
-import json
|
|
|
import argparse
|
|
|
import re
|
|
|
+import requests
|
|
|
+
|
|
|
+try:
|
|
|
+ from urllib.parse import quote as url_quote
|
|
|
+except ImportError:
|
|
|
+ from urllib import quote as url_quote
|
|
|
|
|
|
from pygments import highlight
|
|
|
from pygments.lexers import guess_lexer, get_lexer_by_name
|
|
@@ -21,34 +23,30 @@ from pygments.formatters import TerminalFormatter
|
|
|
from pygments.util import ClassNotFound
|
|
|
|
|
|
from pyquery import PyQuery as pq
|
|
|
+from requests.exceptions import ConnectionError
|
|
|
+
|
|
|
+SEARCH_URL = 'https://www.google.com/search?q=site:stackoverflow.com%20{0}'
|
|
|
+USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17'
|
|
|
+ANSWER_HEADER = u'--- Answer {0} ---\n{1}'
|
|
|
|
|
|
-GOOGLE_SEARCH_URL = "https://www.google.com/search?q=site:stackoverflow.com%20{0}"
|
|
|
-DUCK_SEARCH_URL = "http://duckduckgo.com/html?q=site%3Astackoverflow.com%20{0}"
|
|
|
-USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17"
|
|
|
|
|
|
def get_result(url):
|
|
|
- opener = urllib2.build_opener()
|
|
|
- opener.addheaders = [('User-agent', USER_AGENT)]
|
|
|
- result = opener.open(url)
|
|
|
- return result.read()
|
|
|
+ return requests.get(url, headers={'User-Agent': USER_AGENT}).text
|
|
|
+
|
|
|
|
|
|
def is_question(link):
|
|
|
return re.search('questions/\d+/', link)
|
|
|
|
|
|
-def get_google_links(query):
|
|
|
- url = GOOGLE_SEARCH_URL.format(urllib.quote(query))
|
|
|
+
|
|
|
+def get_links(query):
|
|
|
+ url = SEARCH_URL.format(url_quote(query))
|
|
|
result = get_result(url)
|
|
|
html = pq(result)
|
|
|
return [a.attrib['href'] for a in html('.l')]
|
|
|
|
|
|
-def get_duck_links(query):
|
|
|
- url = DUCK_SEARCH_URL.format(urllib.quote(query))
|
|
|
- result = get_result(url)
|
|
|
- html = pq(result)
|
|
|
- links = [l.find('a').attrib['href'] for l in html('.links_main')]
|
|
|
|
|
|
def get_link_at_pos(links, pos):
|
|
|
- pos = int(pos) - 1
|
|
|
+ pos = pos - 1
|
|
|
for link in links:
|
|
|
if is_question(link):
|
|
|
if pos == 0:
|
|
@@ -82,15 +80,10 @@ def colorize(code, tags=[], arguments=[]):
|
|
|
)
|
|
|
|
|
|
|
|
|
-def get_instructions(args):
|
|
|
- links = get_google_links(args['query'])
|
|
|
- if not links:
|
|
|
- return ''
|
|
|
-
|
|
|
+def get_answer(args, links):
|
|
|
link = get_link_at_pos(links, args['pos'])
|
|
|
if args.get('link'):
|
|
|
return link
|
|
|
-
|
|
|
link = link + '?answertab=votes'
|
|
|
page = get_result(link)
|
|
|
html = pq(page)
|
|
@@ -101,29 +94,49 @@ def get_instructions(args):
|
|
|
if args['all'] or not instructions:
|
|
|
text = first_answer.find('.post-text').eq(0).text()
|
|
|
else:
|
|
|
- text = colorize(instructions.eq(0).text(),
|
|
|
- tags=[t.text for t in html('.post-tag')],
|
|
|
- arguments=args['query'].split())
|
|
|
+ text = instructions.eq(0).text()
|
|
|
+ return text
|
|
|
+
|
|
|
|
|
|
- if not text:
|
|
|
+def get_instructions(args):
|
|
|
+ links = get_links(args['query'])
|
|
|
+ if not links:
|
|
|
return ''
|
|
|
- return text
|
|
|
+ answers = []
|
|
|
+ append_header = args['num_answers'] > 1
|
|
|
+ initial_position = args['pos']
|
|
|
+ for answer_number in range(args['num_answers']):
|
|
|
+ current_position = answer_number + initial_position
|
|
|
+ args['pos'] = current_position
|
|
|
+ answer = get_answer(args, links)
|
|
|
+ if not answer:
|
|
|
+ continue
|
|
|
+ if append_header:
|
|
|
+ answer = ANSWER_HEADER.format(current_position, answer)
|
|
|
+ answer = answer + '\n'
|
|
|
+ answers.append(answer)
|
|
|
+ return u'\n'.join(answers)
|
|
|
+
|
|
|
|
|
|
def howdoi(args):
|
|
|
args['query'] = ' '.join(args['query']).replace('?', '')
|
|
|
- instructions = get_instructions(args) or 'Sorry, couldn\'t find any help with that topic'
|
|
|
+ try:
|
|
|
+ instructions = get_instructions(args) or 'Sorry, couldn\'t find any help with that topic\n'
|
|
|
+ print(instructions)
|
|
|
+ except ConnectionError:
|
|
|
+ print('Failed to establish network connection\n')
|
|
|
|
|
|
- print instructions
|
|
|
|
|
|
def command_line_runner():
|
|
|
parser = argparse.ArgumentParser(description='code search tool')
|
|
|
- parser.add_argument('query', metavar='QUERY', type=str, nargs=argparse.REMAINDER,
|
|
|
+ parser.add_argument('query', metavar='QUERY', type=str, nargs='+',
|
|
|
help='the question to answer')
|
|
|
- parser.add_argument('-p','--pos', help='select answer in specified position (default: 1)', default=1)
|
|
|
+ parser.add_argument('-p','--pos', help='select answer in specified position (default: 1)', default=1, type=int)
|
|
|
parser.add_argument('-a','--all', help='display the full text of the answer',
|
|
|
action='store_true')
|
|
|
parser.add_argument('-l','--link', help='display only the answer link',
|
|
|
action='store_true')
|
|
|
+ parser.add_argument('-n','--num-answers', help='number of answers to return', default=1, type=int)
|
|
|
args = vars(parser.parse_args())
|
|
|
howdoi(args)
|
|
|
|