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

如何用Python从IMDb爬取剧集信息?现有代码提取失败求排查

IMDb剧集信息爬取问题排查

问题描述

我正在为大学研究爬取剧集相关信息,已从IMDb Top250剧集页面爬取所有剧集的URL并存储在名为tvshows_url的DataFrame中,第一列为链接、第二列为标题。现在我想从每个URL中提取用户评论(User Reviews)、演员(Stars)、评分(Rating)、热度(Popularity)、类型(Genres)和年份(Year)并保存为CSV文件,但使用以下代码无法提取所需信息,请问我哪里出错了?

import requests
from bs4 import BeautifulSoup
import pandas as pd

def extract_info(url):
    response = requests.get(url)
    soup = BeautifulSoup(requests.get(url,headers={'user-agent':'some-agent'}).content,"html.parser")
    
    # Extract user reviews
    user_reviews = soup.find('span', {'class': 'rating'}).text.strip()

    # Extract stars
    stars = soup.find('a', class_="ipc-metadata-list-item__icon-link").text.strip()

    # Extract rating
    rating = soup.find('span', class_="sc-bde20123-1 cMEQkK").get('content')

    # Extract popularity
    popularity = soup.find('div', class_="sc-5f7fb5b4-1 fTREEx").text.strip()
    
    # Extract genres
    genres = soup.find('a', class_="ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link").get('content')
   
    # Extract year
    year = soup.find('a', lass="ipc-link ipc-link--baseAlt ipc-link--inherit-color").text.strip()
    
    return user_reviews, stars, rating, popularity, genres, year

# Apply the function to all url
extracted_info = tvshows_url['link'].apply(lambda x: extract_info(x))

# Create a DataFrame 
df = pd.DataFrame(extracted_info.tolist(), columns=['User_Reviews', 'Stars', 'Rating', 'Popularity', 'Genres', 'Year'])
print(df)

#Export
df.to_csv('IMDV Top Tv Shows.csv')

错误分析与修正方案

1. 冗余请求与反爬问题

  • 代码中先执行response = requests.get(url)但未使用,属于冗余操作,直接删除即可。
  • User-Agent设置为some-agent过于随意,易被IMDb反爬机制拦截,建议替换为真实浏览器标识,比如:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36。

2. 元素定位错误(核心问题)

IMDb页面类名多为动态生成,且你的定位逻辑存在偏差:

  • 用户评论:rating类并非评论数元素,正确做法是定位评论入口链接并提取数字:
    review_link = soup.find('a', href='#userReviews')
    user_reviews = review_link.text.split()[0] if review_link else 'N/A'
    
  • 演员:ipc-metadata-list-item__icon-link会匹配多个无关元素,需先定位演员列表容器再批量提取:
    stars_list = []
    stars_container = soup.find('div', {'data-testid': 'title-cast'})
    if stars_container:
        stars = stars_container.find_all('a', class_='ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link')
        stars_list = [star.text.strip() for star in stars[:5]]  # 取前5位主演
    stars = ', '.join(stars_list) if stars_list else 'N/A'
    
  • 评分:动态类名sc-bde20123-1 cMEQkK不稳定,改用属性选择器定位:
    rating_elem = soup.find('span', {'data-testid': 'rating-value'})
    rating = rating_elem.text.strip() if rating_elem else 'N/A'
    
  • 热度:同样替换动态类名为稳定的属性定位:
    popularity_elem = soup.find('div', {'data-testid': 'hero-rating-bar__popularity'})
    popularity = popularity_elem.text.strip() if popularity_elem else 'N/A'
    
  • 类型:错误使用get('content'),类型文本直接在标签内,需提取所有类型标签:
    genres_list = []
    genres_container = soup.find('div', {'data-testid': 'genres'})
    if genres_container:
        genres = genres_container.find_all('a', class_='ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link')
        genres_list = [genre.text.strip() for genre in genres]
    genres = ', '.join(genres_list) if genres_list else 'N/A'
    
  • 年份:代码存在拼写错误(lass应为class),且定位范围过广,改用专属属性定位:
    year_elem = soup.find('span', {'data-testid': 'title-year'})
    year = year_elem.text.strip().strip('()') if year_elem else 'N/A'
    

3. 缺失异常处理

爬取时易出现页面加载失败、元素找不到的情况,需添加异常捕获避免程序崩溃:
在extract_info函数中包裹try-except块,出错时返回默认值并打印错误信息。

4. 其他细节

  • CSV文件名拼写错误:IMDV应改为IMDb。
  • 批量爬取需添加延迟(如time.sleep(2)),避免触发反爬限制。

修正后的完整代码

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time

def extract_info(url):
    try:
        headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'}
        response = requests.get(url, headers=headers)
        response.raise_for_status()  # 检查请求是否成功
        soup = BeautifulSoup(response.content, "html.parser")
        
        # 提取用户评论
        review_link = soup.find('a', href='#userReviews')
        user_reviews = review_link.text.split()[0] if review_link else 'N/A'
        
        # 提取演员
        stars_list = []
        stars_container = soup.find('div', {'data-testid': 'title-cast'})
        if stars_container:
            stars = stars_container.find_all('a', class_='ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link')
            stars_list = [star.text.strip() for star in stars[:5]]
        stars = ', '.join(stars_list) if stars_list else 'N/A'
        
        # 提取评分
        rating_elem = soup.find('span', {'data-testid': 'rating-value'})
        rating = rating_elem.text.strip() if rating_elem else 'N/A'
        
        # 提取热度
        popularity_elem = soup.find('div', {'data-testid': 'hero-rating-bar__popularity'})
        popularity = popularity_elem.text.strip() if popularity_elem else 'N/A'
        
        # 提取类型
        genres_list = []
        genres_container = soup.find('div', {'data-testid': 'genres'})
        if genres_container:
            genres = genres_container.find_all('a', class_='ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link')
            genres_list = [genre.text.strip() for genre in genres]
        genres = ', '.join(genres_list) if genres_list else 'N/A'
        
        # 提取年份
        year_elem = soup.find('span', {'data-testid': 'title-year'})
        year = year_elem.text.strip().strip('()') if year_elem else 'N/A'
        
        time.sleep(2)  # 添加延迟避免反爬
        return user_reviews, stars, rating, popularity, genres, year
    except Exception as e:
        print(f"处理URL {url} 时出错: {e}")
        time.sleep(2)
        return 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'

# 应用函数到所有链接
extracted_info = tvshows_url['link'].apply(lambda x: extract_info(x))

# 创建DataFrame并合并原标题列
df = pd.DataFrame(extracted_info.tolist(), columns=['User_Reviews', 'Stars', 'Rating', 'Popularity', 'Genres', 'Year'])
df = pd.concat([tvshows_url['标题'], df], axis=1)
print(df)

# 导出CSV
df.to_csv('IMDb Top Tv Shows.csv', index=False, encoding='utf-8-sig')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 13:55:09