天天看點

python抓取豆瓣電影排行榜資料(含GUI界面)

項目簡介

這個項目源于某課程設計。平常經常需要搜尋一些電影,但是不知道哪些評分高且評價人數多的電影。為了友善使用,就将原來的項目重新改寫了。當做是對爬蟲技術、可視化技術的實踐了。主要是通過從排行榜和從影片關鍵詞兩種方式爬取電影資料。

本項目代碼量較大,可以從我的GitHub位址fork下來自己跑一跑

GitHub位址

配置說明

  • 打開http://chromedriver.storage.googleapis.com/index.html,根據自己的作業系統下載下傳對應的chromedriver
  • 打開目前面目錄下的getMovieInRankingList.py,定位到第59行
  • 将executable_path=D:/Chrome/chromedriver.exe修改成你自己的chromedriver路徑
  • 打開pycharm,依次安裝以下包
pip install Pillow
pip install selenium
           

功能截圖

包含功能

根據關鍵字搜尋電影
根據排行榜(TOP250)搜尋電影
顯示IMDB評分及其他基本資訊
提供多個線上視訊站點,無需vip
提供多個雲盤站點搜尋該視訊,以便儲存到雲盤
提供多個站點下載下傳該視訊
           

存在問題

加入cookies
采用随機延時方式
采用IP代理池方式(較不穩定)
           

Movie.py

from ssl import _create_unverified_context
from json import loads
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import tkinter.messagebox

import urllib.request
import urllib.parse

movieData = ' [' \
            '{"title":"紀錄片", "type":"1", "interval_id":"100:90"}, ' \
            ' {"title":"傳記", "type":"2", "interval_id":"100:90"}, ' \
            ' {"title":"犯罪", "type":"3", "interval_id":"100:90"}, ' \
            ' {"title":"曆史", "type":"4", "interval_id":"100:90"}, ' \
            ' {"title":"動作", "type":"5", "interval_id":"100:90"}, ' \
            ' {"title":"情色", "type":"6", "interval_id":"100:90"}, ' \
            ' {"title":"歌舞", "type":"7", "interval_id":"100:90"}, ' \
            ' {"title":"兒童", "type":"8", "interval_id":"100:90"}, ' \
            ' {"title":"懸疑", "type":"10", "interval_id":"100:90"}, ' \
            ' {"title":"劇情", "type":"11", "interval_id":"100:90"}, ' \
            ' {"title":"災難", "type":"12", "interval_id":"100:90"}, ' \
            ' {"title":"愛情", "type":"13", "interval_id":"100:90"}, ' \
            ' {"title":"音樂", "type":"14", "interval_id":"100:90"}, ' \
            ' {"title":"冒險", "type":"15", "interval_id":"100:90"}, ' \
            ' {"title":"奇幻", "type":"16", "interval_id":"100:90"}, ' \
            ' {"title":"科幻", "type":"17", "interval_id":"100:90"}, ' \
            ' {"title":"運動", "type":"18", "interval_id":"100:90"}, ' \
            ' {"title":"驚悚", "type":"19", "interval_id":"100:90"}, ' \
            ' {"title":"恐怖", "type":"20", "interval_id":"100:90"}, ' \
            ' {"title":"戰争", "type":"22", "interval_id":"100:90"}, ' \
            ' {"title":"短片", "type":"23", "interval_id":"100:90"}, ' \
            ' {"title":"喜劇", "type":"24", "interval_id":"100:90"}, ' \
            ' {"title":"動畫", "type":"25", "interval_id":"100:90"}, ' \
            ' {"title":"同性", "type":"26", "interval_id":"100:90"}, ' \
            ' {"title":"西部", "type":"27", "interval_id":"100:90"}, ' \
            ' {"title":"家庭", "type":"28", "interval_id":"100:90"}, ' \
            ' {"title":"武俠", "type":"29", "interval_id":"100:90"}, ' \
            ' {"title":"古裝", "type":"30", "interval_id":"100:90"}, ' \
            ' {"title":"黑色電影", "type":"31", "interval_id":"100:90"}' \
            ']'


class getMovieInRankingList:

    # typeId 電影類型, movie_count 欲擷取的該電影類型的數量, rating 電影的評分, vote_count 電影的評價人數
    def __init__(self):
        chrome_options = Options()
        chrome_options.add_argument('--headless')  # 設定為無頭模式,即不顯示浏覽器
        chrome_options.add_argument(
            'user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"')  # 設定user=agent
        chrome_options.add_experimental_option('excludeSwitches',['enable-automation'])  # 此步驟很重要,設定為開發者模式,防止被各大網站識别出來使用了Selenium
        chrome_options.add_experimental_option("prefs",{"profile.managed_default_content_settings.images": 2})  # 不加載圖檔,加快通路速度

        try:
            self.browser = webdriver.Chrome(executable_path='D:/Chrome/chromedriver.exe',chrome_options=chrome_options)  # 設定chromedriver路徑
            self.wait = WebDriverWait(self.browser, 10)  # 逾時時長為10s
        except:
            print("chromedriver.exe出錯,請檢查是否與你的chrome浏覽器版本相比對\n缺失chromedriver.exe不會導緻從排行榜搜尋功能失效,但會導緻從關鍵字搜尋功能失效")

    # 從排行榜中擷取電影資料
    def get_url_data_in_ranking_list(self, typeId, movie_count, rating, vote_count):
        context = _create_unverified_context()  # 屏蔽ssl證書
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', }
        url = 'https://movie.douban.com/j/chart/top_list?type=' + str(
            typeId) + '&interval_id=100:90&action=unwatched&start=0&limit=' + str(movie_count)
        req = urllib.request.Request(url=url, headers=headers)
        f = urllib.request.urlopen(req, context=context)
        response = f.read()
        jsonData = loads(response)  # 将json轉為python對象

        list = []
        for subData in jsonData:  # 依次對每部電影進行操作
            if ((float(subData['rating'][0]) >= float(rating)) and (float(subData['vote_count']) >= float(vote_count))):
                subList = []
                subList.append(subData['title'])
                subList.append(subData['rating'][0])
                subList.append(subData['rank'])
                subList.append(subData['vote_count'])
                list.append(subList)

        for data in list:
            print(data)

        return list, jsonData

    # 從關鍵字擷取電影資料
    def get_url_data_in_keyWord(self, key_word):

        # 浏覽網頁
        self.browser.get('https://movie.douban.com/subject_search?search_text=' + urllib.parse.quote(
            key_word) + '&cat=1002')  # get方式擷取傳回資料

        # js動态渲染的網頁,必須等到搜尋結果元素(DIV中class=root)出來後,才可以停止加載網頁
        # 等待DIV中class=root的元素出現
        self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.root')))

        dr = self.browser.find_elements_by_xpath("//div[@class='item-root']")  # 擷取class為item-root的DIV(因為有多個結果)
        jsonData = []
        list = []
        for son in dr:
            movieData = {'rating': ['', 'null'], 'cover_url': '', 'types': '', 'title': '', 'url': '',
                         'release_date': '', 'vote_count': '', 'actors': ''}
            subList = ['', '', '', '']

            url_element = son.find_elements_by_xpath(".//a")  # 擷取第一個a标簽的url(因為有多個結果)
            if (url_element):
                movieData['url'] = (url_element[0].get_attribute("href"))

            img_url_element = url_element[0].find_elements_by_xpath(".//img")  # 擷取影片海報圖檔位址
            if (img_url_element):
                movieData['cover_url'] = (img_url_element[0].get_attribute("src"))

            title_element = son.find_elements_by_xpath(".//div[@class='title']")  # 擷取标題
            if (title_element):
                temp_title = (title_element[0].text)
                movieData['title'] = (temp_title.split('('))[0]
                movieData['release_date'] = temp_title[temp_title.find('(') + 1:temp_title.find(')')]
                subList[0] = movieData['title']

            rating_element = son.find_elements_by_xpath(".//span[@class='rating_nums']")  # 擷取評分
            if (rating_element):
                movieData['rating'][0] = (rating_element[0].text)
                subList[1] = movieData['rating'][0]

            vote_element = son.find_elements_by_xpath(".//span[@class='pl']")  # 擷取數量
            if (vote_element):
                movieData['vote_count'] = (vote_element[0].text).replace('(', '').replace(')', '').replace('人評價', '')
                subList[3] = movieData['vote_count']

            type_element = son.find_elements_by_xpath(".//div[@class='meta abstract']")  # 擷取類型
            if (type_element):
                movieData['types'] = (type_element[0].text)
                subList[2] = movieData['types']

            actors_element = son.find_elements_by_xpath(".//div[@class='meta abstract_2']")  # 擷取演員
            if (actors_element):
                movieData['actors'] = (actors_element[0].text)

            jsonData.append(movieData)
            list.append(subList)

        # 關閉浏覽器
        self.browser.quit()

        for data in list:
            print(data)

        return list, jsonData
           

DoubanMovie.py

from PIL import Image, ImageTk
from Movie import *
from tkinter import Tk
from tkinter import ttk
from tkinter import font
from tkinter import LabelFrame
from tkinter import Label
from tkinter import StringVar
from tkinter import Entry
from tkinter import END
from tkinter import Button
from tkinter import Frame
from tkinter import RIGHT
from tkinter import NSEW
from tkinter import NS
from tkinter import NW
from tkinter import N
from tkinter import Y
from tkinter import DISABLED
from tkinter import NORMAL
from re import findall
from json import loads
from threading import Thread
from urllib.parse import quote
from webbrowser import open
import os
import ssl
ssl._create_default_https_context = ssl._create_unverified_context #關閉SSL證書驗證





def thread_it(func, *args):
    '''
    将函數打包進線程
    '''
    # 建立
    t = Thread(target=func, args=args)
    # 守護
    t.setDaemon(True)
    # 啟動
    t.start()


def handlerAdaptor(fun, **kwds):
    '''事件處理函數的擴充卡,相當于中介,那個event是從那裡來的呢,我也納悶,這也許就是python的偉大之處吧'''
    return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)



def save_img(img_url, file_name, file_path):
    """
    下載下傳指定url的圖檔,并儲存運作目錄下的img檔案夾
    :param img_url: 圖檔位址
    :param file_name: 圖檔名字
    :param file_path: 存儲目錄
    :return:
    """
    #儲存圖檔到磁盤檔案夾 file_path中,預設為目前腳本運作目錄下的img檔案夾
    try:
        #判斷檔案夾是否已經存在
        if not os.path.exists(file_path):
            print('檔案夾',file_path,'不存在,重建立立')
            os.makedirs(file_path)
        #獲得圖檔字尾
        file_suffix = os.path.splitext(img_url)[1]
        #拼接圖檔名(包含路徑)
        filename = '{}{}{}{}'.format(file_path,os.sep,file_name,file_suffix)

        #判斷檔案是否已經存在
        if not os.path.exists(filename):
            print('檔案', filename, '不存在,重建立立')
            # 下載下傳圖檔,并儲存到檔案夾中
            urllib.request.urlretrieve(img_url, filename=filename)
        return filename

    except IOError as e:
        print('下載下傳圖檔操作失敗',e)
    except Exception as e:
        print('錯誤:',e)



def resize(w_box, h_box, pil_image):
    """
    等比例縮放圖檔,并且限制在指定方框内
    :param w_box,h_box: 指定方框的寬度和高度
    :param pil_image: 原始圖檔
    :return:
    """

    f1 = 1.0 * w_box / pil_image.size[0]  # 1.0 forces float division in Python2
    f2 = 1.0 * h_box / pil_image.size[1]
    factor = min([f1, f2])
    # print(f1, f2, factor) # test
    # use best down-sizing filter
    width = int(pil_image.size[0] * factor)
    height = int(pil_image.size[1] * factor)
    return pil_image.resize((width, height), Image.ANTIALIAS)


def get_mid_str(content,startStr,endStr):
    startIndex = content.index(startStr)
    if startIndex>=0:
        startIndex += len(startStr)
    endIndex = content.index(endStr)
    return content[startIndex:endIndex]


class uiObject:

    def __init__(self):
        self.jsonData = ""
        self.jsonData_keyword = ""


    def show_GUI_movie_detail(self):
        '''
        顯示 影片詳情 界面GUI
        '''
        self.label_img['state'] = NORMAL
        self.label_movie_name['state'] = NORMAL
        self.label_movie_rating['state'] = NORMAL
        self.label_movie_time['state'] = NORMAL
        self.label_movie_type['state'] = NORMAL
        self.label_movie_actor['state'] = NORMAL


    def hidden_GUI_movie_detail(self):
        '''
        顯示 影片詳情 界面GUI
        '''
        self.label_img['state'] = DISABLED
        self.label_movie_name['state'] = DISABLED
        self.label_movie_rating['state'] = DISABLED
        self.label_movie_time['state'] = DISABLED
        self.label_movie_type['state'] = DISABLED
        self.label_movie_actor['state'] = DISABLED



    def show_IDMB_rating(self):
        '''
        顯示IDM評分
        '''

        self.label_movie_rating_imdb.config(text='正在加載IMDB評分')
        self.B_0_imdb['state'] = DISABLED
        rating_imdb = '未知'



        item = self.treeview.selection()
        if(item):
            item_text = self.treeview.item(item, "values")
            movieName = item_text[0] # 輸出電影名
            for movie in self.jsonData:
                if(movie['title'] == movieName):

                    f = urllib.request.urlopen(movie['url'])
                    response = (f.read()).decode()
                    url_imdb = get_mid_str(response, 'IMDb連結:</span> <a href=\"', '\" target=\"_blank\" rel=\"nofollow\">')

                    f = urllib.request.urlopen(url_imdb)
                    data_imdb = (f.read()).decode()
                    rating_imdb = get_mid_str(data_imdb, '<span class=\"rating">', '<span class=\"ofTen\">')







                    self.clear_tree(self.treeview_play_online)
                    s = response
                    name = findall(r"<a class=\"playBtn\" data-cn=\"(.*?)\" href=\"", s)
                    down_url = findall(r"data-cn=\".*?\" href=\"(.*?)\" target=", s)
                    real_movie_name = get_mid_str(s, "<title>", "</title>").replace(" ","").replace("\n","").replace("(豆瓣)","")
                    print(real_movie_name)
                    list = []
                    for i in range(len(name)):
                        list.append([name[i], "限VIP免費", down_url[i]])
                    list.append(["4K屋", "免費", "http://www.4kwu.cc/?m=vod-search&wd=" + quote(real_movie_name)])
                    list.append(["91黑米", "免費", "http://www.91heimi.com/index.php/vod/search.html?wd=" + quote(real_movie_name)])
                    list.append(["AAQQS", "免費", "http://aaxxy.com/vod-search-pg-1-wd-" + quote(real_movie_name) + ".html"])
                    list.append(["Neets", "免費", "http://neets.cc/search?key=" + quote(real_movie_name)])
                    list.append(["Q2電影網", "免費", "http://www.q2002.com/search?wd=" + quote(real_movie_name)])
                    list.append(["霸氣村", "免費", "http://www.baqicun.co/search.php?searchword=" + quote(real_movie_name)])
                    list.append(["魔力電影網", "免費", "http://www.magbt.net/search.php?searchword=" + quote(real_movie_name)])
                    list.append(["新論語", "免費", "http://www.honggujiu.net/index.php?m=vod-search&wd=" + quote(real_movie_name)])
                    list.append(["左手吃齋", "免費", "https://www.xiangkanju.com/index.php?m=vod-search&wd=" + quote(real_movie_name)])
                    self.add_tree(list, self.treeview_play_online)











                    self.clear_tree(self.treeview_save_cloud_disk)
                    list = []
                    list.append(["56網盤搜尋", "有效", "https://www.56wangpan.com/search/o2kw" + quote(real_movie_name)])
                    list.append(["愛搜資源", "有效", "https://www.aisouziyuan.com/?name=" + quote(real_movie_name) + "&page=1"])
                    list.append(["盤多多", "有效", "http://www.panduoduo.net/s/comb/n-" + quote(real_movie_name) + "&f-f4"])
                    list.append(["小白盤", "有效", "https://www.xiaobaipan.com/list-" + quote(real_movie_name) + "-1.html" ])
                    list.append(["雲盤精靈", "有效", "https://www.yunpanjingling.com/search/" + quote(real_movie_name) + "?sort=size.desc"])
                    self.add_tree(list, self.treeview_save_cloud_disk)






                    self.clear_tree(self.treeview_bt_download)
                    list = []
                    list.append(  ['19影視', '有效', 'https://www.19kan.com/vodsearch.html?wd=' + quote(real_movie_name)  ])
                    list.append(  ['2TU影院', '有效', 'http://www.82tu.cc/search.php?submit=%E6%90%9C+%E7%B4%A2&searchword=' + quote(real_movie_name)  ])
                    list.append(  ['4K電影', '有效', 'https://www.dygc.org/?s=' + quote(real_movie_name)  ])
                    list.append(  ['52 Movie', '有效', 'http://www.52movieba.com/search.htm?keyword=' + quote(real_movie_name)  ])
                    list.append(  ['592美劇', '有效', 'http://www.592meiju.com/search/?wd=' + quote(real_movie_name)  ])
                    list.append(  ['97電影網', '有效', 'http://www.55xia.com/search?q=' + quote(real_movie_name)  ])
                    list.append(  ['98TVS', '有效', 'http://www.98tvs.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['9去這裡', '有效', 'http://9qzl.com/index.php?s=/video/search/wd/' + quote(real_movie_name)  ])
                    list.append(  ['CK電影', '有效', 'http://www.ck180.net/search.html?q=' + quote(real_movie_name)  ])
                    list.append(  ['LOL電影', '有效', 'http://www.993dy.com/index.php?m=vod-search&wd=' + quote(real_movie_name)  ])
                    list.append(  ['MP4Vv', '有效', 'http://www.mp4pa.com/search.php?searchword=' + quote(real_movie_name)  ])
                    list.append(  ['MP4電影', '有效', 'http://www.domp4.com/search/' + quote(real_movie_name)   + '-1.html'])
                    list.append(  ['TL95', '有效', 'http://www.tl95.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['比特大雄', '有效', 'https://www.btdx8.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['比特影視', '有效', 'https://www.bteye.com/search/' + quote(real_movie_name)  ])
                    list.append(  ['春曉影視', '有效', 'http://search.chunxiao.tv/?keyword=' + quote(real_movie_name)  ])
                    list.append(  ['第一電影網', '有效', 'https://www.001d.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['電影日志', '有效', 'http://www.dyrizhi.com/search?s=' + quote(real_movie_name)  ])
                    list.append(  ['高清888', '有效', 'https://www.gaoqing888.com/search?kw=' + quote(real_movie_name)  ])
                    list.append(  ['高清MP4', '有效', 'http://www.mp4ba.com/index.php?m=vod-search&wd=' + quote(real_movie_name)  ])
                    list.append(  ['高清電台', '有效', 'https://gaoqing.fm/s.php?q=' + quote(real_movie_name)  ])
                    list.append(  ['高清控', '有效', 'http://www.gaoqingkong.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['界紹部', '有效', 'http://www.jsb456.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['看美劇', '有效', 'http://www.kanmeiju.net/index.php?s=/video/search/wd/' + quote(real_movie_name)  ])
                    list.append(  ['藍光網', '有效', 'http://www.languang.co/?s=' + quote(real_movie_name)  ])
                    list.append(  ['老司機電影', '有效', 'http://www.lsjdyw.net/search/?s=' + quote(real_movie_name)  ])
                    list.append(  ["樂賞電影", '有效', 'http://www.gscq.me/search.htm?keyword=' + quote(real_movie_name)  ])
                    list.append(  ["美劇彙", '有效', 'http://www.meijuhui.net/search.php?q=' + quote(real_movie_name)  ])
                    list.append(  ['美劇鳥', '有效', 'http://www.meijuniao.com/index.php?s=vod-search-wd-' + quote(real_movie_name)  ])
                    list.append(  ['迷你MP4', '有效', 'http://www.minimp4.com/search?q=' + quote(real_movie_name)  ])
                    list.append(  ['泡飯影視', '有效', 'http://www.chapaofan.com/search/' + quote(real_movie_name)  ])
                    list.append(  ['片吧', '有效', 'http://so.pianbar.com/search.aspx?q=' + quote(real_movie_name)  ])
                    list.append(  ['片源網', '有效', 'http://pianyuan.net/search?q=' + quote(real_movie_name)  ])
                    list.append(  ['飄花資源網', '有效', 'https://www.piaohua.com/plus/search.php?kwtype=0&keyword=' + quote(real_movie_name)  ])
                    list.append(  ['趣味源', '有效', 'http://quweiyuan.cc/?s=' + quote(real_movie_name)  ])
                    list.append(  ['人生05', '有效', 'http://www.rs05.com/search.php?s=' + quote(real_movie_name)  ])
                    list.append(  ['貪玩影視', '有效', 'http://www.tanwanyingshi.com/movie/search?keyword=' + quote(real_movie_name)  ])
                    list.append(  ['新片網', '有效', 'http://www.91xinpian.com/index.php?m=vod-search&wd=' + quote(real_movie_name)  ])
                    list.append(  ['迅雷影天堂', '有效', 'https://www.xl720.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['迅影網', '有效', 'http://www.xunyingwang.com/search?q=' + quote(real_movie_name)  ])
                    list.append(  ['一隻大榴蓮', '有效', 'http://www.llduang.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['音範絲', '有效', 'http://www.yinfans.com/?s=' + quote(real_movie_name)  ])
                    list.append(  ['影海', '有效', 'http://www.yinghub.com/search/list.html?keyword=' + quote(real_movie_name)  ])
                    list.append(  ['影視看看', '有效', 'http://www.yskk.tv/index.php?m=vod-search&wd=' + quote(real_movie_name)  ])
                    list.append(  ['雲播網', '有效', 'http://www.yunbowang.cn/index.php?m=vod-search&wd=' + quote(real_movie_name)  ])
                    list.append(  ['中國高清網', '有效', 'http://gaoqing.la/?s=' + quote(real_movie_name)  ])
                    list.append(  ['最新影視站', '有效', 'http://www.zxysz.com/?s=' + quote(real_movie_name)  ])
                    self.add_tree(list, self.treeview_bt_download)



                    break;

        self.label_movie_rating_imdb.config(text='IMDB評分:' + rating_imdb + '分')



    def project_statement_show(self, event):
        open("https://github.com/shengqiangzhang/examples-of-web-crawlers")

    def project_statement_get_focus(self, event):
        self.project_statement.config(fg="blue", cursor="hand1")

    def project_statement_lose_focus(self, event):
        self.project_statement.config(fg="#FF0000")


    def show_movie_data(self, event):
        '''
        顯示某個被選擇的電影的詳情資訊
        '''

        # self.hidden_GUI_movie_detail()

        self.B_0_imdb['state'] = NORMAL
        self.label_movie_rating_imdb.config(text = 'IMDB評分')
        self.clear_tree(self.treeview_play_online)
        self.clear_tree(self.treeview_save_cloud_disk)
        self.clear_tree(self.treeview_bt_download)

        item = self.treeview.selection()
        if(item):
            item_text = self.treeview.item(item, "values")
            movieName = item_text[0] # 輸出電影名
            for movie in self.jsonData:
                if(movie['title'] == movieName):
                    img_url = movie['cover_url']
                    movie_name = movie['title']
                    file_name = save_img(img_url, movie_name, 'img') #下載下傳網絡圖檔
                    self.show_movie_img(file_name)
                    self.label_movie_name.config(text=movie['title'])
                    if(isinstance(movie['actors'],list)):
                        string_actors = "、".join(movie['actors'])
                    else:
                        string_actors = movie['actors']
                    self.label_movie_actor.config(text=string_actors)
                    self.label_movie_rating.config(text=str(movie['rating'][0]) + '分 ' + str(movie['vote_count']) + '人評價')
                    self.label_movie_time.config(text=movie['release_date'])
                    self.label_movie_type.config(text=movie['types'])

                    break

        # self.show_GUI_movie_detail()






    def show_movie_img(self, file_name):
        '''
        更新圖檔GUI
        :param file_name: 圖檔路徑
        :return:
        '''
        img_open = Image.open(file_name) #讀取本地圖檔
        pil_image_resized = resize(160, 230, img_open) #等比例縮放本地圖檔
        img = ImageTk.PhotoImage(pil_image_resized) #讀入圖檔
        self.label_img.config(image=img, width = pil_image_resized.size[0], height = pil_image_resized.size[1])
        self.label_img.image = img


    def center_window(self, root, w, h):
        """
        視窗居于螢幕中央
        :param root: root
        :param w: 視窗寬度
        :param h: 視窗高度
        :return:
        """
        # 擷取螢幕 寬、高
        ws = root.winfo_screenwidth()
        hs = root.winfo_screenheight()

        # 計算 x, y 位置
        x = (ws/2) - (w/2)
        y = (hs/2) - (h/2)

        root.geometry('%dx%d+%d+%d' % (w, h, x, y))



    def clear_tree(self, tree):
        '''
        清空表格
        '''
        x = tree.get_children()
        for item in x:
            tree.delete(item)

    def add_tree(self,list, tree):
        '''
        新增資料到表格
        '''
        i = 0
        for subList in list:
            tree.insert('', 'end', values=subList)
            i = i + 1
        tree.grid()


    def searh_movie_in_rating(self):
        """
        從排行榜中搜尋符合條件的影片資訊
        """

        # 按鈕設定為灰色狀态
        self.clear_tree(self.treeview)  # 清空表格
        self.B_0['state'] = DISABLED
        self.C_type['state'] = DISABLED
        self.T_count['state'] = DISABLED
        self.T_rating['state'] = DISABLED
        self.T_vote['state'] = DISABLED
        self.B_0_keyword['state'] = DISABLED
        self.T_vote_keyword['state'] = DISABLED
        self.B_0['text'] = '正在努力搜尋'
        self.jsonData = ""


        jsonMovieData = loads(movieData)
        for subMovieData in jsonMovieData:
            if(subMovieData['title'] == self.C_type.get()):

                movieObject = getMovieInRankingList() #建立對象
                list,jsonData = movieObject.get_url_data_in_ranking_list(subMovieData['type'], self.T_count.get(), self.T_rating.get(), self.T_vote.get())  # 傳回符合條件的電影資訊
                self.jsonData = jsonData
                self.add_tree(list, self.treeview) # 将資料添加到tree中
                break

        # 按鈕設定為正常狀态
        self.B_0['state'] = NORMAL
        self.C_type['state'] = 'readonly'
        self.T_count['state'] = NORMAL
        self.T_rating['state'] = NORMAL
        self.T_vote['state'] = NORMAL
        self.B_0_keyword['state'] = NORMAL
        self.T_vote_keyword['state'] = NORMAL
        self.B_0['text'] = '從排行榜搜尋'




    def keyboard_T_vote_keyword(self, event):
        thread_it(self.searh_movie_in_keyword)

    def searh_movie_in_keyword(self):
        """
        從關鍵字中搜尋符合條件的影片資訊
        """
        # 按鈕設定為灰色狀态
        self.clear_tree(self.treeview)  # 清空表格
        self.B_0['state'] = DISABLED
        self.C_type['state'] = DISABLED
        self.T_count['state'] = DISABLED
        self.T_rating['state'] = DISABLED
        self.T_vote['state'] = DISABLED
        self.B_0_keyword['state'] = DISABLED
        self.T_vote_keyword['state'] = DISABLED
        self.B_0_keyword['text'] = '正在努力搜尋'
        self.jsonData = ""




        movieObject = getMovieInRankingList(); #建立對象
        list,jsonData = movieObject.get_url_data_in_keyWord(self.T_vote_keyword.get())
        self.jsonData = jsonData
        self.add_tree(list, self.treeview) # 将資料添加到tree中



        # 按鈕設定為正常狀态
        self.B_0['state'] = NORMAL
        self.C_type['state'] = 'readonly'
        self.T_count['state'] = NORMAL
        self.T_rating['state'] = NORMAL
        self.T_vote['state'] = NORMAL
        self.B_0_keyword['state'] = NORMAL
        self.T_vote_keyword['state'] = NORMAL
        self.B_0_keyword['text'] = '從關鍵字搜尋'



    def open_in_browser_douban_url(self, event):
        """
        從浏覽器中打開指定網頁
        :param
        :return:
        """
        item = self.treeview.selection()
        if(item):
            item_text = self.treeview.item(item, "values")
            movieName = item_text[0]
            for movie in self.jsonData:
                if(movie['title'] == movieName):
                    open(movie['url'])


    def open_in_browser(self, event):
        """
        從浏覽器中打開指定網頁
        :param
        :return:
        """
        item = self.treeview_play_online.selection()
        if(item):
            item_text = self.treeview_play_online.item(item, "values")
            url = item_text[2]
            open(url)


    def open_in_browser_cloud_disk(self, event):
        """
        從浏覽器中打開指定網頁
        :param
        :return:
        """
        item = self.treeview_save_cloud_disk.selection()
        if(item):
            item_text = self.treeview_save_cloud_disk.item(item, "values")
            url = item_text[2]
            open(url)



    def open_in_browser_bt_download(self, event):
        """
        從浏覽器中打開指定網頁
        :param
        :return:
        """
        item = self.treeview_bt_download.selection()
        if(item):
            item_text = self.treeview_bt_download.item(item, "values")
            url = item_text[2]
            open(url)


    def ui_process(self):
        """
        Ui主程式
        :param
        :return:
        """
        root = Tk()
        self.root = root
        # 設定視窗位置
        self.center_window(root, 1000, 565)
        root.resizable(0, 0)  # 框體大小可調性,分别表示x,y方向的可變性


        # 從排行榜 電影搜尋布局開始
        # 容器控件
        labelframe = LabelFrame(root, width=660, height=300, text="搜尋電影")
        labelframe.place(x=5, y=5)
        self.labelframe = labelframe

        # 電影類型
        L_typeId = Label(labelframe, text='電影類型')
        L_typeId.place(x=0, y=10)
        self.L_typeId = L_typeId

        #下拉清單框
        comvalue = StringVar()
        C_type = ttk.Combobox(labelframe, width=5, textvariable=comvalue, state='readonly')
        # 将影片類型輸入到下拉清單框中
        jsonMovieData = loads(movieData) #json資料
        movieList = []
        for subMovieData in jsonMovieData: #對每一種類的電影題材進行操作
            movieList.append(subMovieData['title'])
        C_type["values"] = movieList #初始化
        C_type.current(9)  # 選擇第一個
        C_type.place(x=65, y=8)
        self.C_type = C_type


        # 欲擷取的電影數量
        L_count = Label(labelframe, text='擷取數量=')
        L_count.place(x=150, y=10)
        self.L_count = L_count

        # 文本框
        T_count = Entry(labelframe, width=5)
        T_count.delete(0, END)
        T_count.insert(0, '500')
        T_count.place(x=220, y=7)
        self.T_count = T_count


        # 評分
        L_rating = Label(labelframe, text='影片評分>')
        L_rating.place(x=280, y=10)
        self.L_rating = L_rating

        # 文本框
        T_rating = Entry(labelframe, width=5)
        T_rating.delete(0, END)
        T_rating.insert(0, '8.0')
        T_rating.place(x=350, y=7)
        self.T_rating = T_rating

        # 評價人數
        L_vote = Label(labelframe, text='評價人數>')
        L_vote.place(x=410, y=10)
        self.L_vote = L_vote

        # 文本框
        T_vote = Entry(labelframe, width=7)
        T_vote.delete(0, END)
        T_vote.insert(0, '100000')
        T_vote.place(x=480, y=7)
        self.T_vote = T_vote



        # 查詢按鈕
        #lambda表示綁定的函數需要帶參數,請勿删除lambda,否則會出現異常
        #thread_it表示新開啟一個線程執行這個函數,防止GUI界面假死無響應
        B_0 = Button(labelframe, text="從排行榜搜尋")
        B_0.place(x=560, y=10)
        self.B_0 = B_0



        # 架構布局,承載多個控件
        frame_root = Frame(labelframe, width=400)
        frame_l = Frame(frame_root)
        frame_r = Frame(frame_root)
        self.frame_root = frame_root
        self.frame_l = frame_l
        self.frame_r = frame_r


        # 表格
        columns = ("影片名字", "影片評分", "同類排名", "評價人數")
        treeview = ttk.Treeview(frame_l, height=10, show="headings", columns=columns)

        treeview.column("影片名字", width=210, anchor='center')  # 表示列,不顯示
        treeview.column("影片評分", width=210, anchor='center')
        treeview.column("同類排名", width=100, anchor='center')
        treeview.column("評價人數", width=100, anchor='center')

        treeview.heading("影片名字", text="影片名字")  # 顯示表頭
        treeview.heading("影片評分", text="影片評分")
        treeview.heading("同類排名", text="同類排名")
        treeview.heading("評價人數", text="評價人數")



        #垂直滾動條
        vbar = ttk.Scrollbar(frame_r, command=treeview.yview)
        treeview.configure(yscrollcommand=vbar.set)

        treeview.pack()
        self.treeview = treeview
        vbar.pack(side=RIGHT, fill=Y)
        self.vbar = vbar

        # 架構的位置布局
        frame_l.grid(row=0, column=0, sticky=NSEW)
        frame_r.grid(row=0, column=1, sticky=NS)
        frame_root.place(x=5, y=70)

        # 從排行榜 電影搜尋布局結束










        # 輸入關鍵字 電影搜尋布局開始

        # 影片名稱
        L_vote_keyword = Label(labelframe, text='影片名稱')
        L_vote_keyword.place(x=0, y=40)
        #L_vote_keyword.grid(row=0,column=0)
        self.L_vote_keyword = L_vote_keyword

        # 文本框
        T_vote_keyword = Entry(labelframe, width=53)
        T_vote_keyword.delete(0, END)
        T_vote_keyword.insert(0, '我不是藥神')
        T_vote_keyword.place(x=66, y=37)
        self.T_vote_keyword = T_vote_keyword


        # 查詢按鈕
        #lambda表示綁定的函數需要帶參數,請勿删除lambda,否則會出現異常
        #thread_it表示新開啟一個線程執行這個函數,防止GUI界面假死無響應
        B_0_keyword = Button(labelframe, text="從關鍵字搜尋")
        B_0_keyword.place(x=560, y=40)
        self.B_0_keyword = B_0_keyword

        # 輸入關鍵字 電影搜尋布局結束










        # 電影詳情布局開始
        # 容器控件
        labelframe_movie_detail = LabelFrame(root, text="影片詳情")
        labelframe_movie_detail.place(x=670, y=5)
        self.labelframe_movie_detail = labelframe_movie_detail


        # 架構布局,承載多個控件
        frame_left_movie_detail = Frame(labelframe_movie_detail, width=160,height=280)
        frame_left_movie_detail.grid(row=0, column=0)
        self.frame_left_movie_detail = frame_left_movie_detail


        frame_right_movie_detail = Frame(labelframe_movie_detail, width=160,height=280)
        frame_right_movie_detail.grid(row=0, column=1)
        self.frame_right_movie_detail = frame_right_movie_detail


        #影片圖檔
        label_img = Label(frame_left_movie_detail, text="", anchor=N)
        label_img.place(x=0,y=0) #布局
        self.label_img = label_img

        # IMDB評分
        ft_rating_imdb = font.Font(weight=font.BOLD)
        label_movie_rating_imdb = Label(frame_left_movie_detail, text="IMDB評分", fg='#7F00FF', font=ft_rating_imdb, anchor=NW)
        label_movie_rating_imdb.place(x=0, y=250)
        self.label_movie_rating_imdb = label_movie_rating_imdb

        # 查詢按鈕
        B_0_imdb = Button(frame_left_movie_detail, text="初始化")
        B_0_imdb.place(x=115, y=250)
        self.B_0_imdb = B_0_imdb


        #影片名字
        ft = font.Font(size=15, weight=font.BOLD)
        label_movie_name = Label(frame_right_movie_detail, text="影片名字", fg='#FF0000', font=ft,anchor=NW)
        label_movie_name.place(x=0, y=0)
        self.label_movie_name = label_movie_name

        #影片評分
        ft_rating = font.Font(weight=font.BOLD)
        label_movie_rating = Label(frame_right_movie_detail, text="影片評價", fg='#7F00FF', font=ft_rating, anchor=NW)
        label_movie_rating.place(x=0, y=30)
        self.label_movie_rating = label_movie_rating

        #影片年代
        ft_time = font.Font(weight=font.BOLD)
        label_movie_time = Label(frame_right_movie_detail, text="影片日期", fg='#666600', font=ft_time, anchor=NW)
        label_movie_time.place(x=0, y=60)
        self.label_movie_time = label_movie_time

        #影片類型
        ft_type = font.Font(weight=font.BOLD)
        label_movie_type = Label(frame_right_movie_detail, text="影片類型", fg='#330033', font=ft_type, anchor=NW)
        label_movie_type.place(x=0, y=90)
        self.label_movie_type = label_movie_type

        #影片演員
        label_movie_actor = Label(frame_right_movie_detail, text="影片演員", wraplength=135, justify = 'left', anchor=NW)
        label_movie_actor.place(x=0, y=120)
        self.label_movie_actor = label_movie_actor

        # 電影詳情布局結束









        # 線上播放布局開始

        labelframe_movie_play_online = LabelFrame(root, width=324, height=230, text="線上觀看")
        labelframe_movie_play_online.place(x=5, y=305)
        self.labelframe_movie_play_online = labelframe_movie_play_online

        # 架構布局,承載多個控件
        frame_root_play_online = Frame(labelframe_movie_play_online, width=324)
        frame_l_play_online = Frame(frame_root_play_online)
        frame_r_play_online = Frame(frame_root_play_online)
        self.frame_root_play_online = frame_root_play_online
        self.frame_l_play_online = frame_l_play_online
        self.frame_r_play_online = frame_r_play_online

        # 表格
        columns_play_online = ("來源名稱", "是否免費","播放位址")
        treeview_play_online = ttk.Treeview(frame_l_play_online, height=10, show="headings", columns=columns_play_online)
        treeview_play_online.column("來源名稱", width=90, anchor='center')
        treeview_play_online.column("是否免費", width=80, anchor='center')
        treeview_play_online.column("播放位址", width=120, anchor='center')
        treeview_play_online.heading("來源名稱", text="來源名稱")
        treeview_play_online.heading("是否免費", text="是否免費")
        treeview_play_online.heading("播放位址", text="播放位址")

        #垂直滾動條
        vbar_play_online = ttk.Scrollbar(frame_r_play_online, command=treeview_play_online.yview)
        treeview_play_online.configure(yscrollcommand=vbar_play_online.set)

        treeview_play_online.pack()
        self.treeview_play_online = treeview_play_online
        vbar_play_online.pack(side=RIGHT, fill=Y)
        self.vbar_play_online = vbar_play_online

        # 架構的位置布局
        frame_l_play_online.grid(row=0, column=0, sticky=NSEW)
        frame_r_play_online.grid(row=0, column=1, sticky=NS)
        frame_root_play_online.place(x=5, y=0)

        # 線上播放布局結束










        # 儲存到雲盤布局開始

        labelframe_movie_save_cloud_disk = LabelFrame(root, width=324, height=230, text="雲盤搜尋")
        labelframe_movie_save_cloud_disk.place(x=340, y=305)
        self.labelframe_movie_save_cloud_disk = labelframe_movie_save_cloud_disk

        # 架構布局,承載多個控件
        frame_root_save_cloud_disk = Frame(labelframe_movie_save_cloud_disk, width=324)
        frame_l_save_cloud_disk = Frame(frame_root_save_cloud_disk)
        frame_r_save_cloud_disk = Frame(frame_root_save_cloud_disk)
        self.frame_root_save_cloud_disk = frame_root_save_cloud_disk
        self.frame_l_save_cloud_disk = frame_l_save_cloud_disk
        self.frame_r_save_cloud_disk = frame_r_save_cloud_disk

        # 表格
        columns_save_cloud_disk = ("來源名稱", "是否有效","播放位址")
        treeview_save_cloud_disk = ttk.Treeview(frame_l_save_cloud_disk, height=10, show="headings", columns=columns_save_cloud_disk)
        treeview_save_cloud_disk.column("來源名稱", width=90, anchor='center')
        treeview_save_cloud_disk.column("是否有效", width=80, anchor='center')
        treeview_save_cloud_disk.column("播放位址", width=120, anchor='center')
        treeview_save_cloud_disk.heading("來源名稱", text="來源名稱")
        treeview_save_cloud_disk.heading("是否有效", text="是否有效")
        treeview_save_cloud_disk.heading("播放位址", text="播放位址")

        #垂直滾動條
        vbar_save_cloud_disk = ttk.Scrollbar(frame_r_save_cloud_disk, command=treeview_save_cloud_disk.yview)
        treeview_save_cloud_disk.configure(yscrollcommand=vbar_save_cloud_disk.set)

        treeview_save_cloud_disk.pack()
        self.treeview_save_cloud_disk = treeview_save_cloud_disk
        vbar_save_cloud_disk.pack(side=RIGHT, fill=Y)
        self.vbar_save_cloud_disk = vbar_save_cloud_disk

        # 架構的位置布局
        frame_l_save_cloud_disk.grid(row=0, column=0, sticky=NSEW)
        frame_r_save_cloud_disk.grid(row=0, column=1, sticky=NS)
        frame_root_save_cloud_disk.place(x=5, y=0)

        # 儲存到雲盤布局結束









        # BT下載下傳布局開始

        labelframe_movie_bt_download = LabelFrame(root, width=324, height=230, text="影視下載下傳")
        labelframe_movie_bt_download.place(x=670, y=305)
        self.labelframe_movie_bt_download = labelframe_movie_bt_download

        # 架構布局,承載多個控件
        frame_root_bt_download = Frame(labelframe_movie_bt_download, width=324)
        frame_l_bt_download = Frame(frame_root_bt_download)
        frame_r_bt_download = Frame(frame_root_bt_download)
        self.frame_root_bt_download = frame_root_bt_download
        self.frame_l_bt_download = frame_l_bt_download
        self.frame_r_bt_download = frame_r_bt_download

        # 表格
        columns_bt_download = ("來源名稱", "是否有效","播放位址")
        treeview_bt_download = ttk.Treeview(frame_l_bt_download, height=10, show="headings", columns=columns_bt_download)
        treeview_bt_download.column("來源名稱", width=90, anchor='center')
        treeview_bt_download.column("是否有效", width=80, anchor='center')
        treeview_bt_download.column("播放位址", width=120, anchor='center')
        treeview_bt_download.heading("來源名稱", text="來源名稱")
        treeview_bt_download.heading("是否有效", text="是否有效")
        treeview_bt_download.heading("播放位址", text="播放位址")

        #垂直滾動條
        vbar_bt_download = ttk.Scrollbar(frame_r_bt_download, command=treeview_bt_download.yview)
        treeview_bt_download.configure(yscrollcommand=vbar_bt_download.set)

        treeview_bt_download.pack()
        self.treeview_bt_download = treeview_bt_download
        vbar_bt_download.pack(side=RIGHT, fill=Y)
        self.vbar_bt_download = vbar_bt_download

        # 架構的位置布局
        frame_l_bt_download.grid(row=0, column=0, sticky=NSEW)
        frame_r_bt_download.grid(row=0, column=1, sticky=NS)
        frame_root_bt_download.place(x=5, y=0)

        # BT下載下傳布局結束





        #項目的一些資訊
        ft = font.Font(size=14, weight=font.BOLD)
        project_statement = Label(root, text="豆瓣電影排行榜資料抓取", fg='#FF0000', font=ft,anchor=NW)
        project_statement.place(x=5, y=540)
        self.project_statement = project_statement



        #綁定事件
        treeview.bind('<<TreeviewSelect>>', self.show_movie_data)  # 表格綁定選擇事件
        treeview.bind('<Double-1>', self.open_in_browser_douban_url)  # 表格綁定滑鼠左鍵事件
        treeview_play_online.bind('<Double-1>', self.open_in_browser)  # 表格綁定左鍵輕按兩下事件
        treeview_save_cloud_disk.bind('<Double-1>', self.open_in_browser_cloud_disk)  # 表格綁定左鍵輕按兩下事件
        treeview_bt_download.bind('<Double-1>', self.open_in_browser_bt_download)  # 表格綁定左鍵輕按兩下事件
        B_0.configure(command=lambda:thread_it(self.searh_movie_in_rating)) #按鈕綁定單擊事件
        B_0_keyword.configure(command=lambda:thread_it(self.searh_movie_in_keyword)) #按鈕綁定單擊事件
        B_0_imdb.configure(command=lambda: thread_it(self.show_IDMB_rating))  # 按鈕綁定單擊事件
        T_vote_keyword.bind('<Return>', handlerAdaptor(self.keyboard_T_vote_keyword))  # 文本框綁定選擇事件
        project_statement.bind('<ButtonPress-1>', self.project_statement_show)  # 标簽綁定滑鼠單擊事件
        project_statement.bind('<Enter>', self.project_statement_get_focus)  # 标簽綁定獲得焦點事件
        project_statement.bind('<Leave>', self.project_statement_lose_focus)  # 标簽綁定失去焦點事件
        root.mainloop()
           

main.py

from DoubanMovie import uiObject

# main入口
if __name__ == '__main__':

    ui = uiObject()
    ui.ui_process()