DEV Community

Hải Hà Phan Thanh
Hải Hà Phan Thanh

Posted on

Find podcasts and their latest episodes with Python (iTunes Search API + RSS, no API key)

Podcast guest outreach, sponsorship research, and "new episode" alerts all need the same two things: a list of shows on a topic, and the newest episodes of each. Apple gives you both for free:

  • The iTunes Search API finds shows by keyword and returns each show's RSS feedUrl.
  • The show's RSS feed lists episodes with title, date and audio URL.

Neither needs an API key.

DIY: search, then read the feeds

# pip install requests
import requests
import xml.etree.ElementTree as ET

def search(term, n=3, country="us"):
    r = requests.get("https://itunes.apple.com/search",
                     params={"term": term, "media": "podcast", "limit": n, "country": country}, timeout=20)
    return [{"id": p["collectionId"], "title": p["collectionName"], "author": p["artistName"],
             "feedUrl": p.get("feedUrl"), "episodes": p.get("trackCount")} for p in r.json()["results"]]

def episodes(feed_url, n=3):
    xml = requests.get(feed_url, headers={"User-Agent": "Mozilla/5.0"}, timeout=30).content
    items = ET.fromstring(xml).find("channel").findall("item")[:n]
    out = []
    for it in items:
        enc = it.find("enclosure")
        out.append({"title": it.findtext("title"), "published": it.findtext("pubDate"),
                    "audio": enc.get("url") if enc is not None else None})
    return out

for p in search("machine learning", n=3):
    print(p)
    if not p["feedUrl"]:  # some listings have no public RSS feed
        continue
    for ep in episodes(p["feedUrl"], n=2):
        print("   ", ep["published"], "|", ep["title"][:70])
Enter fullscreen mode Exit fullscreen mode

Output (29/10/2026):

{'id': 1204521130, 'title': 'Machine Learning Guide', 'author': 'OCDevel', 'feedUrl': 'https://rss.pdrl.fm/179284/feeds.libsyn.com/100505/rss/?redirect=false', 'episodes': 60}
    Thu, 26 Feb 2026 04:55:00 +0000 | MLA 030 AI and Programming Jobs: What Happened and How to Position
    Sun, 22 Feb 2026 19:09:00 +0000 | MLA 029 OpenClaw and Personal Agents
{'id': 384233048, 'title': 'Machine Learning', 'author': 'Andrew Ng', 'feedUrl': None, 'episodes': 20}
{'id': 1529676568, 'title': 'Machine Learning Simplified', 'author': 'Priyanka Sharma', 'feedUrl': 'https://anchor.fm/s/327aebf8/podcast/rss', 'episodes': 20}
    Sat, 29 May 2021 11:13:39 GMT | Collaboration
    Sat, 12 Sep 2020 02:41:22 GMT | Predictive Modeling and Predictive Analysis in Machine Learning
Enter fullscreen mode Exit fullscreen mode

Things that bite once you go beyond a quick script:

  1. Some listings have no feedUrl. Andrew Ng's "Machine Learning" above is an old iTunes U style listing with no public RSS. You can still get its episodes from https://itunes.apple.com/lookup?id=<id>&entity=podcastEpisode, but that endpoint returns at most 200 recent episodes, not the full archive.
  2. trackCount and recency lie together. A show with 60 episodes can be dormant: "Machine Learning Guide" last published in February, and "Machine Learning Simplified" in 2021. Search ranks by relevance, not activity, so filter on the newest episode date if you want shows that are still running.
  3. pubDate formats vary between hosts (+0000 vs GMT, and some feeds use other variants). Parse with email.utils.parsedate_to_datetime and normalise to UTC before comparing. Also send a browser-like User-Agent: some hosts reject the default python-requests one.

Many shows, top charts, date filter: the actor

I built the Podcast Scraper actor to do the above for lists. It takes search terms, Apple IDs or URLs, raw RSS feeds, and Apple top charts by country and genre. It outputs one podcast record per show, plus episode records with normalised UTC dates and durations in seconds. It falls back to the iTunes lookup when a show has no feed.

# pip install apify-client
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("bachiembmt/podcast-scraper-apple-itunes-rss").call(run_input={
    "searchTerms": ["machine learning"],
    "charts": {"countries": ["us"], "genre": "Technology", "limit": 3},
    "maxPodcastsPerSource": 3,
    "includeEpisodes": True,
    "maxEpisodesPerPodcast": 2,
    "episodesSince": "2026-09-01",
})
for item in client.dataset(run.default_dataset_id).iterate_items():
    if item["type"] == "podcast":
        print(item["title"], "|", item["genres"], "| last:", item["lastReleaseAt"], "| rank:", item["chartRank"])
    else:
        print("   ", item["publishedAt"][:10], item["durationSec"] // 60, "min |", item["title"][:60])
Enter fullscreen mode Exit fullscreen mode

Output of that run (about 6 seconds):

Machine Learning Guide | ['Technology', 'Education', 'Courses'] | last: 2026-02-26T04:55:00Z | rank: None
Machine Learning | ['Technology'] | last: 2008-07-23T19:12:00Z | rank: None
Machine Learning Simplified | ['Education'] | last: 2021-05-29T11:13:00Z | rank: None
The Builders | ['Society & Culture', 'Technology'] | last: 2026-10-27T07:01:00Z | rank: 6
    2026-10-27 40 min | Dario & Daniela Amodei: "This Is Gonna Determine the Fate of
    2026-10-23 50 min | After The Builders: On Musk and Thiel
Machine Gods | ['Technology'] | last: 2026-10-28T11:00:00Z | rank: 27
    2026-10-28 53 min | Inside Anthropic’s IPO + How AI Agents Spy on Your Messages
    2026-10-23 52 min | Fired OpenAI Safety Researchers Speak Out + We Look Inside P
Tomorrow, Today | ['Technology', 'News', 'Tech News'] | last: 2026-10-24T16:58:00Z | rank: 32
    2026-10-27 81 min | Leadership Beyond Strategy With Pilar Mendiola Fernandez | S
    2026-10-24 104 min | The 10 Challenges That Will Shape Our Future with Jorge Brow
Enter fullscreen mode Exit fullscreen mode

The episodesSince filter is why the three dormant search results have no episodes. The chart shows are the top 3 Technology podcasts inside the overall US top 100, so chartRank is their overall position (6, 27, 32). Podcast records also carry the website, artwork, Apple URL, and the owner name and email that the show publishes in its own feed.

Pricing is $3 per 1,000 podcasts plus $0.50 per 1,000 episodes, with no subscription.

When to use which

  • A few shows in a notebook: the DIY script is enough.
  • Lists of keywords, charts across countries, or a scheduled "new episodes since last run" job: use the actor, or extend the script with date parsing, the lookup fallback, chart filtering and retries.

Disclosure: I built and maintain the actor. It reads Apple's public search API and the shows' own public RSS feeds.

Top comments (0)