-
Notifications
You must be signed in to change notification settings - Fork 0
/
hn.py
96 lines (75 loc) · 2.77 KB
/
hn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python
"""Hacker News CLI app
Uses the Hacker News REST API provided by Firebase to return the top N stories
currently posted to Hacker News
Tested with Python 3.7
"""
__version__ = '0.1'
import argparse
import sys
import time
import requests
API_BASE_URL = 'https://hacker-news.firebaseio.com/v0/'
def main():
args = get_args()
# get a list of top story IDs
try:
story_ids = get_resource('topstories.json')
except requests.exceptions.RequestException as exc:
sys.exit(exc)
print('Top {} stories on Hacker News\n'.format(args.n))
stories = get_stories(story_ids)
# print a list of N top stories by rank in descending order
position = 0
for rank in sorted(stories.keys(), reverse=True)[:args.n]:
story = stories[rank]
position += 1
print("{}. {}".format(position, story.get('title', '')))
print(" posted by {} ({} points) - {} comments (rank={:1.2f})"
.format(story.get('by', ''), story.get('score', ''),
story.get('descendants', 0), rank))
def get_args():
"""Parse command line arguments and return an object holding attributes"""
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument('-n', required=True, type=int,
help='number of top stories to retrieve')
parser.add_argument('--version', action='version', version=__version__)
return parser.parse_args()
def get_rank(story, current_time):
"""Return rank of a given story at a point in time"""
try:
factor = 1.0 if story['url'] else 0.4
except KeyError:
factor = 0.4
age = (current_time - story['time']) / 3600 # hours
return factor * ((story['score'] - 1) ** 0.8) / ((age + 2) ** 1.8)
def get_resource(suffix, session=None):
"""Return a Python object for Firebase URL response"""
url = API_BASE_URL + suffix
if session:
response = session.get(url)
else:
response = requests.get(url)
response.raise_for_status()
return response.json()
def get_stories(story_ids):
"""Return a dictionary of ranked stories given a list of story IDs"""
current_time = int(time.time())
stories = {}
session = requests.Session()
# construct a dict of stories as values and their ranks as keys
for story_id in story_ids:
try:
story = get_resource('item/{}.json'.format(story_id), session)
except requests.exceptions.RequestException:
continue
# skip dead or deleted stories
if story == {} or story.get('deleted') is True:
continue
stories[get_rank(story, current_time)] = story
return stories
if __name__ == '__main__':
main()