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

Kinopoisk按Genre获取随机电影报错AttributeError求助

问题:指定类型筛选随机电影时触发AttributeError

开发一款可推送随机电影的Telegram Bot(当前控制台测试,后续重构),全随机电影功能正常,但按指定类型筛选时出现异常,报错信息如下:

错误栈

C:\Users\Iwlj4s\Desktop\pm\telegramMovieBot\.venv\Scripts\python.exe C:\Users\Iwlj4s\Desktop\pm\telegramMovieBot\getMovies\main_pars.py 

Genre: Anime

User Input: Anime

Genre Key:  genre_1750 

Traceback (most recent call last):

  File "C:\Users\Iwlj4s\Desktop\pm\telegramMovieBot\getMovies\main_pars.py", line 130, in <module>

    movie_data.get_full_rnd_movie_data(True)

  File "C:\Users\Iwlj4s\Desktop\pm\telegramMovieBot\getMovies\main_pars.py", line 111, in get_full_rnd_movie_data

    self.poster_img_href = self.poster_div.find("img")["src"]

                           ^^^^^^^^^^^^^^^^^^^^

AttributeError: 'NoneType' object has no attribute 'find'

相关代码(main_pars.py)

import requests
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By


user_input = input("Genre: ")


class ParsSettings:
    def __init__(self):
        self.url = "https://www.kinopoisk.ru/chance/"
        self.url_for_img = "https://www.kinopoisk.ru/"

        self.response = requests.get(self.url)
        self.driver = webdriver.Chrome()

        self.user_genre_key = None
        self.genres = {
            'genre_1750 ': 'Anime', 'genre_22': 'biography',
            'genre_3': 'action movie', 'genre_13': 'Western',
            'genre_19': 'Military', 'genre_17': 'Detective',
            'genre_456': 'Kids', 'genre_12': 'documentary',
            'genre_8': 'Drama', 'genre_23': 'History',
            'genre_6': 'Comedy', 'genre_15': 'short film',
            'genre_16': 'Crime', 'genre_7': 'Melodrama',
            'genre_21': 'Music', 'genre_14': 'Cartoon',
            'genre_9 ': 'Musical', 'genre_10': 'Adventure',
            'genre_11': 'Family', 'genre_24': 'Sport',
            'genre_4': 'Thriller', 'genre_1': 'Horror',
            'genre_2': 'Fantastic', 'genre_18': 'Film-Noir',
            'genre_5': 'Fantasy'
        }


class GetRandomMovieData(ParsSettings):
    def __init__(self):
        super().__init__()
        self.poster_div = None
        self.poster_img_href = None
        self.poster_img = None

        self.film_name_div = None
        self.film_name = None

        self.film_genre_div = None
        self.film_genre = None

        self.film_rating_div = None
        self.film_rating_imb = None

        self.film_desc_div = None
        self.film_desc = None

        self.driver.get(self.url)

        self.list = self.driver.find_element(By.ID, "genreListTitle")
        self.button = self.driver.find_element(By.CLASS_NAME, "button")

        self.new_html = None
        self.soup = None

    def find_user_genre(self, genre):
        """
        dict genre: keys == class <li> in HTML || values == genres
        :return: genre key by user input genre, like: Anime: genre_1750
        """

        for key in self.genres:
            if self.genres[key] == genre:
                self.user_genre_key = key
                print("User Input:", user_input)
                print("Genre Key: ", self.user_genre_key)
                return self.user_genre_key
        print("No Same Gener")
        return None

    def get_rnd_movie(self):
        self.button.click()
        self.new_html = self.driver.page_source
        self.soup = BeautifulSoup(self.new_html, "lxml")
        self.driver.quit()
        return self.soup

    def get_rnd_gener_movie(self):
        self.find_user_genre(user_input)
        self.list.click()

        self.checkbox = self.driver.find_element(By.CLASS_NAME, self.user_genre_key)
        if self.checkbox:
            self.user_genre_key = self.user_genre_key
            self.checkbox.click()
            self.button.click()
            self.new_html = self.driver.page_source
            self.soup = BeautifulSoup(self.new_html, "lxml")
            self.driver.quit()
            return self.soup
        else:
            print("No Same Genre")
            return None

    def get_full_rnd_movie_data(self, genre=False):
        self.soup = None

        if not genre:
            self.soup = self.get_rnd_movie()
        elif genre:
            self.soup = self.get_rnd_gener_movie()

        self.poster_div = self.soup.find("div", class_="poster")
        self.poster_img_href = self.poster_div.find("img")["src"]
        self.poster_img = self.url_for_img + self.poster_img_href

        self.film_name_div = self.soup.find("div", class_="filmName")
        self.film_name = self.film_name_div.find("a").text

        self.film_genre_div = self.soup.find("div", class_="gray")
        self.film_genre = self.film_genre_div.text.strip()

        self.film_rating_div = self.soup.find("div", class_="rating")
        self.film_rating_imb = self.film_rating_div.text.strip()

        self.film_desc_div = self.soup.find("div", class_="syn")
        self.film_desc = self.film_desc_div.text.strip()


movie_data = GetRandomMovieData()

# For now just switch False - for get full random movie and True - for genre random movie
movie_data.get_full_rnd_movie_data(True)

print("Movie Name:", movie_data.film_name)
print("Genre:", movie_data.film_genre)
print("Rating:", movie_data.film_rating_imb)
print("Description:", movie_data.film_desc)

类型选择区域HTML片段

<div class="left_select">
                <div onclick="KP.filter.openSelect('genreList');" id="genreListTitle" class="selectCustom">выберите жанры</div>
                <ul onmouseout="KP.filter.selectBlockClose=false;" onmouseover="KP.filter.selectBlockClose=true;" class="genreList selectList" id="genreList" style="display: block;">
                    
                        <li class="genre_1750 selectItem"><label><input type="checkbox" onchange="KP.filter.toggleCheckbox('genre', this);" data-name="аниме" value="1750" name="m_act[genre][]"> аниме</label></li>
                    
                        <li class="genre_22 selectItem"><label><input type="checkbox" onchange="KP.filter.toggleCheckbox('genre', this);" data-name="биография" value="22" name="m_act[genre][]"> биография</label></li>
                    
                        <li class="genre_3 selectItem"><label><input type="checkbox" onchange="KP.filter.toggleCheckbox('genre', this);" data-name="боевик" value="3" name="m_act[genre][]"> боевик</label></li>
                    
                        <li class="genre_13 selectItem"><label><input type="checkbox" onchange="KP.filter.toggleCheckbox('genre', this);" data-name="вестерн" value="13" name="m_act[genre][]"> вестерн</label></li>

问题原因

  1. 类型键存在多余空格:genres字典中'Anime'对应的键是'genre_1750 '(末尾带空格),但HTML中li的class是genre_1750(无空格),导致Selenium无法找到目标元素,后续未触发正确的筛选,页面没有加载出指定类型的电影内容,BeautifulSoup解析后找不到poster等元素,触发NoneType错误。
  2. 缺少页面等待机制:点击类型列表、复选框后,页面可能未完全加载就获取源码,导致soup内容不完整,无法提取电影信息。
  3. 复选框定位错误:直接点击li元素而非内部的input复选框,可能未触发实际的筛选状态变更。
  4. 逻辑冗余与异常缺失:代码中存在无意义的赋值语句,且未对find方法的返回值做None判断,一旦元素找不到就直接崩溃。

修复方案

1. 修正类型字典的键

移除genres字典中键的多余空格,确保与HTML中的class完全匹配:

self.genres = {
    'genre_1750': 'Anime', 'genre_22': 'biography',
    'genre_3': 'action movie', 'genre_13': 'Western',
    'genre_19': 'Military', 'genre_17': 'Detective',
    'genre_456': 'Kids', 'genre_12': 'documentary',
    'genre_8': 'Drama', 'genre_23': 'History',
    'genre_6': 'Comedy', 'genre_15': 'short film',
    'genre_16': 'Crime', 'genre_7': 'Melodrama',
    'genre_21': 'Music', 'genre_14': 'Cartoon',
    'genre_9': 'Musical', 'genre_10': 'Adventure',
    'genre_11': 'Family', 'genre_24': 'Sport',
    'genre_4': 'Thriller', 'genre_1': 'Horror',
    'genre_2': 'Fantastic', 'genre_18': 'Film-Noir',
    'genre_5': 'Fantasy'
}

2. 添加显式等待

引入WebDriverWait和expected_conditions,确保元素加载完成后再操作:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

3. 修正复选框定位与操作逻辑

在get_rnd_gener_movie中,先等待类型列表展开,再定位li下的input复选框并点击:

def get_rnd_gener_movie(self):
    genre_key = self.find_user_genre(user_input)
    if not genre_key:
        print("No Same Genre")
        return None
    
    self.list.click()
    # 等待类型列表展开
    WebDriverWait(self.driver, 10).until(
        EC.visibility_of_element_located((By.ID, "genreList"))
    )
    # 定位li元素,再找内部的复选框
    li_element = self.driver.find_element(By.CLASS_NAME, genre_key)
    checkbox = li_element.find_element(By.TAG_NAME, "input")
    checkbox.click()
    
    self.button.click()
    # 等待电影内容加载完成
    WebDriverWait(self.driver, 10).until(
        EC.visibility_of_element_located((By.CLASS_NAME, "poster"))
    )
    
    self.new_html = self.driver.page_source
    self.soup = BeautifulSoup(self.new_html, "lxml")
    self.driver.quit()
    return self.soup

4. 增加异常判断,避免NoneType崩溃

在get_full_rnd_movie_data中,对每个find结果做None判断:

def get_full_rnd_movie_data(self, genre=False):
    self.soup = None

    if not genre:
        self.soup = self.get_rnd_movie()
    elif genre:
        self.soup = self.get_rnd_gener_movie()
    
    if not self.soup:
        print("Failed to get page source")
        return
    
    self.poster_div = self.soup.find("div", class_="poster")
    if self.poster_div:
        img_tag = self.poster_div.find("img")
        if img_tag and "src" in img_tag.attrs:
            self.poster_img_href = img_tag["src"]
            self.poster_img = self.url_for_img + self.poster_img_href
    
    self.film_name_div = self.soup.find("div", class_="filmName")
    if self.film_name_div:
        name_tag = self.film_name_div.find("a")
        if name_tag:
            self.film_name = name_tag.text
    
    self.film_genre_div = self.soup.find("div", class_="gray")
    if self.film_genre_div:
        self.film_genre = self.film_genre_div.text.strip()
    
    self.film_rating_div = self.soup.find("div", class_="rating")
    if self.film_rating_div:
        self.film_rating_imb = self.film_rating_div.text.strip()
    
    self.film_desc_div = self.soup.find("div", class_="syn")
    if self.film_desc_div:
        self.film_desc = self.film_desc_div.text.strip()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:22:03