-
-
Save jakejarvis/d1698cc0f930df141e050ce4568b6a46 to your computer and use it in GitHub Desktop.
Fizzbuzz via answers.com
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' we're solving fizzbuzz with a little help from the web ''' | |
from html.parser import HTMLParser | |
from urllib.request import Request, urlopen | |
import re | |
import time | |
base_url = 'https://www.answers.com/Q/' | |
tag_name = 'div' | |
class_name = 'answer-body' | |
delimiter = '_' | |
class SearchParser(HTMLParser): | |
''' Parses search results from the web ''' | |
def __init__(self): | |
HTMLParser.__init__(self) | |
# track if the data we're encountering is part of an answer. we have | |
# to do this because there can be nested tags inside the answer tag | |
self.in_answer = False | |
# keep track of nested tags | |
self.tag_stack = [] | |
# a list of all the answers found | |
self.answers = [] | |
# words that indicate whether the answer is yes or no | |
self.positive_signs = [ | |
'yes', | |
'exactly', | |
'is divisible', | |
] | |
self.negative_signs = [ | |
'no', | |
'not', | |
'decimal', | |
] | |
def handle_starttag(self, tag, attrs): | |
''' identify the tag that we expect to contain the answer ''' | |
if tag == tag_name: | |
for attr in attrs: | |
if attr[0] == 'class' and class_name in attr[1]: | |
self.in_answer = True | |
self.answers.append('') | |
break | |
if self.in_answer: | |
self.tag_stack.append(tag) | |
def handle_endtag(self, tag): | |
''' behavior on encountering a close tag ''' | |
self.tag_stack = self.tag_stack[:-1] | |
# if the stack is empty, we're done with that answer | |
if self.in_answer and self.tag_stack == []: | |
self.in_answer = False | |
def handle_data(self, data): | |
''' extract the answer, if we're in an answer tag ''' | |
if self.in_answer: | |
self.answers[-1] += data | |
def conclude_yes_no(self): | |
''' looks through all the answer to conclude either true or false ''' | |
results = 0 | |
for answer in self.answers: | |
answer = answer.lower().strip() | |
results += self.score_answer(answer) | |
return results > 0 | |
def score_answer(self, answer): | |
''' evaluates an answer to determine if it's a yes or a no ''' | |
score = 0 | |
positive_signs = re.findall( | |
r'\b%s\b' % r'\b|\b'.join(self.positive_signs), | |
answer, | |
) | |
score += len(positive_signs) | |
negative_signs = re.findall( | |
r'\b%s\b' % r'\b|\b'.join(self.negative_signs), | |
answer | |
) | |
score -= len(negative_signs) | |
return score | |
def query_search_engine(numerator, denominator): | |
''' ask a search engine if these numbers are divisible ''' | |
question = 'is %d divisible by %d' % (numerator, denominator) | |
question = question.replace(' ', delimiter) | |
url = '%s%s' % (base_url, question) | |
request = Request(url) | |
request.add_header( | |
'User-Agent', | |
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) ' \ | |
'Gecko/20100101 Firefox/72.0') | |
response = urlopen(request) | |
# politeness -- wait a few seconds before the next query | |
time.sleep(3) | |
if url != response.url: | |
return False | |
text = response.read().decode('unicode-escape') | |
parser = SearchParser() | |
parser.feed(text) | |
return parser.conclude_yes_no() | |
if __name__ == '__main__': | |
divisors = [(3, 'fizz'), (5, 'buzz')] | |
for i in range(1, 101): | |
output = '' | |
for d in divisors: | |
if query_search_engine(i, d[0]): | |
output += d[1] | |
output = output or i | |
print(output) | |
# cool |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment