软件工程期末复习【爬虫代码】

软件工程

一、软件工程复习主线

软件工程的学习和复习一定要抓住下面三条主线:

1.需求分析与设计。如何精确理解用户的需求,将需求转化为可实现的软件设计方案。

这方面的知识点涉及到:学习掌握绘制各类图(用例图,数据流图,状态图,顺序图,类图等等...),理解各类图的分类、作用、适用场景是最重要的。

2.质量保证。如何减少和预防软件中的错误和缺陷,提高软件的可靠性、稳定性。

这方面的知识点主要涉及到:各类测试至少要掌握黑盒测试、白盒测试等基本测试方法的原理和执行过程。

3.项目管理。如何确保软件项目能够按照预期的进度推进,避免时间和资源的浪费。

这方面的知识点主要涉及到:各类开发方式模型(过程模型,瀑布模型,敏捷开发等...)的特点和适用场景。

上三点不仅是考试的重点,也是实际开发中需要注意的要点。因而本文主要围绕上面三点展开,着眼于提升核心能力。

二、需求分析与设计

1.请画图从四个维度标明需求分析建模的各主要模型元素及主要图表模型

图的本质是将信息可视化,变得直观,方便人与人交流。不同的图,有不同的作用和适用场景,同学们要仔细理解。

基于场景的元素:用例文本(图1),用例图(图2),活动图,泳道图(图3)。

  

(友情提示:画图须重视,请仔细理解上图细节。)

用例文本:

包含用例名称,描述,触发条件,主要场景,其它场景等,主要是基于不同的场景分析可能发生的情况。可以让团队更好理解和实现系统的功能。

(重点1) 用例图:

主要描述参与者与用例(功能)间的关系。展现了系统的功能性需求,每个用例代表一个特定的用户需求或功能。

绘制注意事项:要画参与者(就是那个小人),要画边界(就是那个方框),要考虑用例间的关系(比如退课包含退款,要用:虚线箭头 + <<include>>标记出来,关系有:关联,包含,扩展,泛化)

泛化其实是继承关系,除了关联,最常用的是包含关系(一定要记住)。请参考下图理解:

推荐参考博客:

用例图详解-CSDN博客

泳道图:

用于可视化多个参与者之间的协作和交互。每条泳道代表一个角色、部门或系统组件,用于表现过程中的责任和活动。适用于展现业务流程和跨部门工作的流程。

矩形中是一般的操作,菱形中是判断。

活动图:

一张活动图可划分成若干个矩形区,每个矩形区为一个泳道,泳道名放在矩形区的顶端。通常根据责任把活动组织到不同的泳道中,它能清楚地表明动作在哪里执行(在哪个对象中),或者表明一个组织的哪部分工作(一个动作)被执行。

请注意每个活动用圆角矩形来表示。

在活动图中用黑体线来表示迁移的分解和合并。

面向信息流的元素:数据流图(图1),控制流图(图2),处理说明。

(友情提示:画图须重视,请仔细理解上图细节。)

(重点2) 数据流图:

包含数据流、处理器、数据存储和外部实体等元素。是用于可视化数据流动和处理的图形工具,可以描述信息在系统中的传递和转换。可分为多个层级,比如0层、1层等,由上至下逐步细化。

绘制注意事项:试卷上绘图时一般采用红框里的符号书写。

示例如下(左图L0层图,右图L1层图):

绘图技巧:

1.最重要的是要读清楚题目的描述,确定有哪些主体,需要哪些存储文件,有哪些数据流。明确完基本的组成部分之后再考虑其间的关系。

2.考虑主体的时候要考虑一些比较隐蔽的身份,题目中可能没具体说,比如学员分为会员和非会员,不同的身份可以获得不同的权限。只有在顶层图中需要画出这些主体,用矩形框。

2.然后要考虑数据流,包括:输入数据流,输出数据流,额外的输出流(考虑健壮性)。注意在L1层图中每个圆形框(加工),都有流入数据和流出数据,流入数据要有名字。在L1层图中不必画出主体。

控制流图:

包含操作、条件、循环、分支和连接线等元素。用于描述系统中的操作、函数或过程之间的控制流程的顺序关系。

行为元素:状态图(图1),顺序图(图2)

(友情提示:画图须重视,请仔细理解上图细节。)

状态图:

包含状态、状态转换、事件、动作和条件等元素。用于描述对象在生命周期内的各种状态以及状态之间的转换。可以帮助开发人员理解对象的行为和状态转换的逻辑。

状态图符号如下:

请注意每个状态用圆角矩形来表示。

状态机图示例如下:

(重点3) 顺序图:

包含对象、生命线、消息、返回消息等。用于描述对象之间的交互和消息传递,关注对象之间的交互顺序和生存时间。可以帮助开发人员理解系统中的消息流和对象间的相互作用。

顺序图网上的资料很多,可自行查阅,是常考的重点。

基于类的元素:类图(图1),包图(图2),CRC模型,协作图

 

(友情提示:画图须重视,请仔细理解上图细节。)

类图:

包含类、属性、关系和方法等。是用于可视化系统静态结构的图形工具。可以描述类、对象及其之间的关系(继承、关联),帮助开发人员理解系统的组织结构和数据模型。

 

绘制注意事项:可以用中文。对应的数量关系要标识(1对1,1对多,多对多,多用*)。

画图时将聚集和组合的符号画在整体上。

组合比聚集关系更强,在组合中部分是依赖(从属)于整体而生存。

比如翅膀和鸟是组合关系,如果没有了鸟就没有翅膀,翅膀是依赖鸟而存在的。

又比如大雁和雁群是聚集关系,如果没有了雁群,大雁依旧可以独自存在。

下面这个依赖的例子不错:

包图:

包是组织和管理类和用例的容器,包图可以让模型的结构变得清晰,方便维护。

2.简述用户需求建模主要包括哪些重要方法及主要特点

结构化方法:

采用数据流图,描述系统内部的数据流动和处理过程。

注重数据和处理分析,强调对数据的处理和分析,目的是理解系统中数据流和数据处理。

(补充:数据流图归属于结构化方法,是因为它划分了多个层次,逐层细化)

面向对象方法:

静态模型(类和对象关系):对应类图。

动态模型(对象的行为和状态的演化):对应状态机图和时序图。

功能模型(系统的功能和用例):对应用例图。

面向对象关注对象的抽象和建模,系统的功能和数据都以对象的形式表示。注重对象间的交互和信息传递,关注对象的行为和状态。

3.数据字典

数据字典由字典条目组成,每个条目描述数据流图中的一个元素。

数据字典条目包括:数据流、文件、数据项(组成数据流和文件的数据)、加工、源或宿

数据字典:以文字的形式对数据,加工,控制规范进行描述。分别用实体-关系图,数据流图,状态转换图进行描述。

三、质量保证

3.1 白盒测试

白盒测试要求测试者了解代码的具体实现细节,因此能够对条件、分支和语句等进行测试。

比较重要的考点是:逻辑覆盖测试。

逻辑覆盖测试包含:路径覆盖,语句覆盖,条件覆盖,判定覆盖,判定/条件覆盖,条件组合覆盖。

通俗来说:

1.语句是一行行的代码。

— 语句覆盖就是要让测试用例能覆盖每一行代码。

2.判定是判定真或假,像分支结构中的if语句、switch语句或者循环控制语句(for、while、do-while)中的条件成立或不成立的情况。

— 判定覆盖就是要让测试用例能覆盖每一个if、switch、循环语句中括号内的成立和不成立(真/假)的情况,比如覆盖if(a>b && a!=c)括号内为true或false的情况。

3.条件是构成判定的单个元素,比如比较表达式(a>b,x==y等)。

— 条件覆盖就是要让单个条件每个可能结果都被评估一次,比如:a==b成立或不成立。

路径覆盖就是要求覆盖测试程序中所有可能的执行路径。

其中最爱考也是最常考的是:路径覆盖测试,因为这是最严格的覆盖标准,需要考虑所有可能的分支组合情况,一个不小心就会错漏,一般还会和画图(流程图)进行结合,难度比较大。

例1.请用基本路径测试方法为下列程序设计测试用例,并写明中间过程:

下面这道题是典型的给出程序,要求用路径覆盖测试的题目:

第1步:画出流程图

首先要分析题目中的分支数,本题是5个。

1.菱形用于条件判断。用在有分支的地方。

2.矩形表示一个基本操作。

3.圆形是连接点

第2步:计算程序环路复杂性

计算方法1:流图G的环路复杂度V(G)定义为:V(G)=E-N+2 (E为流图中的边数量,N为流图中的节点数量)。

计算方法2(常用):V(G)也可以定义为:V(G)=P+1 其中:P为流图中的判断节点数量。

第3步:给出独立路径集

需要注意的是:路径集对每个循环至多只执行一次,所以第2次不会进入已经进入过的循环中。

(1)2.1 - 2.2.1 - 2.2.2 - 15 - 16

表示不满足i-1后大于等于0,即i-1后小于0,于是直接15,16退出。

(2)2.1 - 2.2.1 - 3 - 4.1 - 4.2 - 12 - 13 - 16

表示i-1后等于0,即i原本为1,即数组中只有1个数,i-1后i值为0,因为j=0,所以不满足j<i,直接退出循环,直接进入12,13,16退出

(3)2.1 - 2.2.1 - 2.2.2 - 3 - 4.1 - 4.2 - 5 - 10 - 4.3 - 4.2 - 12 - 13 - 16

(4)2.1 - 2.2.1 - 2.2.2 - 3 - 4.1 - 4.2 - 5 - 10 - 4.3 - 4.2 - 12 - 2.2.1 - 2.2.2 - 15 - 16

(5)2.1 - 2.2.1 - 2.2.2 - 3 - 4.1 - 4.2 - 5 - 6,7,8,9 - 10 - 4.3 - 4.2 - 12 - 13 - 16

(6)2.1 - 2.2.1 - 2.2.2 - 3 - 4.1 - 4.2 - 5 - 6,7,8,9 - 10 - 4.3 - 4.2 - 12 - 2.2.1 - 2.2.2 - 15 - 16

第4步:测试用例

(1)输入空值

(2)输入只有一个元素的数组,比如数组[3]

(3)输入升序排序的数组,比如数组[2,3,6,9]

(4)同样也是输入升序排序的数组,比如数组[2,3,6,9]

(5)输入数组[1,5,2]

(6)输入降序排序的数组,比如数组[9,5,3,2]

3.2 黑盒测试

黑盒测试要求测试者看不到代码的具体实现细节,因此只能通过单纯的输入数据,检视输出的结果来判断程序是否正确。

比较重要的考点是:等价类划分。

看下面这道考题:

根据题意列出有效等价类和无效等价类,所谓有效等价类就是能返回正确结果的,无效等价类就是会返回错误结果的:

写出输入数据,也就是测试用例;写出能覆盖的等价类;写出预期的结果:

对有效等价类,只需要一个测试用例即可;然后对于无效等价类,需要逐个设置测试用例。

四、项目管理

1.软件生存周期:

需求分析,设计,编码,测试,运行,维护。

2.软件过程模型:

瀑布模型

后一阶段必须依赖前一阶段,因此开发时间长,缺乏灵活性。要求需求相对明确且稳定。体系结构的风险和错误只有在测试阶段才能发现。以文档为驱动。

原型模型

原型:是指模拟某种产品的原始模型。软件原型是一个早期可以运行的版本,它反映最终系统的部分重要特性。

快速构建原型,交付给顾客使用,获得反馈意见,在下一轮迭代中对原型进行改进,周而复始,直到产品满足用户需求。

可以在制作原型的过程中逐步明确需求,进行学习,探索更多可行性。

分为:探索型(弄清对目标系统的要求),实验型(系统实现前考察系统的可行性),进化型(将原型扩展到开发过程,通过原型开发逐步实现所有系统功能)。

但容易忽视文档,较难规划管理,做多余工作。

演化模型

演化模型主要针对需求不太明确的软件项目。

要求快速构造出软件的可运行版本,谓之原型。进过多次迭代,逐步完善,形成最终产品。

增量模型

要求每一次的增量都要是一个可运行的版本,后续工作是在先前版本的基础上修改和补充。

增量模型融合了瀑布模型的基本成分和演化模型的迭代特征。

允许客户的需求可以逐步提出,会对需求按优先级进行排列,每一次增量版本优先对重要需求进行实现。

适用于需求经常变化的软件开发,可以快速开发,提供可运行的产品投入市场,逐步完善。可以降低项目的风险。

螺旋模型

逐步求精:这是一种开发过程,其中软件或项目从一个非常基本的初始版本开始,随着时间的推移不断改进和增加功能。在每个迭代中,系统都会增加新功能或改进现有功能。这个过程强调的是功能的增加和系统能力的扩展。

螺旋模型主要针对大型软件项目,存在多种风险问题,因此增加了风险分析,是瀑布模型和演化模型的结合(因为在风险分析阶段提供有原型)。

将开发分为四个象限:

制定计划:确定软件目标,选定实施方案,弄清项目开发的限制条件。

风险分析:分析所选方案,考虑如何识别和消除风险。

工程实施:实施软件开发。

客户评估:评价开发工作,提出修正建议。

敏捷开发

敏捷方法的主要特点就是具有快速及灵活的响应变更的能力。

敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。

在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。

 顾客和开发人员必须相互合作;必须经常交付可运行的软件;欣然面对需求变化。

见下图敏捷开发最常用的工程方法是Scrum:

三种角色:

三种工件:

取出一个产品待定项(一般在3-4周时间内完成),细化为若干冲刺任务,团队一般在1天的时间内完成一个冲刺任务,进行功能展示,每天进行15分钟例会,反思工作。

3.可行性分析

分析角度:

经济可行性:包括:成本(人员,硬件,场地,开发等成本)、效益(经济效益,社会效益)、

技术可行性:包括:风险分析、资源分析、技术分析。

法律可行性。

4.设计工程

软件设计原则:抽象与逐步求精;模块化;信息隐藏;功能独立。

逐步求精:这是一种开发过程,其中软件或项目从一个非常基本的初始版本开始,随着时间的推移不断改进和增加功能。在每个迭代中,系统都会增加新功能或改进现有功能。这个过程强调的是功能的增加和系统能力的扩展。

爬虫:

1.获取网页的html模板:

# 导入所需的Python第三方库
import urllib3
import certifi
import chardet

def getHtml(url):
    http = urllib3.PoolManager(ca_certs=certifi.where())
    r = http.request('GET', url)
    htmlStr = ""
    #判断是否爬取成功,200表示成功
    if (r.status == 200):
        encoding = chardet.detect(r.data)['encoding']
        htmlStr = r.data.decode(encoding)
    # 打印爬取的html页面内容
    print(htmlStr)

if __name__=='__main__':
    # 本实验采用下面知乎的一个公开页面作为示例
    url=r'https://weibo.com/'
    # 调用爬取URL的函数
    html = getHtml(url)

2.自动登录微博的登录界面,输入用户名和密码登录跳转。

import time
from selenium import webdriver
def LoginWeibo(username, password):
    try:
        # 初始化 Chrome driver, 确保你已经下载了Chrome的WebDriver,并且放置在可访问的位置
        driver = webdriver.Chrome()
        print('准备登陆weibo.cn网站...')
        driver.get("http://weibo.com/login.php")
        time.sleep(3)
        # 修正拼写错误
        elem_user = driver.find_element_by_xpath('//*[@id="loginname"]')
        elem_user.send_keys(username)
        elem_pwd = driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[2]/div/input')
        elem_pwd.send_keys(password)
        elem_sub = driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a')
        elem_sub.click()
        time.sleep(10)
        elem_sub.click()
        time.sleep(10)
    except Exception as e:
        print(e)
    finally:
        pass
# 测试代码
username = '17359456898'
password = 'Panbinjie201314'
LoginWeibo(username, password)

3.自动在微博主页搜索关键字并且搜索,返回搜索结果页面。

import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

def LoginWeibo(key):
    try:
        driver = webdriver.Chrome()
        driver.get("http://s.weibo.com/")

        print('搜索热点主题:')
        time.sleep(1)
        item_cli = driver.find_element_by_xpath('//*[@id="searchapps"]/div/div[1]/div/div/div[1]/div/div[1]')
        item_cli.click()
        item_inp = driver.find_element_by_xpath("//input[@type='text']")
        item_inp.send_keys(key)
        time.sleep(1)
        item_inp.send_keys(Keys.RETURN)
        time.sleep(10)
    except Exception as e:
        print(e)
    finally:
        pass

key = "#蔡徐坤#"
LoginWeibo(key)

4.下面这段代码可以返回CSDN主页所有的图片连接:

# 导入所需的Python第三方库
import certifi
import urllib3
from bs4 import BeautifulSoup

def getImg(html):
    soup = BeautifulSoup(html, 'html.parser')
    img_tags = soup.find_all('img')
    imglist = [img.get('src') for img in img_tags]
    print(imglist)
def getHtml(url):
    http = urllib3.PoolManager(ca_certs=certifi.where())
    r = http.request('GET', url)
    htmlStr = ""
    #判断是否爬取成功,200表示成功
    if (r.status == 200):
        htmlStr=r.data.decode('utf-8') # 取出爬取的页面内容
    # 打印爬取的html页面内容
    # print(htmlStr)
    return htmlStr


if __name__=='__main__':
    url = r'https://www.csdn.net/'
    html = getHtml(url)
    if(len(html)!=0):
        getImg(html)

5.从网页上爬取图片保存在本地文件夹

# 导入所需的Python第三方库
import certifi
import urllib3
import wget
import re
from bs4 import BeautifulSoup

def saveImage(imglist):
    number = 0
    http = urllib3.PoolManager(ca_certs=certifi.where())

    for imageURL in imglist:
        print(imageURL)
        # 以下用正则表达式匹配URL
        if not imageURL:  # 检查 imageURL 是否为空或者 None
            print("imageURL is empty or None.")
            continue  # 跳过这个 imageURL
        if isinstance(imageURL, str):
            pattern = re.compile(r'^(https|http|ftp|rtsp|mms)?:/{2}\w.+$')
            valid = re.match(pattern, imageURL)
        else:
            print(f"imageURL is not a string: {imageURL}")
        # 使用wget把图片下载到本地,注意默认下载到python执行路径下
        if (valid):
            image_filename = wget.download(imageURL,out='./img')
            print(u'正在保存的一张图片为:', image_filename)
            number +=1

    print('\ntotal number of image:', number)


def getImg(html):
    global imglist
    soup = BeautifulSoup(html, 'html.parser')
    img_tags = soup.find_all('img')
    imglist = [img.get('src') for img in img_tags]
    print(imglist)
def getHtml(url):
    http = urllib3.PoolManager(ca_certs=certifi.where())
    r = http.request('GET', url)
    htmlStr = ""
    #判断是否爬取成功,200表示成功
    if (r.status == 200):
        htmlStr=r.data.decode('utf-8') # 取出爬取的页面内容
    # 打印爬取的html页面内容
    # print(htmlStr)
    return htmlStr

imglist = []

if __name__=='__main__':
    url = r'https://www.zhihu.com/question/534661254'
    html = getHtml(url)
    if(len(html)!=0):
        getImg(html)
    print(imglist)
    saveImage(imglist)

 6.微博自动登录,从微博上搜索话题(蔡徐坤),自动爬取数据生成xls文件

# -*- coding: utf-8 -*-
import time
import datetime
import xlwt
import re
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()

# 先调用无界面浏览器Chrome
# driver = webdriver.Chrome()
# 下载chrome:https://www.google.cn/intl/zh-CN/chrome/
# 要使用Chrome浏览器,必须得有chromedriver
# 并且需要设置环境变量PATH
# 参考:https://www.cnblogs.com/lfri/p/10542797.html
# 如89.0.4389.90版本的chrome对应下载89.0.4389.23即可



# ********************************************************************************
#                            第一步: 登陆login.sina.com
#                     这是一种很好的登陆方式,有可能有输入验证码
#                          登陆之后即可以登陆方式打开网页
# ********************************************************************************

def LoginWeibo(username, password):
    global driver
    try:
        # 初始化 Chrome driver, 确保你已经下载了Chrome的WebDriver,并且放置在可访问的位置

        print('准备登陆weibo.cn网站...')
        driver.get("http://weibo.com/login.php")
        time.sleep(3)
        # 修正拼写错误
        elem_user = driver.find_element_by_xpath('//*[@id="loginname"]')
        elem_user.send_keys(username)
        elem_pwd = driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[2]/div/input')
        elem_pwd.send_keys(password)
        elem_sub = driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a')
        elem_sub.click()

        time.sleep(10)
        elem_sub.click()
        time.sleep(10)

        print('Crawl in ', driver.current_url)
        print('输出Cookie键值对信息:')

        for cookie in driver.get_cookies():
            print(cookie)
            for key in cookie:
                print(key, cookie[key])
        print('登陆成功...')
    except Exception as e:
        print("Error: ", e)
    finally:
        print('End LoginWeibo!\n')



# ********************************************************************************
#                  第二步: 访问http://s.weibo.com/页面搜索结果
#               输入关键词、时间范围,得到所有微博信息、博主信息等
#                     考虑没有搜索结果、翻页效果的情况
# ********************************************************************************

def GetSearchContent(key):
    global driver
    driver.get("http://s.weibo.com/")

    print('搜索热点主题:')
    time.sleep(1)
    item_cli = driver.find_element_by_xpath('//*[@id="searchapps"]/div/div[1]/div/div/div[1]/div/div[1]')
    item_cli.click()
    item_inp = driver.find_element_by_xpath("//input[@type='text']")
    item_inp.send_keys(key)
    time.sleep(1)
    item_inp.send_keys(Keys.RETURN)


    # 获取搜索词的URL,用于后期按时间查询的URL拼接
    current_url = driver.current_url

    current_url = current_url.split('&')[0]  # http://s.weibo.com/weibo/%25E7%258E%2589%25E6%25A0%2591%25E5%259C%25B0%25E9%259C%2587

    global start_stamp
    global page


    # 需要抓取的开始和结束日期,可根据你的实际需要调整时间
    start_date = datetime.datetime(2024, 2, 25)
    end_date = datetime.datetime(2024, 3, 25)
    delta_date = datetime.timedelta(days=1)
    # 每次抓取一天的数据
    start_stamp = start_date
    end_stamp = start_date + delta_date

    global outfile
    global sheet

    outfile = xlwt.Workbook(encoding='utf-8')

    while end_stamp <= end_date:
        page = 1

        # 每一天使用一个sheet存储数据
        sheet = outfile.add_sheet(start_stamp.strftime("%Y-%m-%d-%H"))
        initXLS()

        # 通过构建URL实现每一天的查询
        url = current_url+"/weibo?q="+ key + '&typeall=1&suball=1&timescope=custom:' + start_stamp.strftime(
                "%Y-%m-%d-%H") + ':' + end_stamp.strftime("%Y-%m-%d-%H") + '&Refer=g'
        driver.get(url)
        print("这是url:"+url)

        handlePage()  # 处理当前页面内容

        start_stamp = end_stamp
        end_stamp = end_stamp + delta_date
        time.sleep(1)


# time.sleep(1)

# ********************************************************************************
#                  辅助函数,考虑页面加载完成后得到页面所需要的内容
# ********************************************************************************

# 页面加载完成后,对页面内容进行处理
def handlePage():
    global driver
    while True:
        # 之前认为可能需要sleep等待页面加载,后来发现程序执行会等待页面加载完毕
        # sleep的原因是对付微博的反爬虫机制,抓取太快可能会判定为机器人,需要输入验证码
        time.sleep(1)
        # 先行判定是否有内容
        if checkContent():
            print("getContent")
            getContent()
            # 先行判定是否有下一页按钮
            if checkNext():
                print("aaa")
                # 拿到下一页按钮
                next_page_btn = driver.find_element_by_xpath('//*[@id="pl_feedlist_index"]/div[3]/div/a')
                next_page_btn.click()
            else:
                print("no Next")
                break
        else:
            print("no Content")
            break


# 判断页面加载完成后是否有内容
def checkContent():
    # 有内容的前提是有“导航条”?错!只有一页内容的也没有导航条
    # 但没有内容的前提是有“pl_noresult”
    try:
        driver.find_element_by_xpath("//div[@class='card card-no-result s-pt20b40']")
        flag = False
    except:
        flag = True
    return flag


# 判断是否有下一页按钮
def checkNext():
    try:
        driver.find_element_by_xpath('//*[@id="pl_feedlist_index"]/div[3]/div/a')
        print("有")
        flag = True
    except:
        print("无")
        flag = False
    return flag


# 判断是否有展开全文按钮
def checkqw():
    try:
        driver.find_element_by_xpath(".//div[@class='content']/p[@class='txt']/a")
        flag = True
    except:
        flag = False
    return flag


# 在添加每一个sheet之后,初始化字段
def initXLS():
    name = ['博主昵称', '博主主页', '微博认证', '微博达人', '微博内容', '发布位置', '发布时间', '微博地址', '微博来源', '转发', '评论', '赞']

    global row
    global outfile
    global sheet

    row = 0
    for i in range(len(name)):
        sheet.write(row, i, name[i])
    row = row + 1
    outfile.save("./微博数据.xls")   ############


# 将dic中的内容写入excel
def writeXLS(dic):
    global row
    global outfile
    global sheet

    for k in dic:
        for i in range(len(dic[k])):
            sheet.write(row, i, dic[k][i])
        row = row + 1
    outfile.save("./微博数据.xls")   #############


# 在页面有内容的前提下,获取内容
def getContent():
    # 寻找到每一条微博的class
    try:
        nodes = driver.find_elements_by_xpath("//div[@class='card-wrap']/div[@class='card']")
    except Exception as e:
        print(e)

    # 在运行过程中微博数==0的情况,可能是微博反爬机制,需要输入验证码
    if len(nodes) == 0:
        input("请在微博页面输入验证码!")
        url = driver.current_url
        driver.get(url)
        getContent()
        return

    dic = {}

    global page
    print(start_stamp.strftime("%Y-%m-%d-%H"))
    print('页数:', page)
    page = page + 1
    print('微博数量', len(nodes))

    for i in range(len(nodes)):
        dic[i] = []
        try:
            BZNC = nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='txt']").get_attribute("nick-name")
        except:
            BZNC = ''
        print('博主昵称:', BZNC)
        dic[i].append(BZNC)

        try:
            BZZY = nodes[i].find_element_by_xpath(".//div[@class='content']/div[@class='info']/div[2]/a").get_attribute("href")
        except:
            BZZY = ''
        print('博主主页:', BZZY)
        dic[i].append(BZZY)
        # 微博官方认证,没有爬取
        try:
            WBRZ = nodes[i].find_element_by_xpath(".//div[@class='info']/div/a[contains(@title,'微博')]").get_attribute('title') # 若没有认证则不存在节点
        except:
            WBRZ = ''
        print('微博认证:', WBRZ)
        dic[i].append(WBRZ)

        try:
            WBDR = nodes[i].find_element_by_xpath(".//div[@class='feed_content wbcon']/a[@class='ico_club']").get_attribute('title')  # 若非达人则不存在节点
        except:
            WBDR = ''
        print('微博达人:', WBDR)
        dic[i].append(WBDR)

        # 判断展开全文和网页链接是否存在
        try:
            nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='txt']/a[@action-type='fl_unfold']").is_displayed()
            flag = True
        except:
            flag = False
        # 获取微博内容
        try:
            if flag:
                nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='txt']/a[@action-type='fl_unfold']").click()
                time.sleep(1)
                WBNR = nodes[i].find_element_by_xpath(".//div[@class='content']/p[2]").text.replace("\n","")
                # 判断发布位置是否存在
                try:
                    nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='txt']/a/i[@class='wbicon']").is_displayed()
                    flag = True
                except:
                    flag = False
                # 获取微博发布位置
                try:
                    if flag:
                        pattern = nodes[i].find_elements_by_xpath(".//div[@class='content']/p[2]/a[i[@class='wbicon']]")
                        if isinstance(pattern,list):
                            text = [p.text for p in pattern]
                            FBWZ = [loc for loc in [re.findall('^2(.*$)', t) for t in text] if len(loc) > 0][0][0]
                        else:
                            text = pattern.text
                            FBWZ = re.findall('^2(.*$)',text)[0]
                    else:
                        FBWZ = ''
                except:
                    FBWZ = ''
            else:
                WBNR = nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='txt']").text.replace("\n","")
                # 判断发布位置是否存在
                try:
                    nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='txt']/a/i[@class='wbicon']").is_displayed()
                    flag = True
                except:
                    flag = False
                # 获取微博发布位置
                try:
                    if flag:
                        pattern = nodes[i].find_elements_by_xpath(".//div[@class='content']/p[@class='txt']/a[i[@class='wbicon']]")
                        if isinstance(pattern,list):
                            text = [p.text for p in pattern]
                            FBWZ = [loc for loc in [re.findall('^2(.*$)', t) for t in text] if len(loc) > 0][0][0]
                        else:
                            text = pattern.text
                            FBWZ = re.findall('^2(.*$)',text)[0]
                    else:
                        FBWZ = ''
                except:
                    FBWZ = ''
        except:
            WBNR = ''
        print('微博内容:', WBNR)
        dic[i].append(WBNR)

        print('发布位置:', FBWZ)
        dic[i].append(FBWZ)

        try:
            FBSJ = nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='from']/a[1]").text
        except:
            FBSJ = ''
        print('发布时间:', FBSJ)
        dic[i].append(FBSJ)

        try:
            WBDZ = nodes[i].find_element_by_xpath(".//div[@class='content']/p[@class='from']/a[1]").get_attribute("href")
        except:
            WBDZ = ''
        print('微博地址:', WBDZ)
        dic[i].append(WBDZ)

        try:
            ZF_TEXT = nodes[i].find_element_by_xpath(".//a[@action-type='feed_list_forward']").text
            if ZF_TEXT == '转发':
                ZF = 0
            else:
                ZF = int(ZF_TEXT.split(' ')[1])
        except:
            ZF = 0
        print('转发:', ZF)
        dic[i].append(ZF)
        print('\n')

    # 写入Excel
    writeXLS(dic)


# *******************************************************************************
#                                程序入口
# *******************************************************************************
if __name__ == '__main__':
    # 定义变量
    username = '17359456898'
    password = 'Panbinjie201314'

    # 操作函数
    LoginWeibo(username, password)  # 登陆微博
    # 搜索热点微博爬取评论
    # 关键词请根据实际需要进行替换
    # 请搜索和疫情有关的一些非敏感关键词
    # 注意:如果输入的是“疫情”“武汉”“中国”这样的敏感词汇,微博不会返回给你任何结果
    # 请尽量输入疫情相关又不会敏感的词汇,可以输入一些疫情支援人员的姓名试试看
    key = '蔡徐坤'
    GetSearchContent(key)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值