• בלוג
  • בואו נמצא פודקסטים מעניינים עם פייתון

בואו נמצא פודקסטים מעניינים עם פייתון

08/09/2019

במכונית, בסופר או כשעושים כלים, כולם אוהבים לשמוע פודקסטים. מתוך סקרנות ובשביל למצוא פודקסטים מעניינים בעברית הגעתי לאתר המעולה podcastim.org.il ומצאתי שם רשימה אין סופית כמעט של פודקסטים בעברית. יש להם שם גם תיבה של חיפוש אבל מה שאותי הכי עניין זה למצוא פודקסטים שעדיין מפרסמים פרקים חדשים, רצוי כל שבוע.

אין עדיין רשימה כזאת מוכנה בפודקסטים אבל עם פייתון וקצת רצון טוב אפשר למצוא אותה בקלות.

1. התקנת הכלים

בכל דף פודקסט באתר יש רשימה של פרקים שהוקלטו, ובדף הראשי רשימה של כל הפודקסטים. עם הספריה aiohttp אוכל בקלות להוציא בקשות http ועם beautifulsoup4 נקרא את ה HTML-ים ונשלוף מהם את המידע שצריך. בצד ההשלמות beautifulsoup עובדת טוב יותר עם ספריית lxml והספריה asyncio_throttle שומרת שלא נעמיס על האתר עם יותר מדי בקשות במקביל. סך הכל שורת ההתקנה:

$ pip install aiohttp[speedups] beautifulsoup4 lxml asyncio_throttle

2. איך יודעים אם פודקסט העלה פרק בשבועיים האחרונים

בכל דף פודקסט באתר יש רשימה של פרקים שהפודקסט פירסם. הפקודה fetch של aiohttp מביאה תוכן של עמוד אינטרנט, הפקודה select של beautifulsoup שולפת מידע מהדף ויחד הקוד הבא נכנס לדף פודקסט, מוציא את התאריך בו התפרסם הפרק האחרון ומדפיס אותו רק אם הפרק האחרון פורסם בשבועיים האחרונים:

async def check_podcast(session, podcast_url, podcast_name):
    html = await fetch(session, podcast_url)
    soup = BeautifulSoup(html, 'lxml')
    dates = soup.select('.episode-list__entry .pod-entry__date')
    if len(dates) > 0:
        last_episode_date = datetime.datetime.strptime(dates[0].get_text(), '%b %d, %Y')

        if (datetime.datetime.now() - last_episode_date).days < 14:
            print(podcast_name, podcast_url)

3. רשימת כל הפודקסטים

באותו האופן אפשר לקחת את הדף הראשי ולמשוך ממנו את רשימת כל הפודקסטים:

html = await fetch(session, 'https://podcastim.org.il/')
soup = BeautifulSoup(html, 'lxml')
titles = soup.select('.pt-cv-title a')

ואולי החלק הכי מורכב בתוכנית היא הלולאה הבאה שמפעילה את check_podcast במקביל על כל רשימת הפודקסטים, וסומכת על asyncio_throttler כדי לא להעמיס על האתר:

await asyncio.wait([check_podcast(session, link.get('href'), link.get_text()) for link in titles])

הפקודה asyncio.wait מקבלת רשימה של דברים שאפשר לחכות להם ומאחדת אותם ל"משימה" אחת. הפקודה await ממתינה לביצוע משימה זו והפונקציה check_podcast היא שיוצרת את המשימה. ה for מתחבא בסוף השורה והוא שמציין שאנחנו בלולאה, לולאה מסוג List Comprehension.

בקיצור הנה התוכנית אליה הגעתי בסוף שתדפיס לכם רשימה של כל הפודקסטים שפירסמו פרק חדש בשבועיים האחרונים:

import aiohttp
import asyncio
from bs4 import BeautifulSoup
import pdb
from asyncio_throttle import Throttler
import datetime


async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def check_podcast(session, podcast_url, podcast_name):
    html = await fetch(session, podcast_url)
    soup = BeautifulSoup(html, 'lxml')
    dates = soup.select('.episode-list__entry .pod-entry__date')
    if len(dates) > 0:
        last_episode_date = datetime.datetime.strptime(dates[0].get_text(), '%b %d, %Y')

        if (datetime.datetime.now() - last_episode_date).days < 14:
            print(podcast_name, podcast_url)

throttler = Throttler(rate_limit=30, period=60)

async def main():
    async with throttler:
        async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False)) as session:
            html = await fetch(session, 'https://podcastim.org.il/')
            soup = BeautifulSoup(html, 'lxml')
            titles = soup.select('.pt-cv-title a')
            await asyncio.wait([check_podcast(session, link.get('href'), link.get_text()) for link in titles])

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

האזנה נעימה.