用python(kivy模块)开发安卓影视App——搜索页面开发(二)

本文介绍了一个使用Kivy框架构建的国内影视推荐系统。开发者克服了Kivy在国内使用较少的困难,实现了包括分类列表、详情展示、搜索功能在内的多个模块。系统能够从指定网站抓取数据,展示影视信息,如标题、图片和简介,并提供了详细的代码实现。通过这个项目,读者可以学习到Kivy应用开发和网页数据抓取的相关技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于kivy在国内使用较少,在开发道路上困难重重,本人也花了不少精力来进行开发,希望大家能够从中得到学习与锻炼。

下面是我的成果图

 首先是py文件

import requests
import re
from kivy.properties import StringProperty
from kivymd.app import MDApp
from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.card import MDCard
from kivymd.uix import bottomsheet
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.stacklayout import MDStackLayout
from kivy.uix.screenmanager import Screen
from kivymd.font_definitions import theme_font_styles
from kivy.core.text import LabelBase
from kivymd.uix.screen import MDScreen
from kivy.core.window import Window
Window.size = (Window.height*3/4, Window.width*9/10)
screen_num = 0


class DealData():
    class_name = ['动漫', '追剧', '电影']
    class_key = ['4', '2', '1']
    class_url = 'https://saohuo.la/list/[].html'
    header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50",
        'Cookie': 'PHPSESSID=6rag7kboi7414tmm4amgebaonq; Hm_lvt_176de524c092a1d4ae22a38102515b0c=1634174369,1634204939,1634692218; Hm_lpvt_176de524c092a1d4ae22a38102515b0c=1634710419',
        'Connection': 'keep-alive',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
        'Origin': 'https://play.hhplayer.com',
        'Referer': '',
        'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'sec-ch-ua': '"Chromium";v="94", "Microsoft Edge";v="94", ";Not A Brand";v="99"',


    }
    class_list = '<ul class="v_list">(.*?)</ul></section><section class="page">'
    class_list_name = '<li><div class="v_img"><a href=".*?" title="(.*?)"><img class='
    class_list_picture = '<img class="lazyload" alt=".*?" data-original="(.*?)" /></a><div class='
    class_list_href = '<li><div class="v_img"><a href="(.*?)" title=".*?"><img class='
    class_list_text = '<div class="v_note">(.*?)</div></div><p class='
    search_url = 'https://saohuo.la/search.php?page=1&searchword=KEYWORDS&searchtype='
    search_list = '<ul class="v_list">(.*?)</ul></section><section class="page">'
    search_video_name = '<li><div class="v_img"><a href=".*?" title="(.*?)"><img class='
    search_video_url = '<li><div class="v_img"><a href="(.*?)" title=".*?"><img class='
    search_video_pic = '<img class="lazyload" data-original="(.*?)" /></a><div class="v_note">'
    search_video_data = '<div class="v_note">(.*?)</div>'
    video_class_data = '<ul class="from_list">([\s\S]*?)</ul>'
    video_class_name = '<li class=".*?">([\s\S]*?)</li>'
    video_play_data = '<section class="grid_box">([\s\S]*?)</section>'
    video_play_list = '<ul class="play_list"([\s\S]*?)</ul>'
    video_play_name = '<a title="[\s\S]*?" href="[\s\S]*?" target="_self">([\s\S]*?)</a>'
    video_play_url = '<a title="[\s\S]*?" href="([\s\S]*?)" target="_self">[\s\S]*?</a>'
    video_real_url = '><iframe src="([\s\S]*?)" width="100%" scrolling="no" height="250"'
    name_head = {'name': '骚火',
                 'href_head': 'https://saohuo.la', 'image_head': ''}


# 首页影视分类列表
class MovieLayoutData(MDStackLayout):
    pass

# 屏幕切换列表


class MovieLayout(MDStackLayout):
    pass


class MovieLayoutVideoData(MDBoxLayout):
    pass


# 首页分类布局
class TabCard(MDCard):
    screen = StringProperty()
    text = StringProperty()

    def on_press(self):
        # 切换影视分类
        self.parent.parent.parent.parent.parent.parent.parent.parent.ids.screen_manager.current = self.screen


class TabCardCard(MDCard):
    screen = StringProperty()
    text = StringProperty()

    def on_press(self):
        print(self.screen)
        self.parent.parent.parent.parent.ids.video_screen_manager.current = self.screen
        self.parent.parent.parent.parent.screen = int(
            self.screen.replace('video_screen', ''))

# 影视详情单


class ElementCard(MDCard):
    url_all_datas = DealData()
    image = StringProperty()
    title_name = StringProperty()
    pictext = StringProperty()
    video_href = StringProperty()
    global screen_num

    def on_release(self):
        # 切换至搜索页面
        global screen_num
        searchscreen = MDScreen(name=f'search_screen{str(screen_num)}')
        list_movies = SearchScreen()
        list_movies.searchkey = self.title_name
        list_movies_list = list_movies.add_movie_list()
        searchscreen.add_widget(list_movies_list)
        self.parent.parent.parent.parent.parent.parent.parent.parent.parent.parent.ids.home_screen_manager.add_widget(
            searchscreen)
        self.parent.parent.parent.parent.parent.parent.parent.parent.parent.parent.ids.home_screen_manager.current = f'search_screen{str(screen_num)}'
        screen_num += 1
# 搜索影视详情单


class ElementCardCard(MDCard):
    url_all_datas = DealData()
    image = StringProperty()
    title_name = StringProperty()
    pictext = StringProperty()
    video_href = StringProperty()

    def on_press(self):
        global screen_num
        videoscreen = MDScreen(name=f'video_play_screen{str(screen_num)}')
        video_play_layout = VideoPlayScreen()
        video_play_layout.title_name = self.title_name
        video_play_layout.video_href = self.video_href
        video_play_layout.image = self.image
        video_play_layout.pictext = self.pictext
        video_play_layout.datas = []
        video_play_layout.pa_class_list()
        video_play_layout.add_class_list()
        videoscreen.add_widget(video_play_layout)
        self.parent.parent.parent.parent.parent.parent.parent.ids.home_screen_manager.add_widget(
            videoscreen)
        self.parent.parent.parent.parent.parent.parent.parent.ids.home_screen_manager.current = f'video_play_screen{str(screen_num)}'
        screen_num += 1


class ElementCardCardCard(MDCard):
    image = StringProperty()
    title_name = StringProperty()
    pictext = StringProperty()
    video_href = StringProperty()


# 主屏幕
class MainScreen(MDScreen):
    url_all_datas = DealData()
    num = 0

    def __init__(self):
        self.one_screen()
        self.add_class_name()

    def one_screen(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

    # 主页分类标签列表

    def add_class_name(self):
        for i in range(len(self.url_all_datas.class_name)):
            header = TabCard()
            header.text = self.url_all_datas.class_name[i]
            header.screen = f'screen{i}'
            self.ids.movie_class.add_widget(header)
            self.add_screen_details()
            self.num = self.num+1
    # 切换主页分类

    def add_screen_details(self):
        screen = Screen(name=f'screen{str(self.num)}')
        screen.add_widget(self.add_movie_list())
        self.ids.screen_manager.add_widget(screen)
    # 主页分类列表

    def add_movie_list(self):
        movie_layout = MovieLayoutData()
        datas = self.pa_shou_ye()
        for data in datas:
            video_list = ElementCard()
            video_list.title_name = data['title']
            video_list.video_href = data['list_url']
            video_list.image = data['image']
            video_list.pictext = data['pictext']
            movie_layout.ids.movie_list_data.add_widget(video_list)
        return movie_layout
    # 爬取主页分类详情

    def pa_shou_ye(self):
        all_datas = []
        url = self.url_all_datas.class_url.replace(
            '[]', self.url_all_datas.class_key[self.num])
        response = requests.get(
            url, headers=self.url_all_datas.header, timeout=6)
        html = response.content.decode('utf-8')
        try:
            list_item = re.findall(self.url_all_datas.class_list, html)[0]
            title_lists = re.findall(
                self.url_all_datas.class_list_name, list_item)
            href_lists = re.findall(
                self.url_all_datas.class_list_href, list_item)
            src_lists = re.findall(
                self.url_all_datas.class_list_picture, list_item)
            pictext_lists = re.findall(
                self.url_all_datas.class_list_text, list_item)
            for i in range(len(title_lists)):
                data = dict()
                data['name'] = self.url_all_datas.name_head['name']
                data['href_head'] = self.url_all_datas.name_head['href_head']
                data['image_head'] = self.url_all_datas.name_head['image_head']
                data['title'] = title_lists[i]
                data['list_url'] = data['href_head']+href_lists[i]
                data['image'] = data['image_head']+src_lists[i]
                data['pictext'] = pictext_lists[i]
                all_datas.append(data)
            return all_datas
        except:
            return all_datas

    def on_release(self):
        self.ids.home_screen_manager.current = 'home_class_screen'

    def on_press(self):
        global screen_num
        searchscreen = MDScreen(name=f'search_screen{str(screen_num)}')
        list_movies = SearchScreen()
        list_movies.searchkey = self.ids.search_key.text
        list_movies_list = list_movies.add_movie_list()
        searchscreen.add_widget(list_movies_list)
        self.ids.home_screen_manager.add_widget(searchscreen)
        self.ids.home_screen_manager.current = f'search_screen{str(screen_num)}'
        screen_num += 1


class SearchScreen():
    searchkey = ''
    url_all_datas = DealData()

    def add_movie_list(self):
        movie_layout = MovieLayout()
        datas = self.pa_sou_suo()
        for data in datas:
            video_list = ElementCardCard()
            video_list.title_name = data['title']
            video_list.video_href = data['list_url']
            video_list.image = data['image']
            video_list.pictext = data['pictext']
            movie_layout.ids.movie_list.add_widget(video_list)
        return movie_layout
    # 爬取搜索页面详情

    def pa_sou_suo(self):
        all_datas = []
        url = self.url_all_datas.search_url.replace(
            'KEYWORDS', self.searchkey)
        response = requests.get(
            url, headers=self.url_all_datas.header, timeout=6)
        html = response.content.decode('utf-8')
        try:
            list_item = re.findall(self.url_all_datas.search_list, html)[0]
            title_lists = re.findall(
                self.url_all_datas.search_video_name, list_item)
            href_lists = re.findall(
                self.url_all_datas.search_video_url, list_item)
            src_lists = re.findall(
                self.url_all_datas.search_video_pic, list_item)
            pictext_lists = re.findall(
                self.url_all_datas.search_video_data, list_item)
            for i in range(len(title_lists)):
                data = dict()
                data['name'] = self.url_all_datas.name_head['name']
                data['href_head'] = self.url_all_datas.name_head['href_head']
                data['image_head'] = self.url_all_datas.name_head['image_head']
                data['title'] = title_lists[i]
                data['list_url'] = data['href_head']+href_lists[i]
                data['image'] = data['image_head']+src_lists[i]
                data['pictext'] = pictext_lists[i]
                all_datas.append(data)
            return all_datas
        except:
            return all_datas


class VideoPlayScreen(MDBoxLayout):
    title_name = ''
    video_href = ''
    image = ''
    pictext = ''
    num = 0
    url_all_datas = DealData()
    datas = []
    screen = 0

    def add_class_list(self):
        self.ids.movie_data.title_name = self.title_name
        self.ids.movie_data.video_href = self.video_href
        self.ids.movie_data.image = self.image
        self.ids.movie_data.pictext = self.pictext
        for i in range(len(self.datas)):
            video_class_header = TabCardCard()
            video_class_header.text = self.datas[i][0]
            video_class_header.screen = f'video_screen{str(i)}'
            self.ids.video_play_class.add_widget(video_class_header)
            self.add_screen_details()
            if self.num < len(self.datas):
                self.num = self.num+1

    def add_screen_details(self):
        screen = Screen(name=f'video_screen{str(self.num)}')
        screen.add_widget(self.add_video_play_list())
        self.ids.video_screen_manager.add_widget(screen)

    def add_video_play_list(self):
        video_play_layout = MovieLayoutVideoData()
        video_lists = self.datas[self.num][1]
        for i in range(len(video_lists)):
            btnt = MDRectangleFlatButton(
                text=video_lists[i], font_name='./Lishu.ttf', size_hint_x=None)
            btnt.bind(on_press=self.on_press)

            # btnt=TabCardCardCard()
            # btnt.text=video_lists[i]
            video_play_layout.ids.movie_video_list.add_widget(btnt)
        return video_play_layout

    def pa_class_list(self):
        url = self.video_href
        response = requests.get(
            url, headers=self.url_all_datas.header, timeout=6)
        html = response.content.decode('utf-8')
        try:
            list_class_item = re.findall(
                self.url_all_datas.video_class_data, html)[0]
            video_class_name_lists = re.findall(
                self.url_all_datas.video_class_name, list_class_item)
            list_item = re.findall(self.url_all_datas.video_play_data, html)[0]
            video_play_lists = re.findall(
                self.url_all_datas.video_play_list, list_item)

            for i in range(len(video_class_name_lists)):
                last_video_play_href_lists = []
                video_play_name_lists = re.findall(
                    self.url_all_datas.video_play_name, video_play_lists[i])
                video_play_href_lists = re.findall(
                    self.url_all_datas.video_play_url, video_play_lists[i])
                for video_play_href_list in video_play_href_lists:
                    video_play_href_list_ = self.url_all_datas.name_head['href_head'] + \
                        video_play_href_list
                    last_video_play_href_lists.append(video_play_href_list_)
                data = (
                    video_class_name_lists[i], video_play_name_lists, last_video_play_href_lists)
                self.datas.append(data)

        except:
            pass

    def on_press(self, widget):
        play_href = self.datas[self.screen][2][self.datas[self.screen][1].index(
            widget.text)]
        get_real_href = GetRealPlayUrl()
        get_real_href.video_play_url = play_href
        video_play_real_url = get_real_href.pa_class_list()
        print(video_play_real_url)


class GetRealPlayUrl():
    url_all_datas = DealData()
    video_play_url = ''


    def pa_class_list(self):
        url = self.video_play_url
        response = requests.get(
            url, headers=self.url_all_datas.header, timeout=6)
        html = response.content.decode('utf-8')
        try:
            video_real_url = re.findall(
                self.url_all_datas.video_real_url, html)[0]

            return video_real_url
        except:
            return '空'


class MainApp(MDApp):
    def build(self):
        self.theme_cls.theme_style = 'Light'
        self.theme_cls.primary_palette = 'Gray'
        LabelBase.register(name='Lishu', fn_regular='Lishu.ttf')
        theme_font_styles.append('Lishu')
        self.theme_cls.font_styles['Lishu'] = ['Lishu', 16, False, 0.15]
        return MainScreen()


if __name__ == '__main__':
    MainApp().run()

然后是kv文件

<MainScreen>:
    MDBoxLayout:
        orientation: 'vertical'
        MDBoxLayout:
            size_hint_y:.08
            orientation: 'vertical'
            MDBoxLayout:
                padding:[0,0,0,0]
                spacing:dp(10)
                MDIconButton:
                    icon: 'menu'
                    on_release:root.on_release()
                MDLabel:
                MDTextFieldRound:
                    id:search_key
                    normal_color: app.theme_cls.primary_light
                    hint_text:'搜索'
                    font_name: './Lishu.ttf'
                    size_hint_x:2
                    pos_hint: {'x':.1,'y': .2}
                MDIconButton:
                    icon: 'magnify'
                    on_release:root.on_press()
                MDIconButton:
                    icon:'download'             
        ScreenManager:
            id:home_screen_manager
            MDScreen:
                name:'home_class_screen'
                MDBoxLayout:
                    orientation: 'vertical'
                    MDBoxLayout:
                        size_hint_y:.05
                        ScrollView:
                            MDBoxLayout:
                                id:movie_class
                                adaptive_width:True
                                rows:1
                                padding:[10,2,10,2] 
                                spacing:dp(5)         
                    ScreenManager:
                        id:screen_manager
                        
                    MovieLayoutData:
                        size_hint_y:None
                        height:Window.width*1/100
                        adaptive_height:True 
                        screen_manager:screen_manager  
                  
                            
        MovieLayout:
            size_hint_y:None
            height:Window.width*1/100
            adaptive_height:True 
            screen_manager:home_screen_manager  
 


<ElementCard>:
    orientation: 'vertical'
    size_hint_x: .5
    size_hint_y: None
    height:Window.height*1/4
    padding: dp(10)
    radius:[25]
    
    MDBoxLayout:
        orientation: 'horizontal'
        size_hint_y: .9
        
        AsyncImage:
            source:root.image 
        MDBoxLayout:
            orientation: 'vertical'
            size_hint_y: .9
            MDLabel:
                text: root.title_name
                font_size: 15
                bold:True
                font_name: './Lishu.ttf'
                halign:'center'
            MDLabel:
                text:root.pictext
                font_name: './Lishu.ttf'
                halign:'center'
                font_size: 15     
<ElementCardCard>:
    orientation: 'vertical'
    size_hint_x: 1
    size_hint_y: None
    height:Window.height*1/4
    padding: dp(10)
    radius:[25]
    MDBoxLayout:
        orientation: 'horizontal'
        size_hint_y: .9
        
        AsyncImage:
            source:root.image 
        MDBoxLayout:
            orientation: 'vertical'
            size_hint_y: .9
            MDLabel:
                text: root.title_name
                font_size: 24
                bold:True
                font_name: './Lishu.ttf'
                halign:'center'
            MDLabel:
                text:root.pictext
                font_name: './Lishu.ttf'
                halign:'center'
                font_size: 18      
<ElementCardCardCard>:
    orientation: 'vertical'
    size_hint_x: .5
    size_hint_y: None
    height:Window.height*1/4
    padding: dp(10)
    radius:[25]
    MDBoxLayout:
        orientation: 'horizontal'
        size_hint_y: .9
        
        AsyncImage:
            source:root.image 
        MDBoxLayout:
            orientation: 'vertical'
            size_hint_y: .9
            MDLabel:
                text: root.title_name
                font_size: 24
                bold:True
                font_name: './Lishu.ttf'
                halign:'center'
            MDLabel:
                text:root.pictext
                font_name: './Lishu.ttf'
                halign:'center'
                font_size: 18    
        
<TabCard>:
    icon:'movie-roll'
    size_hint: None,1
    radius:dp(15)
    MDIcon:
        icon:root.icon
    MDLabel:
        text: root.text
        font_name:'Lishu.ttf'
<TabCardCard>:
    size_hint: None,1
    radius:dp(15)
    MDLabel:
        text: root.text
        font_name:'Lishu.ttf'
        halign:'center'

<MovieLayout>:   
    size_hint_y:1
    ScrollView:
        MDStackLayout:
            id:movie_list
            padding:[10,2,10,10] 
            spacing: '5dp'
            adaptive_height:True 
<MovieLayoutData>:   
    size_hint_y:1
    ScrollView:
        MDStackLayout:
            id:movie_list_data
            padding:[10,2,10,10] 
            spacing: '5dp'
            adaptive_height:True 
<MovieLayoutVideoData>:  
    ScrollView:
        MDStackLayout:
            id:movie_video_list
            spacing:dp(10)
            padding:[15,2,10,2]
            adaptive_height:True  
<VideoPlayScreen>:
    orientation: 'vertical'
    spacing: '10dp'
    padding:[10,2,10,2]
    MDBoxLayout:
        size_hint_y: None
        height:Window.height*1/4
        ElementCardCardCard:
            id:movie_data         
                
    MDBoxLayout:
        size_hint_y:.1
        ScrollView:
            MDBoxLayout:
                id:video_play_class
                adaptive_width:True
                rows:1
                padding:[15,2,10,2] 
                spacing:dp(5)   
                MDFillRoundFlatButton: 
                    text:'线路'
                    font_name: './Lishu.ttf'
                    normal_color: app.theme_cls.primary_dark
                    bold:True  
    ScreenManager:
        id:video_screen_manager
        
    MovieLayoutVideoData:
        size_hint_y:None
        height:Window.width*1/100
        adaptive_height:True 
        screen_manager:video_screen_manager

如果有朋友想直接使用该代码,需要设置一个字体文件,放在代码同一目录下,且名字命为Lishu.ttf即可直接使用,如果有朋友想和文墨一起开发,请私信我~

### 将Python Kivy应用打包成Android APK 为了将使用Kivy框架开发的应用程序转换为适用于Android设备的APK文件,开发者通常会利用Buildozer这一工具。Buildozer是一个专门用于构建针对Android平台的Python应用程序的命令行工具[^1]。 #### 安装依赖项 在开始之前,确保安装了必要的软件包和库来支持整个过程: 对于Linux用户来说,可以通过终端运行如下脚本来设置环境: ```bash sudo apt-get update && sudo apt-get install -y build-essential git python3-pip default-jdk pip3 install --upgrade pip virtualenv ``` #### 创建虚拟环境并激活 创建一个新的项目目录,并初始化一个Python虚拟环境,在该环境中安装所需的Python包而不会影响系统的其他部分。 ```bash mkdir mykivyapp && cd mykivyapp virtualenv venv source venv/bin/activate ``` #### 安装Kivy和其他必要模块 一旦进入虚拟环境下工作,就可以继续安装Kivy以及任何额外的需求,比如`buildozer`本身。 ```bash pip install kivy==2.0.0rc4 pip install buildozer ``` #### 编写简单的Kivy App代码作为例子 下面展示了一个非常基础的例子——带有按钮的小型GUI界面,当点击这个按钮时会在控制台打印消息。 ```python from kivy.app import App from kivy.uix.button import Button class MyApp(App): def build(self): btn = Button(text='Hello World') btn.bind(on_press=self.on_button_click) return btn @staticmethod def on_button_click(instance): print('Button clicked!') if __name__ == '__main__': MyApp().run() ``` 保存上述代码至名为`main.py`的文件内。 #### 使用Buildozer配置与构建 现在可以准备构建APK了。首先需要生成默认规格文件(`spec`),然后编辑其中的一些选项以适应具体需求。 ```bash buildozer init nano buildozer.spec ``` 在这个`.spec`文件里,应该修改至少以下几个字段: - `package.name`: 应用名称 - `package.domain`: 反向域名表示法下的公司或个人ID - `source.include_exts`: 需要被打包进最终产品的扩展名列表;如果存在非标准资源则需相应调整此参数 - `requirements`: 列出所有必需的Python依赖关系,例如`kivy, requests`等 完成这些更改之后,只需简单地执行以下指令即可启动实际的编译流程: ```bash buildozer android debug deploy run logcat ``` 这一步骤将会自动处理下载所需SDK版本、NDK以及其他相关组件的任务,接着尝试编译源码成为进制形式,并上传到连接着电脑的真实安卓手机或是模拟器上测试运行效果。最后还能实时查看日志输出以便调试目的。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值