API اخبار هکرها

برای بررسی نحوه‌ی استفاده از فراخوانی APIها در سایت‌های دیگر بیایید نگاهی سریع به سایت Hacker News (http://news.ycombinator.com/) بندازیم. در این سایت افراد مقاله‌هایی درباره‌ی برنامه‌نویسی و فنّآوری به اشتراک می‌گذارند و در بحث‌های زنده پیرامون این مقاله‌ها شرکت می‌کنند. API این سایت دسترسی به داده‌های تمام مطالب ثبت‌شده و نظرات سایت را فراهم می‌آورد و می‌توانید از آن بدون نیاز به ثبت‌نام برای دریافت کلید استفاده کنید.

فراخوانی زیر اطّلاعاتی درباره‌ی بالاترین مقاله‌ی فعلی در زمان نگارش این کتاب برمی‌گرداند:

https://hacker-news.firebaseio.com/v0/item/19155826.json

اگر این URL را در مرورگری وارد کنید متنی داخل آکلاد خواهید دید که نشان می‌دهد این یک دیکشنری است. امّا بررسی این پاسخ بدون شکل‌دهی مناسب به آن کاری مشکل است. بیایید این URL را از طریق متد json.dump() فرابخوانیم همانند آنچه در فصل ۱۶ کردیم، تا ببینیم چه اطّلاعاتی درباره‌ی یک مقاله برگردانده می‌شود:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import requests
import json

# Make an API call, and store the response.
url = 'https://hacker-news.firebaseio.com/v0/item/19155826.json'
r = requests.get(url)
print(f"Status code: {r.status_code}")

# Explore the structure of the data.
response_dict = r.json()
readable_file = 'data/readable_hn_data.json'
with open(readable_file, 'w') as f:
    json.dump(response_dict, f, indent=4)

همه چیز در این برنامه آشنا به نظر می‌آید زیرا آن را در سراسر دو فصل قبل استفاده کرده‌ایم. خروجی یک دیکشنری درباره‌ی اطّلاعات مقاله به شماره‌ی ۱۹۱۵۵۸۲۶ است:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "by": "jimktrains2",
  "descendants": 220,
  "id": 19155826,
  "kids": [
    19156572,
    19158857,
    --snip--
  ],
  "score": 722,
  "time": 1550085414,
  "title": "Nasa's Mars Rover Opportunity Concludes a 15-Year Mission",
  "type": "story",
  "url": "https://www.nytimes.com/.../mars-opportunity-rover-dead.html"
}

این دیکشنری شامل تعدادی کلید است که می‌توان با آن کار کرد. کلید descendants (فرزندان) تعداد نظراتی را نشان می‌دهد که مقاله دریافت کرده است. کلید kids (کودکان) شماره‌ی تمام نظراتی را در برمی‌گیرد که به طور مستقیم برای این مقاله ارسال شده است. این نظرات ممکن است خود نظرات دیگری را هم شامل شوند در نتیجه تعداد فرزندان معمولاً بیشتر از تعداد کودکان است. عنوان مقاله‌ی مورد بحث را می‌توان دید و URL‌ای برای مقاله هم در دسترس است.

URL زیر لیست ساده‌ای از شماره‌ی تمام مقاله‌های برتر فعلی وب‌سایت را برمی‌گرداند:

https://hacker-news.firebaseio.com/v0/topstories.json

از این فراخوانی استفاده می‌کنیم تا مقاله‌های موجود در صفحه‌ی اصلی سایت را بیابیم و سپس دنباله‌ای از فراخوانی‌های API مشابه بالا تولید می‌کنیم. با این رویکرد می‌توانیم خلاصه‌ای از تمام مقالات موجود در صفحه‌ی اصلی سایت را بلافاصله داشته باشیم:

 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
from operator import itemgetter
import requests

# Make an API call and store the response.
url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
r = requests.get(url)  # ①
print(f"Status code: {r.status_code}")

# Process information about each submission.
submission_ids = r.json()  # ②

submission_dicts = []  # ③
for submission_id in submission_ids[:30]:
    # Make a separate API call for each submission.
    url = f"https://hacker-news.firebaseio.com/v0/item/{submission_id}.json"  # ④
    r = requests.get(url)
    print(f"id: {submission_id}\tstatus: {r.status_code}")

    response_dict = r.json()

    # Build a dictionary for each article.
    submission_dict = {  # ⑤
        'title': response_dict['title'],
        'hn_link': f"http://news.ycombinator.com/item?id={submission_id}",
        'comments': response_dict['descendants'],
    }
    submission_dicts.append(submission_dict)  # ⑥

submission_dicts = sorted(submission_dicts, key=itemgetter('comments'),  # ⑦
                          reverse=True)

for submission_dict in submission_dicts:  # ⑧
    print(f"\nTitle: {submission_dict['title']}")
    print(f"Discussion link: {submission_dict['hn_link']}")
    print(f"Comments: {submission_dict['comments']}")

ابتدا API را فراخوانی و وضعیّت پاسخ را چاپ می‌کنیم. فراخوانی API لیستی شامل شماره‌ی ۵۰۰ مقاله‌ی محبوب این سایت در زمان فراخوانی را برمی‌گرداند. سپس شیء پاسخ را به لیست پایتون تبدیل می‌کنیم و آن را در submission_ids ذخیره می‌کنیم. از این شماره‌ها برای ساختن مجموعه‌ای از دیکشنری‌ها استفاده خواهیم کرد که اطّلاعات هر کدام از مقاله‌های فعلی را ذخیره می‌کنند.

لیستی خالی به نام submission_dicts می‌سازیم تا دیکشنری‌ها را نگه داریم. سپس روی شماره‌ی ۳۰ مقاله‌ی برتر حلقه می‌زنیم. با تولید یک URL که شامل مقدار فعلی submission_id است، برای هر مقاله یک فراخوانی API انجام می‌دهیم. وضعیّت هر درخواست را به همراه شماره‌ی آن چاپ می‌کنیم تا مطمئن شویم که درخواست موفقیّت‌آمیز بوده یا نه.

برای هر مقاله‌ی در حال پردازش یک دیکشنری می‌سازیم که در آن عنوان، پیوندی به صفحه‌ی نظرات آن و تعداد نظراتی را که تا الان دریافت کرده ذخیره می‌کنیم. سپس هر submission_dict را به لیست submission_dicts الحاق می‌کنیم.

هر مقاله در این سایت بر اساس امتیازی کلّی رده‌بندی می‌شود که به عوامل مختلفی مثل تعداد رای‌های مثبت، تعداد نظرات دریافتی و میزان جدید بودن آن بستگی دارد. لیست دیکشنری‌ها را بر اساس تعداد نظرات آن‌ها مرتّب می‌کنیم. بر این کار از تابعی به نام itemgetter() استفاده می‌کنیم که در ماژول operator قرار دارد. کلید comments را به این تابع می‌دهیم تا مقدارهای مرتبط با آن را از هر دیکشنری داخل لیست بیرون بکشد. سپس تابع sorted() لیست را بر اساس این مقدار مرتّب می‌کند. لیست را به ترتیب معکوس مرتّب می‌کنیم تا مقالات با بیشترین نظر را اوّل بیاوریم.

به محض مرتّب شدن لیست داخل آن حلقه می‌زنیم و سه نوع اطّلاعات را درباره‌ی هر کدام چاپ می‌کنیم: عنوان، پیوندی به صفحه‌ی بحث و گفتگوی آن و تعداد نظراتی که در حال حاضر برای مقاله وجود دارد:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Status code: 200
id: 19155826   status: 200
id: 19180181   status: 200
id: 19181473   status: 200
--snip--

Title: Nasa's Mars Rover Opportunity Concludes a 15-Year Mission
Discussion link: http://news.ycombinator.com/item?id=19155826
Comments: 220

Title: Ask HN: Is it practical to create a software-controlled model rocket?
Discussion link: http://news.ycombinator.com/item?id=19180181
Comments: 72

Title: Making My Own USB Keyboard from Scratch
Discussion link: http://news.ycombinator.com/item?id=19181473
Comments: 62

--snip--

شما می‌توانید فرآیندی مشابه را برای دسترسی و تحلیل اطّلاعات هر API پی بگیرید. با این داده‌ها می‌توانید نموداری تولید کنید که نشان دهد اخیراً کدام مقاله‌ها بیشترین بحث‌های فعّال را برانگیخته‌اند. این همچنین پایه‌ی برنامه‌هایی است که تجربه‌ی مطالعه‌ی شخصی را برای سایت‌های اینچنینی فراهم می‌آورند. برای اطّلاع یافتن از انواع اطّلاعاتی که از طریق این API می‌توانید دریافت کنید به صفحه‌ی مستندات آن در https://github.com/HackerNews/API/ مراجعه کنید.