蘋果網(wǎng)站用flash做百度西安分公司地址
目錄
1、項目效果
2、項目源碼
3、技術(shù)實現(xiàn)
4、總結(jié)
前言
? ? ? ? 我的這個項目是做的一個豆瓣電影爬取,爬取了豆瓣電影的TOP排行榜的數(shù)據(jù) 包括電影的名稱 演員 評分 評價人數(shù)等等 運用了TK布局助手 布了4個界面 有登錄 注冊 首頁 詳情
? ? ? ? 注意:項目并沒有連接數(shù)據(jù)庫?
一、項目效果
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 登錄?
??????????????????????????????????????????????????????注冊
?首頁
詳情
二、項目源碼
登錄?
from tkinter import *
from tkinter.ttk import *from tkinter import Button
import subprocess
from tkinter import messageboxclass WinGUI(Tk):def __init__(self):super().__init__()self.__win()self.name_var = "root" # 固定的姓名self.password_var = "123" # 固定的密碼self.tk_label_lwudgfpe = self.__tk_label_lwudgfpe(self)self.tk_label_lwudgqcp = self.__tk_label_lwudgqcp(self)self.tk_input_lwudhq1s = self.__tk_input_lwudhq1s(self)self.tk_input_lwudi5tc = self.__tk_input_lwudi5tc(self)self.tk_button_lwudit80 = self.__tk_button_lwudit80(self)self.tk_button_zc = self.__tk_button_zc(self)# 設(shè)置主窗口的背景顏色# self.config(bg='#B0E2FF')def __win(self):self.title("登錄")# 設(shè)置窗口大小、居中width = 400height = 300screenwidth = self.winfo_screenwidth()screenheight = self.winfo_screenheight()geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)self.geometry(geometry)self.resizable(width=False, height=False)def scrollbar_autohide(self, vbar, hbar, widget):"""自動隱藏滾動條"""def show():if vbar: vbar.lift(widget)if hbar: hbar.lift(widget)def hide():if vbar: vbar.lower(widget)if hbar: hbar.lower(widget)hide()widget.bind("<Enter>", lambda e: show())if vbar: vbar.bind("<Enter>", lambda e: show())if vbar: vbar.bind("<Leave>", lambda e: hide())if hbar: hbar.bind("<Enter>", lambda e: show())if hbar: hbar.bind("<Leave>", lambda e: hide())widget.bind("<Leave>", lambda e: hide())def v_scrollbar(self, vbar, widget, x, y, w, h, pw, ph):widget.configure(yscrollcommand=vbar.set)vbar.config(command=widget.yview)vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')def h_scrollbar(self, hbar, widget, x, y, w, h, pw, ph):widget.configure(xscrollcommand=hbar.set)hbar.config(command=widget.xview)hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')def create_bar(self, master, widget, is_vbar, is_hbar, x, y, w, h, pw, ph):vbar, hbar = None, Noneif is_vbar:vbar = Scrollbar(master)self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)if is_hbar:hbar = Scrollbar(master, orient="horizontal")self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)self.scrollbar_autohide(vbar, hbar, widget)def __tk_label_lwudgfpe(self, parent):label = Label(parent, text="用戶名", anchor="center", )label.place(x=20, y=60, width=80, height=38)return labeldef __tk_label_lwudgqcp(self, parent):label = Label(parent, text="密碼", anchor="center", )label.place(x=20, y=140, width=78, height=38)return labeldef __tk_input_lwudhq1s(self, parent):ipt = Entry(parent, )ipt.place(x=117, y=60, width=263, height=39)self.ipt1 = iptreturn iptdef __tk_input_lwudi5tc(self, parent):ipt = Entry(parent, )ipt.place(x=117, y=140, width=258, height=39)self.ipt2 = iptreturn iptdef __tk_button_lwudit80(self, parent):btn = Button(parent, text="登錄", takefocus=False, )btn.place(x=120, y=220, width=79, height=41)# 添加事件綁定btn.bind("<Button-1>", self.on_login_click) # <Button-1> 是鼠標左鍵點擊的事件return btndef __tk_button_zc(self,parent):btn = Button(parent,text="注冊",takefocus=False,)btn.place(x=250, y=220, width=79, height=41)btn.bind("<Button-1>", self.on_zc_click) # <Button-1> 是鼠標左鍵點擊的事件return btn# 添加一個新的方法作為回調(diào)函數(shù)# 登錄def on_login_click(self, event):# 輸入框里值entered_name = self.ipt2.get()entered_password =self.ipt1.get()if self.password_var== entered_name and self.name_var== entered_password:self.run_index_script()else:# 顯示錯誤提示messagebox.showerror("登錄失敗", "賬號或密碼不正確,請重新輸入。")# 添加一個新的方法作為回調(diào)函數(shù)# 注冊def on_zc_click(self, event):try:# 使用subprocess模塊啟動新的Python腳本subprocess.Popen(['python', 'register.py'])# 關(guān)閉當(dāng)前窗口# self.destroy()except Exception as e:print(f"Error occurred while running index.py: {e}")def run_index_script(self):try:# 使用subprocess模塊啟動新的Python腳本subprocess.Popen(['python', 'index.py'])# 關(guān)閉當(dāng)前窗口# self.destroy()except Exception as e:print(f"Error occurred while running index.py: {e}")def __event_bind(self):passdef __style_config(self):passif __name__ == "__main__":win = WinGUI()win.mainloop()
注冊(與登錄頁面相似,只是判斷不相同)
# 添加一個新的方法作為回調(diào)函數(shù)def on_register_click(self, event):# 輸入框里的值# 注冊新用戶new_username = self.ipt2.get().strip()new_password = self.ipt1.get().strip()if new_username and new_password:messagebox.showinfo("注冊", "注冊成功!")else:messagebox.showwarning("注冊", "用戶名或密碼不能為空!")
?首頁(布局是運用了TK助手 大家可自行設(shè)置 我這里只展示了部分功能性代碼)
def thread_it(func, *args):"""將函數(shù)打包進線程(重要):param func::param args::return:"""# 創(chuàng)建t = Thread(target=func, args=args)# 守護# t.setDaemon(True)# 啟動t.start()class movie_ui():# def ll(self):def __init__(self):self.jsonData = []def clear_treeview(self, tree):"""清空表格:param tree::return:"""rows = tree.get_children()for r in rows:tree.delete(r)def add_treeview(self, rows, tree):"""新增表格數(shù)據(jù):param rows::param tree::return:"""for r in rows:tree.insert('', END, values=(r['title'], r['rank'], r['score'], r['vote_count']))def select_treeview(self, event):"""treeview行雙擊選中事件:return:"""# 獲取選中的treeview數(shù)據(jù)行item = self.movie_tv.selection()values = self.movie_tv.item(item, "values")print(values[0])try:# 跳轉(zhuǎn)詳情頁面d = WinGUI()with open('movies.json', 'r', encoding='utf-8') as fp:# 獲取json數(shù)據(jù)movies = json.load(fp)for movie in movies:if movie['title'].__contains__(values[0]):# 將值綁定到詳情信息文本框中d.mc.insert("1.0", movie["title"])d.pj.insert("1.0", movie["score"])d.rq.insert("1.0", movie["release_date"])d.lx.insert("1.0", movie["types"])d.yy.insert("1.0", movie["actors"])except Exception as e:print(f"Error occurred while running index.py: {e}")def do_search_top(self):"""排行榜查詢按鈕事件:return:"""# 清空表格self.clear_treeview(self.movie_tv)# 設(shè)置按鈕為灰色self.btn_top['state'] = DISABLED# 下拉框的數(shù)據(jù)jsonMovieData = loads(movieData)# 循環(huán)獲取選擇下拉框中選中的值movie_type = Nonefor subMovieData in jsonMovieData:if subMovieData['title'] == self.movie_combo.get():movie_type = subMovieData['type']break# 調(diào)用查詢接口獲取數(shù)據(jù)res = get_movie_top(movie_type)# 判斷是否成功if res['code'] == 200:self.jsonData = res['movies']self.add_treeview(res['movies'], self.movie_tv)else:messagebox.showinfo('提示', res['msg'][:1000])# 按鈕設(shè)置為正常狀態(tài)self.btn_top['state'] = NORMALdef do_search_kw(self):"""關(guān)鍵字查詢按鈕事件:return:"""# 清空表格self.clear_treeview(self.movie_tv)# 設(shè)置按鈕為灰色self.btn_top['state'] = DISABLEDself.btn_keyword['state'] = DISABLED# 調(diào)用查詢接口獲取數(shù)據(jù)res = get_movie_kw(self.movie_keyword_entry.get())# 判斷是否成功if res['code'] == 200 and len(res['movies']) > 0:self.jsonData = res['movies']self.add_treeview(res['movies'], self.movie_tv)else:messagebox.showwarning('提示', '請輸入關(guān)鍵字!')# 按鈕設(shè)置為正常狀態(tài)# 從排行榜搜索self.btn_top['state'] = NORMAL# 從關(guān)鍵字搜索self.btn_keyword['state'] = NORMAL
?詳情
from tkinter import *
from tkinter.ttk import *class WinGUI(Tk):def __init__(self):super().__init__()self.__win()self.tk_label_frame_lwym93kr = self.__tk_label_frame_lwym93kr(self)self.tk_label_lwym9yej = self.__tk_label_lwym9yej( self.tk_label_frame_lwym93kr)self.tk_label_lwymcscf = self.__tk_label_lwymcscf( self.tk_label_frame_lwym93kr)self.tk_label_lwymdu0i = self.__tk_label_lwymdu0i( self.tk_label_frame_lwym93kr)self.tk_label_lwymfoy1 = self.__tk_label_lwymfoy1( self.tk_label_frame_lwym93kr)self.tk_label_lwymgb8y = self.__tk_label_lwymgb8y( self.tk_label_frame_lwym93kr)self.tk_text_lwymink1 = self.__tk_text_lwymink1( self.tk_label_frame_lwym93kr)self.tk_text_lwynp020 = self.__tk_text_lwynp020( self.tk_label_frame_lwym93kr)self.tk_text_lwynpnhj = self.__tk_text_lwynpnhj( self.tk_label_frame_lwym93kr)self.tk_text_lwynq5ny = self.__tk_text_lwynq5ny( self.tk_label_frame_lwym93kr)self.tk_text_lwynqjmm = self.__tk_text_lwynqjmm( self.tk_label_frame_lwym93kr)# 設(shè)置主窗口的背景顏色# self.config(bg='#B0E2FF')def __win(self):self.title("豆瓣電影TOP250")# 設(shè)置窗口大小、居中width = 730height = 370screenwidth = self.winfo_screenwidth()screenheight = self.winfo_screenheight()geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)self.geometry(geometry)self.resizable(width=False, height=False)def scrollbar_autohide(self,vbar, hbar, widget):"""自動隱藏滾動條"""def show():if vbar: vbar.lift(widget)if hbar: hbar.lift(widget)def hide():if vbar: vbar.lower(widget)if hbar: hbar.lower(widget)hide()widget.bind("<Enter>", lambda e: show())if vbar: vbar.bind("<Enter>", lambda e: show())if vbar: vbar.bind("<Leave>", lambda e: hide())if hbar: hbar.bind("<Enter>", lambda e: show())if hbar: hbar.bind("<Leave>", lambda e: hide())widget.bind("<Leave>", lambda e: hide())def v_scrollbar(self,vbar, widget, x, y, w, h, pw, ph):widget.configure(yscrollcommand=vbar.set)vbar.config(command=widget.yview)vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')def h_scrollbar(self,hbar, widget, x, y, w, h, pw, ph):widget.configure(xscrollcommand=hbar.set)hbar.config(command=widget.xview)hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')def create_bar(self,master, widget,is_vbar,is_hbar, x, y, w, h, pw, ph):vbar, hbar = None, Noneif is_vbar:vbar = Scrollbar(master)self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)if is_hbar:hbar = Scrollbar(master, orient="horizontal")self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)self.scrollbar_autohide(vbar, hbar, widget)def __tk_label_frame_lwym93kr(self,parent):frame = LabelFrame(parent,text="電影詳情",)frame.place(x=18, y=11, width=698, height=346)return framedef __tk_label_lwym9yej(self,parent):label = Label(parent,text="影片名稱",anchor="center", )label.place(x=58, y=11, width=120, height=38)return labeldef __tk_label_lwymcscf(self,parent):label = Label(parent,text="電影評價",anchor="center", )label.place(x=59, y=71, width=119, height=37)return labeldef __tk_label_lwymdu0i(self,parent):label = Label(parent,text="電影日期",anchor="center", )label.place(x=60, y=131, width=119, height=39)return labeldef __tk_label_lwymfoy1(self,parent):label = Label(parent,text="電影類型",anchor="center", )label.place(x=60, y=191, width=119, height=39)return labeldef __tk_label_lwymgb8y(self,parent):label = Label(parent,text="電影演員",anchor="center", )label.place(x=60, y=251, width=119, height=39)return label# 電影演員def __tk_text_lwymink1(self,parent):self.yy = Text(parent)self.yy.place(x=218, y=250, width=444, height=60)return self.yy# 電影名稱def __tk_text_lwynp020(self,parent):self.mc = Text(parent)self.mc.place(x=279, y=10, width=299, height=41)return self.mc# 電影評價def __tk_text_lwynpnhj(self,parent):self.pj = Text(parent)self.pj.place(x=280, y=72, width=299, height=37)return self.pj# 電影日期def __tk_text_lwynq5ny(self,parent):self.rq = Text(parent)self.rq.place(x=280, y=131, width=298, height=36)return self.rq# 電影類型def __tk_text_lwynqjmm(self,parent):self.lx = Text(parent)self.lx.place(x=280, y=191, width=298, height=38)return self.lxclass Win(WinGUI):def __init__(self, controller):self.ctl = controllersuper().__init__()self.__event_bind()self.__style_config()self.ctl.init(self)def __event_bind(self):passdef __style_config(self):pass
if __name__ == "__main__":win = WinGUI()win.mainloop()
爬取代碼?
import json
import urllib
from json import loadsfrom urllib import requestimport requests
from requests_html import HTMLSession
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import BymovieData = ' [' \'{"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":"災(zāi)難", "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":"戰(zhàn)爭", "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"}' \']'# 電影類型
def get_movie_top(m_type: str):"""排行榜查詢方法https://movie.douban.com/j/chart/top_list?type=&interval_id=100:90&action=unwatched&start=0&limit=:param m_type: 電影類型:param num: 爬取數(shù)量:param rating: 影片評分:param pj: 評價人數(shù):return:"""try: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(# m_type) + '&interval_id=100:90&action=unwatched&start=0&limit=' + str(num)# req = request.Request(url=url, headers=headers)# # 用于打開一個遠程的url連接,并且向這個連接發(fā)出請求,獲取響應(yīng)結(jié)果# f = request.urlopen(req)# # 獲取響應(yīng)對象# response = f.read()# # 將json轉(zhuǎn)為python對象# jsonData = loads(response)url = "https://movie.douban.com/j/chart/top_list"params = {"type": m_type,"interval_id": "100:90","action": "unwatched","start": "0",# 固定每次搜索條數(shù)為50條"limit": 50}resp = requests.get(url, headers=headers, params=params)jsonData = resp.json()movies_list = []# 循環(huán)獲取的電影信息并提取有效數(shù)據(jù)for subData in jsonData:# 將評分設(shè)定為大于1.0以上 評價人數(shù)大于100000if (float(subData['score']) >= float(1.0)) and (float(subData['vote_count']) >= float(100000)):movie = {"title": subData["title"],"rank": subData["rank"],"cover_url": subData["cover_url"],"types": "/".join(subData["types"]),"regions": subData["regions"][0],"release_date": subData["release_date"],"vote_count": subData["vote_count"],"score": subData["score"],"actors": "/".join(subData["actors"])}movies_list.append(movie)with open('movies.json', 'w', encoding='utf-8') as fp:json.dump(movies_list, fp, ensure_ascii=False, indent=2)return {'code': 200, 'movies': movies_list}except Exception as ex:err_str = "出現(xiàn)未知異常:{}".format(ex)return {'code': 500, 'msg': err_str}def get_movie_kw2(kw:str):params = {"search_text": "指環(huán)王","cat": "1002"}session = HTMLSession(browser_args=['--no-sand','--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'])resp = session.get("https://search.douban.com/movie/subject_search", params=params)resp.html.render()html = resp.html;movies_list = []divs = html.xpath("//div[@class='item-root'")print(divs)return movies_listdef get_movie_kw(kw: str):"""基于關(guān)鍵字查詢電影信息https://movie.douban.com/subject_search?search_text=&cat=1002:param kw::return:"""chrome_options = Options()# 設(shè)置為無頭模式,即不顯示瀏覽器chrome_options.add_argument('--headless')# 設(shè)置user=agentchrome_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"')# 此步驟很重要,設(shè)置為開發(fā)者模式,防止被各大網(wǎng)站識別出來使用了Selenium# chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])# # 不加載圖片,加快訪問速度# chrome_options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})# 加載chromedriver驅(qū)動是否成功load_driver_success = Falsebrowser = Nonetry:# 設(shè)置chromedriver驅(qū)動路徑browser = webdriver.Chrome(options=chrome_options)# 頁面加載超時時間為10sbrowser.set_page_load_timeout(10)# 頁面js加載超時時間為10sbrowser.set_script_timeout(10)load_driver_success = Trueexcept Exception as ex:load_driver_success = Falseerr_str = "加載chromedriver驅(qū)動失敗,請下載chromedriver驅(qū)動并填寫正確的路徑。\n\n異常信息:{}".format(ex)return {'code': 500, 'msg': err_str}if load_driver_success:# print(load_driver_success)try:url = 'https://search.douban.com/movie/subject_search?search_text=' + urllib.parse.quote(kw) + '&cat=1002'# print(url)# get方式獲取返回數(shù)據(jù)browser.get(url)# 通過樣式選擇器獲取滿足div.item-root要求的所有數(shù)據(jù)divs = browser.find_elements(By.CSS_SELECTOR, "div.item-root")movies_list = []for div in divs:movie = {"title": '',"rank": '',"cover_url": '',"types": '',"regions": '',"release_date": '',"vote_count": '',"score": '',"actors": ''}cover_url = div.find_elements_by_css_selector(".cover")# print(cover_url)if cover_url:movie["cover_url"] = cover_url[0].get_attribute("src")movie["title"] = cover_url[0].get_attribute("alt")rating = div.find_elements_by_css_selector("span.rating_nums")if rating:movie["score"] = rating[0].textpl = div.find_elements_by_css_selector("span.pl")if pl:movie["vote_count"] = pl[0].text.replace("(", "").replace(")", "").replace("人評價", "")regions = div.find_elements_by_css_selector("div.abstract")if regions:movie["regions"] = regions[0].textactors = div.find_elements_by_css_selector("div.abstract_2")if actors:movie["actors"] = actors[0].textmovies_list.append(movie)return {'code': 200, 'movies': movies_list}except Exception as ex:# 關(guān)閉瀏覽器browser.quit()err_str = "chromedriver驅(qū)動加載成功,但是Selenium獲取數(shù)據(jù)出現(xiàn)其他未知異常:{}".format(ex)return {'code': 200, 'msg': err_str}if __name__ == "__main__":# movies = get_movie_top("25", 20, 8.8, 100000)# movies = get_movie_kw("指環(huán)王")movies = get_movie_kw2("指環(huán)王")print(movies)# for m in movies['movies']:# print(m)
三、技術(shù)實現(xiàn)
tkinter 布局
json?? 獲取數(shù)據(jù)
thread? 線程
requests 模塊
selenium 爬取
四、總結(jié)
? ? ? ? 此次項目結(jié)合了許多之前學(xué)過的知識 有最基本的python語法 也有界面的融合 還有selenium數(shù)據(jù)的爬取 字典 集合 列表 函數(shù) 方法也有用到?
? ? ? ? 其實可以連接數(shù)據(jù)庫效果會更好 大家可以去嘗試一下