多相同class元素爬取IMDb剧集类型及批量处理问题求助
IMDb剧集类型爬取问题及解决方案
问题描述
我正在为大学项目进行数据爬取,需要从IMDb获取剧集的类型信息,页面中目标类型元素与开头的"Creation"元素class完全一致。使用以下代码时,爬取到的是"Creation"而非剧集类型:
url1 = 'https://m.imdb.com/title/tt0903747/?ref_=chttvtp_t_1' headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'} response1 = requests.get(url1, headers=headers) soup1 = BeautifulSoup(response1.content, 'html.parser') genres= soup1.find("a", class_="ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link").text print(genres)
尝试用soup.find_all()获取所有同class元素时,出现错误:ResultSet object has no attribute 'text'. You're probably treating a list of elements like a single element. Did you call find_all() when you meant to call find()?
此外,需要将爬取逻辑应用到以下DataFrame的所有剧集链接中,但不擅长编写for循环:
tvshows_url= pd.DataFrame( [ { 'link':f'https://www.imdb.com{link.get("href")}', 'title': link.text.split('. ')[-1] } for link in soup.select('a[href^="/title"]:has(h3)') ] ) print(tvshows_url)
解决方案
一、类型爬取错误的修复
find()方法的问题find()仅返回匹配到的第一个元素,页面开头的"Creation"元素和目标类型元素class完全一致,因此被优先选中,导致结果不符合预期。find_all()报错的原因find_all()返回的是元素列表(ResultSet),不能直接调用.text属性,必须遍历列表中的每个元素单独获取文本。正确的爬取逻辑
根据页面结构,目标类型属于"Genres"分类下的链接,可先定位到"Genres"所在区域,再提取类型:
# 方法1:通过父元素定位 genre_section = soup1.find("span", string="Genres").parent.parent genres = [a.text for a in genre_section.find_all("a", class_="ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link")] print(genres) # 方法2:用CSS选择器直接定位 genres = [a.text for a in soup1.select('span:contains("Genres") + div a')] print(genres)
二、批量处理DataFrame的for循环实现
可以先定义一个爬取单条链接类型的函数,再通过遍历DataFrame批量处理:
方式1:使用apply()方法(简洁高效)
import requests from bs4 import BeautifulSoup import pandas as pd # 定义爬取单剧集类型的函数 def get_genres(url): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'} response = requests.get(url, headers=headers) soup = BeautifulSoup(response.content, 'html.parser') try: genre_section = soup.find("span", string="Genres").parent.parent genres = [a.text for a in genre_section.find_all("a", class_="ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link")] return ', '.join(genres) # 拼接成字符串便于存储 except AttributeError: return "无类型信息" # 处理页面结构异常的情况 # 批量获取类型并添加到DataFrame tvshows_url['genres'] = tvshows_url['link'].apply(get_genres) # 输出结果 print(tvshows_url)
方式2:使用iterrows()遍历行(直观易懂)
import requests from bs4 import BeautifulSoup import pandas as pd import time # 用于添加延迟,避免反爬 def get_genres(url): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'} response = requests.get(url, headers=headers) soup = BeautifulSoup(response.content, 'html.parser') try: genre_section = soup.find("span", string="Genres").parent.parent genres = [a.text for a in genre_section.find_all("a", class_="ipc-metadata-list-item__list-content-item ipc-metadata-list-item__list-content-item--link")] return ', '.join(genres) except AttributeError: return "无类型信息" # 初始化空列表存储类型 genres_list = [] for index, row in tvshows_url.iterrows(): url = row['link'] genres = get_genres(url) genres_list.append(genres) time.sleep(2) # 每次爬取后延迟2秒,避免触发反爬 # 将结果添加到DataFrame tvshows_url['genres'] = genres_list print(tvshows_url)
注意:频繁爬取IMDb可能触发反爬机制,建议添加延迟或使用代理IP,避免IP被封禁。
内容的提问来源于stack exchange,提问作者Paula Gryglewska
相关产品推荐
相关产品推荐

