如何用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
相关产品推荐
相关产品推荐

