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])
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
Things that bite once you go beyond a quick script:
-
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 fromhttps://itunes.apple.com/lookup?id=<id>&entity=podcastEpisode, but that endpoint returns at most 200 recent episodes, not the full archive. -
trackCountand 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. -
pubDateformats vary between hosts (+0000vsGMT, and some feeds use other variants). Parse withemail.utils.parsedate_to_datetimeand normalise to UTC before comparing. Also send a browser-likeUser-Agent: some hosts reject the defaultpython-requestsone.
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])
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
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)