20192426 实验四《Python程序设计》实验报告

重要提醒:现在微博热搜界面已经删除了更新时间,所以在运行代码时请将Experiment4.py文件中的self.label_time.setText("{}".format(UpdateTime()))以及Ex4_func.py文件中的UpdateTime()函数部分注释掉,否则无法运行!!!

课程:《Python程序设计》
班级: 1924
姓名: 陈瀚文
学号: 20192426
实验教师:王志强
实验日期:2020年6月8日
必修/选修: 公选课

1.实验内容

Python综合应用:爬虫、数据处理、GUI

2. 实验过程及结果

实验过程:

  1. 本次作业可选内容较多,由于刚学习过爬虫的相关知识,所以我选择了爬虫作为我的实验方向,为了使结果更加清楚,所以我选择使用PyQt5来生成图形界面,我将爬取的目标定为微博的热搜榜和要闻榜(做到一半才发现微博热搜暂时停更整改,屮)。

  2. 首先,根据云班课中的教程,我使用如下指令下载了对应的模块。

    pip install requests
    pip install Beautifulsoup4 
    pip install PyQt5
    pip install PyQt5-tools
    
  3. 之后,我先完成了爬虫部分的函数,保存到Ex4_func.py中。

    • 在这一部分里,首先我导入了所需的模块,并定义了两个全局列表变量address_hot和address_news用于保存解析出来的链接并供其他函数使用。

      from bs4 import BeautifulSoup
      import requests
      import webbrowser	# 该库主要用于实现在默认浏览器中打开指定链接的功能
      import re
      
      address_hot = []
      address_news = []
      
    • 通过分析热搜的网页,我得出以下结论:

      • 热搜榜的序号在<td class="td-01 ranktop">标签中;

      • 热搜榜的正常内容在<td class="td-02>标签下的<a href>标签中,而带有标记“荐”的条目则在<td class="td-02>标签下的<a href_to>中,分析这部分信息时应当注意区分情况。

        • 上图为正常情况下的位置

        • 上图为带有“荐”标签情况下的位置
      • 热搜榜的标签分为“热”和“荐”,都在标签<td class="td-03>中;

      • 热搜榜的搜索量在标签<span>中;

    • 之后,根据以上分析,我完成了微博热搜部分的爬取和解析。

      def search_hot():
          """
          功能:定义函数爬取微博热搜榜信息,并返回元组的列表
          """
          url = 'https://s.weibo.com/top/summary/summary?cate=realtimehot'
          # 将爬虫伪装成浏览器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.44"}
          wb_data = requests.get(url, headers=headers)
          wb_data.encoding = "utf-8"
      
          soup = BeautifulSoup(wb_data.content, 'lxml')
          # 创立空列表 把热搜序号数据填入
          id = soup.find_all("td", class_='td-01')
          num = []
          for i in id:
              if i.text == '':
                  num.append("置顶")
              else:
                  num.append(i.text)
      
          # 创立空列表 把热搜内容填入
          hot = soup.find_all("td", class_='td-02')
          name = []
          for x in hot:
              name.append(x.a.text)
      
          # 把对应网址保存
          del address_hot[:]      # 保证列表中无上一次查询的记录
          pattern = r'/weibo?'
          for z in soup.find_all('a'):
              link = z.get('href')
              if re.match(pattern, link):
                  address_hot.append("https://s.weibo.com" + link)
              else:
                  link = z.get('href_to')
                  if link and re.match(pattern, link):
                      address_hot.append("https://s.weibo.com" + link)
      
          # 创立空列表 把热搜标签数据填入
          rank = []
          top = soup.find_all("td", class_='td-03')
          for y in top:
              rank.append(y.text)
      
          # 爬取搜索量
          total = ['']
          for k in soup.find_all('span'):
              total.append(k.text)
      
          result = list(zip(num, name, rank, total))
          return result
      
    • 随后,按照同样的方法,我分析得出微博要闻榜中的内容都保存在<td class="td-02>标签中。据此,我完成了微博要闻部分的爬取和解析。

      def search_news():
          """
          功能:爬取微博要闻榜
          """
          url = 'https://s.weibo.com/top/summary/summary?cate=socialevent'
          # 将爬虫伪装成浏览器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.44"}
          wb_data = requests.get(url, headers=headers)
          wb_data.encoding = "utf-8"
      
          soup = BeautifulSoup(wb_data.content, 'lxml')
          del address_news[:]     # 保证列表中无上一次查询的记录
          pattern = r'/weibo?'
          for z in soup.find_all('a'):
              link = z.get('href')
              if re.match(pattern, link):
                  address_news.append("https://s.weibo.com" + link)
              else:
                  link = z.get('href_to')
                  if link and re.match(pattern, link):
                      address_news.append("https://s.weibo.com" + link)
          result = []
          news = soup.find_all("td", class_='td-02')
          for i in news:
              result.append(i.a.text)
          return result
      
    • 接下来,观察到在热搜榜的最上端会显示“实时热点,更新于2020-6-10 15:00:00”,通过分析元素的方法发现它位于<p style="color:#999;margin:0 0 10px 28px">标签中,据此,爬取最后更新的时间。(已失效)

      '''def UpdateTime():
          """
          功能:爬取最后更新的时间
          """
          # 筛选数据最后一次的更新时间
          url = 'https://s.weibo.com/top/summary/summary?cate=realtimehot'
          # 将爬虫伪装成浏览器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.44"}
          wb_data = requests.get(url, headers=headers)
          wb_data.encoding = "utf-8"
          soup = BeautifulSoup(wb_data.content, 'lxml')
          p = soup.find_all("p", style="color:#999;margin:0 0 10px 28px")
          update = p[0].text
          return update'''
      
    • 最后,为了能够实现点击指定按钮弹出对应的网页内容,我定义了三个函数,完成了爬虫模块的编写。

      def search_hot_link(num):
          """
          功能:返回对应序号的热搜链接
          """
          return address_hot[num]
      
      
      def search_news_link(num):
          """
          功能:返回对应的要闻链接
          """
          return address_news[num]
      
      
      def openbrowser(a):
          """
          功能:打开指定外部链接
          """
          webbrowser.open(a)
      
    • Ex4_func.py 完整代码(码云直达):

      from bs4 import BeautifulSoup
      import requests
      import webbrowser  # 该库主要用于实现在默认浏览器中打开指定链接的功能
      import re
      
      address_hot = []
      address_news = []
      
      
      def search_hot():
          """
          功能:定义函数爬取微博热搜榜信息,并返回元组的列表
          """
          url = 'https://s.weibo.com/top/summary/summary?cate=realtimehot'
          # 将爬虫伪装成浏览器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.44"}
          wb_data = requests.get(url, headers=headers)
          wb_data.encoding = "utf-8"
      
          soup = BeautifulSoup(wb_data.content, 'lxml')
          # 创立空列表 把热搜序号数据填入
          id = soup.find_all("td", class_='td-01')
          num = []
          for i in id:
              if i.text == '':
                  num.append("置顶")
              else:
                  num.append(i.text)
      
          # 创立空列表 把热搜内容填入
          hot = soup.find_all("td", class_='td-02')
          name = []
          for x in hot:
              name.append(x.a.text)
      
          # 把对应网址保存
          del address_hot[:]  # 保证列表中无上一次查询的记录
          pattern = r'/weibo?'
          for z in soup.find_all('a'):
              link = z.get('href')
              if re.match(pattern, link):
                  address_hot.append("https://s.weibo.com" + link)
              else:
                  link = z.get('href_to')
                  if link and re.match(pattern, link):
                      address_hot.append("https://s.weibo.com" + link)
      
          # 创立空列表 把热搜标签数据填入
          rank = []
          top = soup.find_all("td", class_='td-03')
          for y in top:
              rank.append(y.text)
      
          # 爬取搜索量
          total = ['']
          for k in soup.find_all('span'):
              total.append(k.text)
      
          result = list(zip(num, name, rank, total))
          return result
      
      
      def search_news():
          """
          功能:爬取微博要闻榜
          """
          url = 'https://s.weibo.com/top/summary/summary?cate=socialevent'
          # 将爬虫伪装成浏览器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.44"}
          wb_data = requests.get(url, headers=headers)
          wb_data.encoding = "utf-8"
      
          soup = BeautifulSoup(wb_data.content, 'lxml')
          del address_news[:]  # 保证列表中无上一次查询的记录
          pattern = r'/weibo?'
          for z in soup.find_all('a'):
              link = z.get('href')
              if re.match(pattern, link):
                  address_news.append("https://s.weibo.com" + link)
              else:
                  link = z.get('href_to')
                  if link and re.match(pattern, link):
                      address_news.append("https://s.weibo.com" + link)
          result = []
          news = soup.find_all("td", class_='td-02')
          for i in news:
              result.append(i.a.text)
          return result
      
      
      '''def UpdateTime():
          """
          功能:爬取最后更新的时间
          """
          # 筛选数据最后一次的更新时间
          url = 'https://s.weibo.com/top/summary/summary?cate=realtimehot'
          # 将爬虫伪装成浏览器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.44"}
          wb_data = requests.get(url, headers=headers)
          wb_data.encoding = "utf-8"
          soup = BeautifulSoup(wb_data.content, 'lxml')
          p = soup.find_all("p", style="color:#999;margin:0 0 10px 28px")
          update = p[0].text
          return update'''
      
      
      def search_hot_link(num):
          """
          功能:返回对应序号的热搜链接
          """
          return address_hot[num]
      
      
      def search_news_link(num):
          """
          功能:返回对应的要闻链接
          """
          return address_news[num]
      
      
      def openbrowser(a):
          """
          功能:打开指定外部链接
          """
          webbrowser.open(a)
      
      
  4. 接下来是GUI部分,也是主函数部分(可以说这一部分也是耗时最长的一部分)。

    • 首先,我打开配置好的Qt Designer,按照云班课上的教程完成了主窗体的设计,保存为Experiment4.ui。

    • 之后,使用配置好的PyUIC生成了对应的python文件,如图。

    • 生成代码如下:

      1# -*- coding: utf-8 -*-
      2 
      3# Form implementation generated from reading ui file 'Experiment4.ui'
      4#
      5# Created by: PyQt5 UI code generator 5.15.0
      6#
      7# WARNING: Any manual changes made to this file will be lost when pyuic5 is
      8# run again.  Do not edit this file unless you know what you are doing.
      9 
      10
      11from PyQt5 import QtCore, QtGui, QtWidgets
      12
      13
      14class Ui_MainWindow(object):
      15	def setupUi(self, MainWindow):
      16		MainWindow.setObjectName("MainWindow")
      17		MainWindow.resize(960, 900)
      18		MainWindow.setMinimumSize(QtCore.QSize(960, 900))
      19		MainWindow.setMaximumSize(QtCore.QSize(960, 900))
      20		self.centralwidget = QtWidgets.QWidget(MainWindow)
      21		self.centralwidget.setObjectName("centralwidget")
      22		self.widget_query = QtWidgets.QWidget(self.centralwidget)
      23		self.widget_query.setGeometry(QtCore.QRect(0, 0, 960, 80))
      24		self.widget_query.setObjectName("widget_query")
      25		self.pushButton_hot = QtWidgets.QPushButton(self.widget_query)
      26		self.pushButton_hot.setGeometry(QtCore.QRect(280, 26, 200, 28))
      27		self.pushButton_hot.setObjectName("pushButton_hot")
      28		self.label_img = QtWidgets.QLabel(self.widget_query)
      29		self.label_img.setGeometry(QtCore.QRect(100, 26, 80, 27))
      30		self.label_img.setStyleSheet("")
      31		self.label_img.setText("")
      32		self.label_img.setPixmap(QtGui.QPixmap("WB_logo.png"))
      33		self.label_img.setObjectName("label_img")
      34		self.pushButton_news = QtWidgets.QPushButton(self.widget_query)
      35		self.pushButton_news.setGeometry(QtCore.QRect(600, 26, 200, 28))
      36		self.pushButton_news.setObjectName("pushButton_news")
      37		self.label_time = QtWidgets.QLabel(self.centralwidget)
      38		self.label_time.setGeometry(QtCore.QRect(50, 84, 900, 20))
      39		font = QtGui.QFont()
      40		font.setFamily("微软雅黑 Light")
      41		self.label_time.setFont(font)
      42		self.label_time.setText("")
      43		self.label_time.setObjectName("label_time")
      44		self.label_note = QtWidgets.QLabel(self.centralwidget)
      45		self.label_note.setGeometry(QtCore.QRect(660, 84, 260, 20))
      46		font = QtGui.QFont()
      47		font.setFamily("微软雅黑 Light")
      48		self.label_note.setFont(font)
      49		self.label_note.setObjectName("label_note")
      50		self.tableView_result = QtWidgets.QTableView(self.centralwidget)
      51		self.tableView_result.setGeometry(QtCore.QRect(30, 110, 900, 750))
      52    	self.tableView_result.setObjectName("tableView")
      53		MainWindow.setCentralWidget(self.centralwidget)
      54		self.statusbar = QtWidgets.QStatusBar(MainWindow)
      55		self.statusbar.setObjectName("statusbar")
      56		MainWindow.setStatusBar(self.statusbar)
      57			
      58		self.retranslateUi(MainWindow)
      59		QtCore.QMetaObject.connectSlotsByName(MainWindow)
      60		
      61	def retranslateUi(self, MainWindow):
      62		_translate = QtCore.QCoreApplication.translate
      63		MainWindow.setWindowTitle(_translate("MainWindow", "微博热搜"))
      64		self.pushButton_hot.setText(_translate("MainWindow", "热搜榜"))
      65		self.pushButton_news.setText(_translate("MainWindow", "要闻榜"))
      66		self.label_note.setText(_translate("MainWindow", "提示:双击具体标题可跳转至浏览器"))			
      

      需要注意的是,此时的代码仅仅是一个基本框架,仍需要添加代码使其具有完整功能。

    • 在添加代码部分,首先我在12行的位置补充导入了模块,代码如下:

      import sys
      from PyQt5.QtCore import Qt
      from PyQt5.QtGui import *
      from PyQt5.QtWidgets import *
      from Ex4_func import *  # 导入爬虫函数
      
    • 接下来,为了使得最后程序打包后能够正常显示图片,我将32行的图片路径改为绝对路径。

      32		self.label_img.setPixmap(QtGui.QPixmap("D:\\网空专业\\大一下\\Python程序设计\\Learnpython\\Experiment\\Experiment4\\WB_logo.png"))  # 设置微博logo
      
    • 在42行的位置,我调用了爬虫模块中的UpdateTime()函数以获取最后更新的时间并使其显示在label_time控件上(已失效)。

      # self.label_time.setText("{}".format(UpdateTime()))
      
    • 在43行与44行之间,我添加了一行代码来设置label_time字体的颜色

      self.label_time.setStyleSheet("color:#999")  # 设置字体颜色
      
    • 删除了46行、47行的冗余代码

    • 在49行、50行之间添加一行代码设置label_note字体的颜色

      self.label_note.setStyleSheet("color:#999")  # 设置字体颜色
      
    • 在52行、53行之间添加代码详细设置tableView_result控件的属性,主要包括设置大小不可改变、纵向表头不可见、表格内文字大小、设置表格内容不可编辑以及垂直滚动条始终开启。

      self.tableView_result.setMinimumSize(QtCore.QSize(900, 750))
      self.tableView_result.setMaximumSize(QtCore.QSize(900, 750))
      self.model = QStandardItemModel()
      # 纵向表头不可见
      self.tableView_result.verticalHeader().setVisible(False)
      # 设置表格内容文字大小
      font = QtGui.QFont()
      font.setPointSize(10)
      self.tableView_result.setFont(font)
      # 设置表格内容不可编辑
      self.tableView_result.setEditTriggers(QAbstractItemView.NoEditTriggers)
      # 垂直滚动条始终开启
      self.tableView_result.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
      
    • 在55行、56行之间添加代码绑定pushButton_hot、pushButton_news的单击事件,使得在单击按钮时显示对应的排行榜。

      self.pushButton_hot.clicked.connect(lambda: self.PushHot())  # 绑定pushButton_hot按钮的单机事件
      self.pushButton_news.clicked.connect(lambda: self.PushNews())  # 绑定pushButton_news按钮的单机事件
      
    • 之后,在下方定义方法DisplayTable1()来展示爬取到的热搜,定义DisplayTable2()来展示爬取到的要闻。

      def DisplayTable1(self, row, column, data):
          # 功能:让tableView_result控件展示爬取的热搜
          self.model.clear()
          for a in range(row):
              for b in range(column):
                  # 添加表格内容
                  item = QStandardItem(data[a][b])
                  item.setTextAlignment(Qt.AlignCenter)
                  # 向表格存储模式中添加表格具体信息
                  self.model.setItem(a, b, item)
              # 设置表格存储数据的模式
              self.tableView_result.setModel(self.model)
      
      def DisplayTable2(self, row, data):
          # 功能:让tableView_result控件展示爬取的要闻
          self.model.clear()
          for a in range(row):
              # 添加表格内容
              item = QStandardItem(data[a])
              item.setTextAlignment(Qt.AlignCenter)
              id = QStandardItem("{}".format(a + 1))
              id.setTextAlignment(Qt.AlignCenter)
              # 向表格存储模式中添加表格具体信息
              self.model.setItem(a, 0, id)
              self.model.setItem(a, 1, item)
          # 设置表格存储数据的模式
          self.tableView_result.setModel(self.model)
      
    • 然后再定义上文中单击事件绑定的PushHot()、PushNews()方法,在其中设置表头、列宽并绑定tableView_result的双击事件,使用try……except语句来防止绑定多次。

      def PushHot(self):
              result_h = search_hot()
              self.DisplayTable1(len(result_h), len(result_h[0]), result_h)
              self.model.setHorizontalHeaderLabels(['序号', '内容', '标签', '热度'])
              self.tableView_result.setColumnWidth(0, 50)
              self.tableView_result.setColumnWidth(1, 670)
              self.tableView_result.setColumnWidth(2, 50)
              self.tableView_result.setColumnWidth(3, 100)
              try:
                  self.tableView_result.doubleClicked.disconnect()    # 防止将self.table_openhotlink()绑定多次
              except:
                  pass
              self.tableView_result.doubleClicked.connect(lambda: self.table_openhotlink())  # 绑定tableView_result的双击事件
      
      def PushNews(self):
          result_n = search_news()
          self.DisplayTable2(len(result_n), result_n)
          self.model.setHorizontalHeaderLabels(['序号', '内容'])
          self.tableView_result.setColumnWidth(0, 50)
          self.tableView_result.setColumnWidth(1, 820)
          try:
              self.tableView_result.doubleClicked.disconnect()    # 防止将self.table_opennewslink()绑定多次
          except:
              pass
          self.tableView_result.doubleClicked.connect(lambda: self.table_opennewslink())  # 绑定tableView_result的双击事件
      
    • 接下来定义上文中双击事件绑定的方法table_openhotlink()、table_opennewslink(),使得在双击列表中的热搜内容时打开浏览器并定位到对应的网页,在这里调用了openbrowser()函数。

      def table_openhotlink(self):
          # 功能:根据tableView_result中双击的位置打开对应的热搜链接
          row = self.tableView_result.currentIndex().row()
          link = search_hot_link(row)
          openbrowser(link)
      
      def table_opennewslink(self):
          # 功能:根据tableView_result中双击的位置打开对应的要闻链接
          row = self.tableView_result.currentIndex().row()
          link = search_news_link(row)
          openbrowser(link)
      
    • 最终,定义函数显示主窗体,并定义程序入口,完成了主函数的部分,实现了全部的功能。

      def show_MainWindow():
          """
          功能:显示主窗体
          """
          app = QtWidgets.QApplication(sys.argv)
          MainWindow = QtWidgets.QMainWindow()
          ui = Ui_MainWindow()
          ui.setupUi(MainWindow)
          MainWindow.setWindowIcon(QIcon("D:\\网空专业\\大一下\\Python程序设计\\Learnpython\\Experiment\\Experiment4\\icon_wb.ico"))  # 设置程序图标
          MainWindow.show()
          sys.exit(app.exec_())
      
      
      if __name__ == "__main__":
          # 程序入口
          show_MainWindow()
      
    • Experiment4.py 完整代码(码云直达):

      # -*- coding: utf-8 -*-
      
      # Form implementation generated from reading ui file 'Experiment4.ui'
      #
      # Created by: PyQt5 UI code generator 5.15.0
      #
      # WARNING: Any manual changes made to this file will be lost when pyuic5 is
      # run again.  Do not edit this file unless you know what you are doing.
      
      
      from PyQt5 import QtCore, QtGui, QtWidgets
      import sys
      from PyQt5.QtCore import Qt
      from PyQt5.QtGui import *
      from PyQt5.QtWidgets import *
      from Ex4_func import *  # 导入爬虫函数
      
      
      class Ui_MainWindow(object):
          def setupUi(self, MainWindow):
              MainWindow.setObjectName("MainWindow")
              MainWindow.resize(960, 900)
              MainWindow.setMinimumSize(QtCore.QSize(960, 900))
              MainWindow.setMaximumSize(QtCore.QSize(960, 900))
              self.centralwidget = QtWidgets.QWidget(MainWindow)
              self.centralwidget.setObjectName("centralwidget")
              self.widget_query = QtWidgets.QWidget(self.centralwidget)
              self.widget_query.setGeometry(QtCore.QRect(0, 0, 960, 80))
              self.widget_query.setObjectName("widget_query")
              self.pushButton_hot = QtWidgets.QPushButton(self.widget_query)
              self.pushButton_hot.setGeometry(QtCore.QRect(280, 26, 200, 28))
              self.pushButton_hot.setObjectName("pushButton_hot")
              self.label_img = QtWidgets.QLabel(self.widget_query)
              self.label_img.setGeometry(QtCore.QRect(100, 26, 80, 27))
              self.label_img.setStyleSheet("")
              self.label_img.setText("")
              self.label_img.setPixmap(QtGui.QPixmap("D:\\网空专业\\大一下\\Python程序设计\\Learnpython\\Experiment\\Experiment4\\WB_logo.png"))  # 设置微博logo
              self.label_img.setObjectName("label_img")
              self.pushButton_news = QtWidgets.QPushButton(self.widget_query)
              self.pushButton_news.setGeometry(QtCore.QRect(600, 26, 200, 28))
              self.pushButton_news.setObjectName("pushButton_news")
              self.label_time = QtWidgets.QLabel(self.centralwidget)
              self.label_time.setGeometry(QtCore.QRect(50, 84, 900, 20))
              font = QtGui.QFont()  # 设置字体
              font.setFamily("微软雅黑 Light")
              self.label_time.setFont(font)
              # self.label_time.setText("{}".format(UpdateTime())) 已失效
              self.label_time.setObjectName("label_time")
              self.label_time.setStyleSheet("color:#999")  # 设置字体颜色
              self.label_note = QtWidgets.QLabel(self.centralwidget)
              self.label_note.setGeometry(QtCore.QRect(660, 84, 260, 20))
              self.label_note.setFont(font)
              self.label_note.setObjectName("label_note")
              self.label_note.setStyleSheet("color:#999")  # 设置字体颜色
              self.tableView_result = QtWidgets.QTableView(self.centralwidget)
              self.tableView_result.setGeometry(QtCore.QRect(30, 110, 900, 750))
              self.tableView_result.setMinimumSize(QtCore.QSize(900, 750))
              self.tableView_result.setMaximumSize(QtCore.QSize(900, 750))
              self.tableView_result.setObjectName("tableView")
              self.model = QStandardItemModel()
              # 纵向表头不可见
              self.tableView_result.verticalHeader().setVisible(False)
              # 设置表格内容文字大小
              font = QtGui.QFont()
              font.setPointSize(10)
              self.tableView_result.setFont(font)
              # 设置表格内容不可编辑
              self.tableView_result.setEditTriggers(QAbstractItemView.NoEditTriggers)
              # 垂直滚动条始终开启
              self.tableView_result.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
              MainWindow.setCentralWidget(self.centralwidget)
              self.statusbar = QtWidgets.QStatusBar(MainWindow)
              self.statusbar.setObjectName("statusbar")
              self.pushButton_hot.clicked.connect(lambda: self.PushHot())  # 绑定pushButton_hot按钮的单机事件
              self.pushButton_news.clicked.connect(lambda: self.PushNews())  # 绑定pushButton_news按钮的单机事件
              MainWindow.setStatusBar(self.statusbar)
              self.retranslateUi(MainWindow)
              QtCore.QMetaObject.connectSlotsByName(MainWindow)
      
          def retranslateUi(self, MainWindow):
              _translate = QtCore.QCoreApplication.translate
              MainWindow.setWindowTitle(_translate("MainWindow", "微博热搜"))
              self.pushButton_hot.setText(_translate("MainWindow", "热搜榜"))
              self.pushButton_news.setText(_translate("MainWindow", "要闻榜"))
              self.label_note.setText(_translate("MainWindow", "提示:双击具体标题可跳转至浏览器"))
      
          def DisplayTable1(self, row, column, data):
              # 功能:让tableView_result控件展示爬取的热搜
              self.model.clear()
              for a in range(row):
                  for b in range(column):
                      # 添加表格内容
                      item = QStandardItem(data[a][b])
                      item.setTextAlignment(Qt.AlignCenter)
                      # 向表格存储模式中添加表格具体信息
                      self.model.setItem(a, b, item)
              # 设置表格存储数据的模式
              self.tableView_result.setModel(self.model)
      
          def DisplayTable2(self, row, data):
              # 功能:让tableView_result控件展示爬取的要闻
              self.model.clear()
              for a in range(row):
                  # 添加表格内容
                  item = QStandardItem(data[a])
                  item.setTextAlignment(Qt.AlignCenter)
                  id = QStandardItem("{}".format(a + 1))
                  id.setTextAlignment(Qt.AlignCenter)
                  # 向表格存储模式中添加表格具体信息
                  self.model.setItem(a, 0, id)
                  self.model.setItem(a, 1, item)
              # 设置表格存储数据的模式
              self.tableView_result.setModel(self.model)
      
          def PushHot(self):
              result_h = search_hot()
              self.DisplayTable1(len(result_h), len(result_h[0]), result_h)
              self.model.setHorizontalHeaderLabels(['序号', '内容', '标签', '热度'])
              self.tableView_result.setColumnWidth(0, 50)
              self.tableView_result.setColumnWidth(1, 670)
              self.tableView_result.setColumnWidth(2, 50)
              self.tableView_result.setColumnWidth(3, 100)
              try:
                  self.tableView_result.doubleClicked.disconnect()    # 防止将self.table_openhotlink()绑定多次
              except:
                  pass
              self.tableView_result.doubleClicked.connect(lambda: self.table_openhotlink())  # 绑定tableView_result的双击事件
      
          def PushNews(self):
              result_n = search_news()
              self.DisplayTable2(len(result_n), result_n)
              self.model.setHorizontalHeaderLabels(['序号', '内容'])
              self.tableView_result.setColumnWidth(0, 50)
              self.tableView_result.setColumnWidth(1, 820)
              try:
                  self.tableView_result.doubleClicked.disconnect()    # 防止将self.table_opennewslink()绑定多次
              except:
                  pass
              self.tableView_result.doubleClicked.connect(lambda: self.table_opennewslink())  # 绑定tableView_result的双击事件
      
          def table_openhotlink(self):
              # 功能:根据tableView_result中双击的位置打开对应的热搜链接
              row = self.tableView_result.currentIndex().row()
              link = search_hot_link(row)
              openbrowser(link)
      
          def table_opennewslink(self):
              # 功能:根据tableView_result中双击的位置打开对应的要闻链接
              row = self.tableView_result.currentIndex().row()
              link = search_news_link(row)
              openbrowser(link)
      
      
      def show_MainWindow():
          """
          功能:显示主窗体
          """
          app = QtWidgets.QApplication(sys.argv)
          MainWindow = QtWidgets.QMainWindow()
          ui = Ui_MainWindow()
          ui.setupUi(MainWindow)
          MainWindow.setWindowIcon(QIcon("D:\\网空专业\\大一下\\Python程序设计\\Learnpython\\Experiment\\Experiment4\\icon_wb.ico"))  # 设置程序图标
          MainWindow.show()
          sys.exit(app.exec_())
      
      
      if __name__ == "__main__":
          # 程序入口
          show_MainWindow()
      
      
  5. 最后使用pyinstaller打包生成exe文件,以便之后的运行。

    pyinstaller -i icon_wb.ico -Fw Experiment4.py -p D:/网空专业/大一下/Python程序设计/Learnpython/Experiment/Experiment4/Ex4_func.py -p D:/Python3/Lib/site-packages/PyQt5/Qt/bin -p D:/Python3/Lib/site-packages -p D:/Python3/Lib
    

    打包截图如下:

实验结果:

  • 图1 刚进入程序时的界面

  • 图2 热搜榜界面

  • 图3 要闻榜界面

  • 由于无法上传视频,故在此处对于双击内容后打开默认浏览器并跳转到指定页面不做展示,详情请见程序演示视频。

3. 实验过程中遇到的问题和解决过程

  • 问题1:爬取界面上的元素时无从下手
  • 问题1解决方案:仔细观察网页源代码,并从中定位相应数据所在标签,使用bs4中的find_all方法来查找对应的标签,从中提取数据
  • 问题2:对于爬取到的链接无法直接打开
  • 问题2解决方案:通过观察发现爬取的链接没有开头部分,即https://s.weibo.com,故将爬取的链接进行处理,使其拼接成一个完整的网址。
  • 问题3:对于PyQt5的使用不是非常清楚,对于绑定事件、设置字体属性等问题无法解决
  • 问题3解决方案:查阅博客等各种资料,查看官方文档,最终通过PyQt5中的方法解决了这些问题
  • 问题4:使用pyinstaller打包程序的时候生成的程序出现错误,无法打开
  • 问题4解决方案:通过搜索了解到需要给pyinstaller指定路径,于是添加了路径参数,从而解决了该问题。

其他(感悟、思考等)

  1. 实验感想:此次的实验是整个python课程学习中综合性最强的一次,可以说挑战性非常强,与此同时,我收获的知识也非常地多,我首次了解了GUI编程的相关知识,并通过编写爬虫程序加深了我对于HTML的认识,通过此次实验,我初步掌握了从网站中获取相关信息的具体方法。此外,在GUI编程阶段有许多问题在百度里也找不到有用的信息,最后只能采取阅读官方文档并自己动手尝试的方式来解决,在此过程中,也极大地锻炼了我的英语水平以及实践能力,我突然意识到过去的依赖CSDN等博客的方式固然能够解决问题,但其中却少了一分自己的思考,长此以往便造成了思维定式,也增加了对他人的依赖,所以我应当在参考别人的同时,通过自己亲自动手实践、缜密思考来得出更好的解决问题的方法,这样才能在要求多变的编程题目中找出其中核心的不变之处,从而更加高效地解决实际问题,提高自己的编程能力。
  2. 课程总结:由于在上学期的时候接触过一部分python的知识,本学期我便选择了python程序设计这门课,希望能够更深入地了解python这门程序语言,掌握编程的本领。相比于我同时在学习的C语言来说,python具有简洁、高效的特征,使用python,你不需要关心各种函数、方法的底层实现,你所需要做的是将这些高效的工具有机地结合在一起,实现复杂的功能,可以说,python语言比C语言对新手更加友好,通过它那庞大的第三方库,几乎任何问题都能够被它所解决,虽然课程已经接近尾声,但是我会记住这些学习新知识的方法,在将来更加深入地对python进行学习。
  3. 课程感想:本学期的课采用翻转课堂加老师讲解的方式进行,这种方法十分新颖,不仅加深了我对于知识点的理解,还使我可以提出更加有价值的问题,使得时间的利用变得非常合理。在讲课过程中,王志强老师给我留下了十分深刻的印象,他很擅长和学生打成一片,并且他还很在意和学生进行互动,这样既保证了上课的效率,也营造了一种轻松愉快的学习氛围,而在作业方面,王老师要求我们今日事今日毕,使得我逐渐克服了做事拖沓的习惯,他在作业中留下的彩蛋项目也是我更加有学习python的动力,他鼓励我们在学编程的过程中每天背单词,我的英语水平也在逐渐地提高,总而言之,王志强老师是一位非常好的老师,他不仅在python方面引导我深入地学习,同时他也使我做一个更好的自己,每天都能有进步,每天都有新的收获。这段学习python的时光连同王老师对我的教导,我会始终铭记在心。
  4. 课程建议:建议老师每次课上随机抽取几个同学的作业进行点评,以便我们能够更加地完善自己的知识体系,同时也可以从别人的代码中学习一些自己未曾想到的思路,进而提高同学们的编程水平,使得解决问题的方式更加多样化。希望继续保留翻转课堂加老师讲解的教学模式。

参考资料

posted @ 2020-06-13 02:55  20192426陈瀚文  阅读(299)  评论(0编辑  收藏  举报