You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

urllib2.urlopen请求IMDB影片演职人员页面返回空内容的问题求助

urllib2.urlopen请求IMDB影片演职人员页面返回空内容的问题求助

问题描述

我之前用urllib2读取IMDB页面一直正常,但最近请求影片演职人员页面时,urllib2.urlopen返回的响应是空的——没有报错,但逐行读取时循环执行0次。不过在浏览器里打开该页面完全正常,甚至在开发者工具里能看到“刚开始返回空白,等待后才出现完整源码”的现象。

我的测试代码如下:

import urllib2
# 注意:原代码遗漏了ssl模块导入,会导致隐性错误
import ssl

def openConnection(URL):
    try:
        req = urllib2.Request(URL, headers={'User-Agent' : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"})
        context = ssl._create_unverified_context()
        con = urllib2.urlopen( req, context=context )
        # 测试用的逐行打印
        for line in con:
            print line
        return con
    except:
        # 宽泛的异常捕获吞掉了真实错误信息
        print "Connection failed. Retrying."

def readIMDB(movie):
    data = openConnection("https://www.imdb.com/title/" + movie + "/fullcredits")

readIMDB("tt0084726")

其他URL传入openConnection都能正常逐行打印内容,但IMDB的这个演职人员页面就是不行。想请教:为什么会出现这种情况?有没有办法修改代码拿到数据?


问题根源分析

结合IMDB的页面机制和urllib2的局限性,主要有这几个核心原因:

  1. 动态内容渲染(最可能)
    IMDB的演职人员页面现在大量内容是通过JavaScript动态加载的。你在浏览器里看到“等待后才出现源码”的现象,本质是浏览器在执行页面中的JS脚本,动态拉取并渲染实际的演职人员数据。

urllib2只是纯HTTP请求工具,它只能获取服务器返回的初始静态响应,不会执行任何JavaScript代码。如果IMDB返回的初始响应里只有页面框架(没有实际的演职人员HTML),urllib2自然读不到有效内容,看起来就像返回了空。

  1. 响应压缩未处理
    IMDB服务器通常会返回gzip压缩后的响应来节省带宽。urllib2默认不会自动解压gzip内容,此时直接逐行读取响应时,因为压缩数据的二进制格式没有换行符,会导致for line in con循环执行0次(没有可识别的“行”)。

  2. 隐性错误被吞掉
    你的代码里except块太宽泛,没有捕获并打印具体异常信息——比如可能存在SSL验证的隐性问题、请求被IMDB反爬机制拦截(虽然加了UA,但可能还有其他检测),但这些错误被笼统的except覆盖了,你看不到真实问题。


解决方案

针对不同原因,给出对应的修复方案:

方案1:先处理响应压缩(快速验证)

先尝试解决压缩问题,这是最容易验证的:

import urllib2
import ssl
import gzip
from StringIO import StringIO  # Python 2.x用这个,Python3请用io.BytesIO

def openConnection(URL):
    try:
        req = urllib2.Request(URL, headers={
            'User-Agent' : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
            'Accept-Encoding': 'gzip, deflate'  # 明确告诉服务器我们接受压缩响应
        })
        context = ssl._create_unverified_context()
        con = urllib2.urlopen(req, context=context)
        
        # 检查并解压gzip响应
        content_encoding = con.info().get('Content-Encoding')
        if content_encoding == 'gzip':
            buf = StringIO(con.read())
            f = gzip.GzipFile(fileobj=buf)
            content = f.read()
            print(content)
            return content
        else:
            # 正常逐行读取
            for line in con:
                print line
            return con
    except Exception as e:
        # 打印具体错误信息,方便排查
        print "Connection failed. Error: {} - {}".format(type(e).__name__, str(e))

如果修改后能看到内容,说明是压缩问题;如果还是空,那大概率是动态渲染的问题。

方案2:用支持JS渲染的工具(解决动态内容问题)

如果是动态渲染导致的,urllib2这类纯HTTP工具就不够用了,需要用能模拟浏览器执行JS的工具,比如selenium

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def readIMDB(movie):
    # 配置无头浏览器(不弹出可视化窗口)
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36")
    
    driver = webdriver.Chrome(options=chrome_options)
    try:
        url = "https://www.imdb.com/title/" + movie + "/fullcredits"
        driver.get(url)
        # 等待页面动态内容加载完成(隐式等待10秒)
        driver.implicitly_wait(10)
        # 获取和浏览器一致的完整页面源码
        page_source = driver.page_source
        print(page_source)
        return page_source
    finally:
        # 确保浏览器进程关闭
        driver.quit()

readIMDB("tt0084726")

selenium会模拟真实浏览器的行为,执行页面中的JS,所以能拿到和浏览器里一样的完整内容。

方案3:优化错误捕获,排查隐性问题

修改except块,打印具体异常信息,快速定位是否有反爬或SSL问题:

except Exception as e:
    print "Connection failed. Error type: {}, Message: {}".format(type(e).__name__, str(e))

比如如果IMDB返回了403 Forbidden,你就能看到对应的错误,这时候可能需要添加更多请求头(比如AcceptReferer),或者使用代理、添加Cookie来绕过反爬。


额外提醒

IMDB有官方API,如果你是合法的爬取需求,建议优先使用官方API,这样更稳定,也不会触发反爬机制。不过官方API可能需要申请密钥,部分功能可能收费,但比自己爬取页面更可靠。

火山引擎 最新活动