A serverless FastAPI-based web scraper for MyDramaList.com, designed for deployment on Vercel.
Note: This project is inspired from @tbdsux/kuryana. Special thanks to @tbdsux!
- 11 Endpoints — Search, details, cast, episodes (list / single / enriched-all), reviews, recommendations, people, seasonal, lists, user watchlists
- Episode Deep Scraping — Visits each
/episode/{n}page to extract description, cover image, rating, and season - Concurrent Fetching —
episodes/allbatches requests (4 at a time) with anti-ban delays - Serverless Ready — Optimized for Vercel deployment
- Rate Limiting — Built-in 1 s delay per endpoint call; 0.5 s pause between episode batches
- Error Handling — Consistent JSON error responses with proper HTTP status codes
- Modular Design — Separate
scraper.pyfor all scraping logic
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/search/q/{query} |
Search dramas by title. Returns up to 20 results. |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/id/{slug} |
Full drama details — title, synopsis, genres, cast, rating, etc. |
| GET | /api/id/{slug}/cast |
Cast & crew grouped by role |
| GET | /api/id/{slug}/reviews |
User reviews (up to 10) |
| GET | /api/id/{slug}/recs |
Drama recommendations with reasons and votes |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/id/{slug}/episodes |
Episode list — number, title, air date |
| GET | /api/id/{slug}/episodes/{n} |
Single episode — title, description, cover image, air date, rating, season |
| GET | /api/id/{slug}/episodes/all |
All episodes enriched — concurrently fetches every episode page for full details |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/people/{people_id} |
Person details — biography, filmography, personal info |
| GET | /api/seasonal/{year}/{quarter} |
Top dramas for a season (quarter: 1=Winter 2=Spring 3=Summer 4=Fall) |
| GET | /api/list/{id} |
Items in a user-created public list |
| GET | /api/dramalist/{user_id} |
A user's public watchlist |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health |
Health check |
Slug format:
{id}-{drama-name}— e.g.,58651-run-on,746993-my-demon
{
"episode_number": "1",
"url": "https://mydramalist.com/58651-run-on/episode/1",
"title": "Run On Episode 1",
"image": "https://i.mydramalist.com/pRvkV_3m.jpg",
"description": "Ki Seon Gyeom notices bruises on Kim Woo Shik's body. Trying to get back into her professor's good graces, Oh Mi Joo takes on an interpreting gig. (Source: Netflix)",
"air_date": "December 16, 2020",
"rating": "8.5/10",
"season": "1"
}{
"episodes": [
{
"episode_number": "1",
"title": "Run On Episode 1",
"air_date": "Dec 16, 2020",
"description": "Ki Seon Gyeom notices bruises on Kim Woo Shik's body...",
"image": "https://i.mydramalist.com/pRvkV_3m.jpg",
"rating": "8.5/10",
"season": "1"
}
],
"total": 16
}{
"episodes": [
{ "episode_number": "1", "title": "Run On Episode 1", "air_date": "Dec 16, 2020" },
{ "episode_number": "2", "title": "Run On Episode 2", "air_date": "Dec 17, 2020" }
],
"total": 16
}{
"results": [
{
"title": "Squid Game",
"slug": "40257-round-six",
"year": "2021",
"image": "https://i.mydramalist.com/X6vkX_4s.jpg",
"rating": "8.4",
"url": "https://mydramalist.com/40257-round-six"
}
],
"total": 20
}{
"recommendations": [
{
"title": "My Secret Romance",
"year": "2017",
"slug": "21465-my-secret-romance",
"url": "https://mydramalist.com/21465-my-secret-romance",
"image": "https://i.mydramalist.com/...",
"rating": "7.3",
"reasons": ["Both have office romance", "Similar chemistry between leads"],
"recommended_by": "username",
"votes": "42"
}
],
"total": 25,
"pages_fetched": 1
}{
"code": 404,
"error": true,
"description": "404 Not Found"
}| Tool | Purpose |
|---|---|
| Python 3.12 | Primary language |
| FastAPI | Web framework + auto /docs |
| BeautifulSoup4 | HTML parsing |
| curl_cffi | Anti-bot HTTP requests (browser impersonation) |
| Uvicorn | ASGI server |
project_root/
├── main.py # FastAPI routes
├── scraper.py # All scraping logic
├── requirements.txt # Dependencies
├── vercel.json # Vercel serverless config
├── static/
│ └── index.html # Interactive API docs UI
└── README.md
-
Clone and setup:
git clone https://github.com/B1PL0B/MyDramaList-Unofficial-API.git cd MyDramaList-Unofficial-API -
Install dependencies:
pip install -r requirements.txt
-
Run development server:
python -m uvicorn main:app --reload --port 9000
-
Access:
- Custom UI Docs: http://localhost:9000
- Swagger UI: http://localhost:9000/docs
- ReDoc: http://localhost:9000/redoc
- Health Check: http://localhost:9000/api/health
# 1. Install Vercel CLI
npm i -g vercel
# 2. Deploy
vercel --prodOr use the one-click button at the top of this README.
/episodes/{n}— makes 1 extra HTTP request per call (the episode detail page)/episodes/all— makes N extra requests (one per episode), batched 4 at a time with 0.5 s delays. Expect ~5–15 s for a 16-episode drama.
| Limit | Value |
|---|---|
| Max execution time | 10 s |
| Function size | 15 MB |
| Cold starts | Possible on first request |
⚠️ /episodes/allmay time out on Vercel's free tier for long dramas. Consider deploying your own instance or using individual/episodes/{n}calls instead.
- 1 s delay on every endpoint entry
- 0.5 s pause between episode batch groups
| Code | Meaning |
|---|---|
| 400 | Invalid parameters or private resource |
| 404 | Resource not found |
| 500 | Server-side scraping error |
Educational use only. Please respect MyDramaList.com's terms of service.
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request