You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中异步加载HTML:IMDB数据爬取页面阻塞优化需求

解决IMDB爬取导致页面阻塞的异步加载方案

嘿,我之前做影视类项目时也碰到过类似的爬取延迟问题,给你几个落地性强的方案,完美匹配你“先加载页面、后补数据”的需求:


方案一:前端异步请求(最直接的快速实现)

核心思路是先返回完整页面框架,再通过JS异步拉取耗时的爬取数据,比如先渲染共同参演演员的静态内容,页面加载完成后再请求推荐影片接口。

后端步骤(Django)

  1. 写常规视图返回页面,只渲染无需爬取的基础内容:
# views.py
from django.shortcuts import render

def movie_detail(request, movie_id):
    # 先从本地数据库读取已有的共同参演演员数据
    co_actors = get_local_co_actors(movie_id)
    # 返回页面,仅渲染co_actors,推荐影片留空占位
    return render(request, 'movie_detail.html', {'co_actors': co_actors, 'movie_id': movie_id})
  1. 新增API视图专门处理推荐影片爬取:
# views.py
from django.http import JsonResponse
import requests

def get_recommended_movies(request, movie_id):
    # 这里写你的IMDB爬取逻辑(单请求耗时约0.3秒)
    recommended = crawl_imdb_recommendations(movie_id)
    return JsonResponse({'recommended': recommended})
  1. 在urls.py配置API路由:
path('movie/<int:movie_id>/recommendations/', get_recommended_movies, name='movie_recommendations'),

前端步骤(HTML/JS)

给推荐影片留占位容器,页面加载完成后用fetch拉取数据并渲染:

<!-- movie_detail.html -->
<div class="co-actors-section">
    <h3>共同参演演员</h3>
    {% for actor in co_actors %}
        <div class="actor-card">{{ actor.name }}</div>
    {% endfor %}
</div>

<div class="recommended-section">
    <h3>推荐影片</h3>
    <div id="recommended-container" class="loading-text">加载中...</div>
</div>

<script>
window.addEventListener('load', () => {
    const movieId = "{{ movie_id }}";
    fetch(`/movie/${movieId}/recommendations/`)
        .then(res => res.json())
        .then(data => {
            const container = document.getElementById('recommended-container');
            container.classList.remove('loading-text');
            container.innerHTML = '';
            // 渲染推荐影片卡片
            data.recommended.forEach(movie => {
                const card = document.createElement('div');
                card.className = 'movie-card';
                card.innerHTML = `<p>${movie.title}</p><span>评分:${movie.rating}</span>`;
                container.appendChild(card);
            });
        })
        .catch(err => {
            document.getElementById('recommended-container').textContent = '推荐影片加载失败';
        });
});
</script>

方案二:Celery + 前端轮询(适合超耗时爬取任务)

如果你的爬取任务不止单请求0.3秒(比如批量爬取),Celery确实是好选择,但需要结合前端轮询获取任务状态——毕竟Celery是后台异步执行,前端得主动“问”结果:

1. 定义Celery爬取任务

# tasks.py
from celery import shared_task
from django.core.cache import cache

@shared_task
def crawl_recommendations_task(movie_id):
    # 耗时的IMDB爬取逻辑
    recommended = crawl_imdb_recommendations(movie_id)
    # 结果存入Redis缓存,方便后续快速获取
    cache.set(f'rec_{movie_id}', recommended, timeout=3600)
    return recommended

2. 后端新增任务状态查询接口

# views.py
from celery.result import AsyncResult
from django.http import JsonResponse
from django.core.cache import cache

def check_task_status(request, task_id):
    result = AsyncResult(task_id)
    if result.ready():
        # 任务完成,从缓存取结果返回
        movie_id = result.args[0]
        data = cache.get(f'rec_{movie_id}')
        return JsonResponse({'status': 'completed', 'data': data})
    else:
        return JsonResponse({'status': 'pending'})

3. 前端流程

  • 页面加载时,后端启动Celery任务并返回任务ID
  • 前端每隔1秒轮询状态接口,直到任务完成再渲染数据

方案三:实时搜索提示的实现

对于索引页的实时输入可点击选项,核心是前端防抖+后端快速响应:

前端防抖(避免频繁请求)

<!-- index.html -->
<div class="search-box">
    <input type="text" id="search-input" placeholder="输入影片名搜索...">
    <ul id="suggestions-list" class="suggestions"></ul>
</div>

<script>
let debounceTimer;
const input = document.getElementById('search-input');
const suggestionsList = document.getElementById('suggestions-list');

input.addEventListener('input', (e) => {
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(() => {
        const query = e.target.value.trim();
        if (!query) {
            suggestionsList.innerHTML = '';
            return;
        }
        // 防抖后发起请求
        fetch(`/search-suggest/?q=${encodeURIComponent(query)}`)
            .then(res => res.json())
            .then(data => {
                suggestionsList.innerHTML = '';
                data.forEach(item => {
                    const li = document.createElement('li');
                    li.className = 'suggestion-item';
                    li.textContent = item.title;
                    li.addEventListener('click', () => {
                        window.location.href = `/movie/${item.id}/`;
                    });
                    suggestionsList.appendChild(li);
                });
            });
    }, 300); // 300毫秒防抖,减少不必要请求
});
</script>

后端优化建议

  • 把高频搜索的影片数据提前爬取并存入数据库,搜索时直接查DB,避免每次都调用IMDB接口
  • 用Django内置的Q对象做模糊查询,或者引入全文搜索工具(比如Django Haystack)提升查询速度

额外优化小技巧

  • 用aiohttp代替requests做异步爬取,在Django异步视图里并行处理多个爬取请求,能把总耗时从“N*0.3秒”压缩到接近0.3秒
  • 给IMDB爬取请求加缓存,同一影片的推荐数据1小时内不再重复爬取,大幅减少重复请求

内容的提问来源于stack exchange,提问作者user9707891

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:00:17