网站的前端测试经常最后才做,或者指派给低级程序员去做,最多再给他们一个检查表和一个 bug 跟踪器。就可以把检查表变成一系列单元测试,用网络爬虫代替人眼进行测试。
本篇内容将介绍测试的基础知识,以及如何用 Python 网络爬虫测试各种简单或复杂的网站。
1.测试简介
什么是单元测试
对于程序员来说,测试和单元测试(unit test)这两个词基本可以看成是等价的。
单元测试通常具有以下特点:

  • 每个单元测试用于测试一个组件的功能的一个方面。通常,一个组件的所有单元测试都集成在同一个类(class)里。
  • 每个单元测试都可以完全独立地运行,一个单元测试需要的所有启动(setup)和卸载(teardown)都必须通过这个单元测试本身去处理。
  • 每个单元测试通常至少包含一个断言(assertion)。有时,一个单元测试也许只包含一个失败状态,例如抛出异常则测试失败。
  • 单元测试与生产代码是分离的。

2.Python单元测试
所有标准版 Python 安装后都有单元测试模块 unittest。只要导入并扩展 unittest.TestCase 类,就可以实现下面的功能:

  • 为每个单元测试的开始和结束提供 setUp 和 tearDown 函数;
  • 提供不同类型的“断言”语句,让测试成功或失败;
  • 把所有以 test_ 开头的函数当作单元测试运行,忽略不带 test_ 的函数。

Python单元测试来测试2+2=4,代码如下:

import unittestclass TestAddition(unittest.TestCase):def setUp(self):print('Setting up the test')def tearDown(self):print('Tearing down the test')def test_twoPlustwo(self):total = 2+2self.assertEqual(4, total);if __name__ == '__main__':unittest.main()


setUp 和 tearDown 这两个函数在每个测试开始和结束时都会运行一次,而不是在类中所有测试开始之前和结束之后各运行一次。

本篇内容单元测试代码开头都是
if __name__ == '__main__':
------unittest.main()
它可以让你用 unittest.TestCase 类在命令行直接运行你的单元测试。
Jupyter notebook 中,Jupyter 创建的 argv 参数可能会在单元测试中引起错误,且由于在测试运行之后,unittest 框架默认会退出 Python(这会导致notebook 内核发生错误)
所以在Jupyter notebook中,可以用以下命令启动单元测试:
if __name__ == '__main__':
------unittest.main(argv=[''], exit=False)
------%reset
第二行将所有的 argv 变量(命令行参数)设置成一个空字符串,它就会被 unnittest.main 忽略。它还阻止了 unittest 在测试运行之后退出。%reset 行也非常有用,因为它重置了内存,并销毁了所有用户在 Jupyter notebook 中创
建的变量。

测试维基百科
将 Python 的 unittest 库与网络爬虫组合起来(测试页面标题和页面某元素)

from urllib.request import urlopen
from bs4 import BeautifulSoup
import unittestclass TestWikipedia(unittest.TestCase):bs = Nonedef setUpClass():url = 'http://en.wikipedia.org/wiki/Monty_Python'TestWikipedia.bs = BeautifulSoup(urlopen(url), 'html.parser')def test_titleText(self):pageTitle = TestWikipedia.bs.find('h1').get_text()self.assertEqual('Monty Python', pageTitle);def test_contentExists(self):content = TestWikipedia.bs.find('div', {'id': 'mw-context-text'})self.assertIsNotNone(content)if __name__ == '__main__':unittest.main()

这个页面的内容只加载一次,全局对象 bs 由多个测试共享。这是通过unittest 类的函数 setUpClass 来实现的,这个函数只在类的初始化阶段运行一次。用 setUpClass 代替 setUp 可以省去不必要的页面加载;我们可以一次性抓取全部内容,供多个测试使用。
除了运行时间和频次不同之外,setUpClass 和 setUp 的一个主要架构区别是:setUpClass是一个静态方法,它属于类本身并且拥有全局类变量,而 setUp 是一个实例函数,它属于类的一个特定实例。
setUp 可以设置自身的属性(即这个类的特定实例),而这里setUpClass 只能获取 TestWikipedia 类的静态类属性。
把网络爬虫和一个向页面内容添加断言的单元测试组合起来。(重复执行一个测试)
以下代码在能访问维基百科网站的前提下也会发生错误,因为网页会发生重定向。

# -*- coding:GBK -*-
from urllib.request import urlopen
from bs4 import BeautifulSoup
import unittest
import re
import random
from urllib.parse import unquoteclass TestWikipedia(unittest.TestCase):def test_PageProperties(self):self.url = 'http://en.wikipedia.org/wiki/Monty_Python'#测试遇到的前10个页面for i in range(1, 10):self.bs = BeautifulSoup(urlopen(self.url), 'html.parser')titles = self.titleMatchesURL()self.assertEquals(titles[0], titles[1])self.assertTrue(self.contentExists())self.url = self.getNextLink()print('Done!')def titleMathesURL(self):pageTitle = self.bs.find('h1').get_text()urlTitle = self.url[(self.url.index('/wiki/')+6):]urlTitle = urlTitle.raplace('_', ' ')urlTitle = unquote(urlTitle)    #unquote 对url进行解码,将%u格式编码解码为正常可读字符。return [pageTitle.lower(), urlTitle.lower()]def contentExists(self):content = self.bs.find('div', {'id': 'mw-content-text'})if content is not None:return Truereturn Falsedef getNextLink(self):# 利用第3篇文章中介绍的技术返回页面上的随机链接links = self.bs.find('div', {'id': 'bodyContent'}).find_all('a', href=re.compile('^(/wiki/)((?!:).)*$'))randomLink = random.SystemRandom().choice(links)return 'https://wikipedia.org{}'.format(randomLink.attrs['href'])if __name__ == '__main__':unittest.main()

布尔型断言结果与assertEquals语句的结果相比:

==========================================================
FAIL: test_PageProperties (__main__.TestWikipedia)
----------------------------------------------------------------------
Traceback (most recent call last):
File "15-3.py", line 22, in test_PageProperties
self.assertTrue(self.titleMatchesURL())
AssertionError: False is not true

========================================================
FAIL: test_PageProperties (__main__.TestWikipedia)
----------------------------------------------------------------------
Traceback (most recent call last):
File "15-3.py", line 23, in test_PageProperties
self.assertEquals(titles[0], titles[1])
AssertionError: 'lockheed u-2' != 'u-2 spy plane'

3.Selenium 单元测试
Selenium,它是一个可以解决网站上各种复杂问题的优秀的测试框架;其实,它的设计初衷就是用来做网站测试!
Selenium 不要求单元测试必须是类的一个函数,它的“断言”语句也不需要括号,而且测试通过时不会有提示,只有当测试失败时才会给出提示。

driver = webdriver.PhantomJS()
driver.get('http://en.wikipedia.org/wiki/Monty_Python')
assert 'Monty Python' in driver.title
driver.close()

当这个测试运行的时候,不会输出任何信息。这种形式非常适合某个条件不能满足就中断代码执行的需求。

与网站进行交互
前面几篇文章介绍的链接跳转、表单提交和其他网站交互行为,都是避开浏览器图形界面,而不是不使用浏览器。另一方面,Selenium 可以在浏览器(这里用 PhantomJS 无头浏览器)中做任何事,包括输入文字、点击按钮等,这样就可以找出异常表单、JavaScript 代码错误、HTML 排版错误,以及在用户使用过程中可能出现的其他问题。
这个测试的关键是使用 Selenium 的 elements。调用方式如usernameField = driver.find_element_by_name('username'),就像你可以在浏览器里对网站上的不同元素执行一系列操作一样,Selenium 也可以对任何给定元素执行很多操作,例如:

myElement.click()
myElement.click_and_hold()
myElement.release()
myElement.double_click()
myElement.send_keys_to_element(‘content to enter’)

除了一次性完成一个元素的多个操作,还可以将一组操作组合成一个动作链(action chain)存储起来,然后在一个程序中执行一次或多次。
对比两种方式的差异,代码如下:

# -*- coding:GBK -*-
from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChainsdriver = webdriver.PhantomJS(executable_path='D:/Web_crawler/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.get('http://pythonscraping.com/pages/files/form.html')firstnameField = driver.find_element_by_name('firstname')
lastnameField = driver.find_element_by_name('lastname')
submitButton = driver.find_element_by_id('submit')### 方法1 ###
firstnameField.send_keys('Ryan')
lastnameField.send_keys('Mitchell')
submitButton.click()### 方法2 ###
actions = ActionChains(driver).click(firstnameField).send_keys('Ryan').click(lastnameField).send_keys('Mitchell').send_keys(Keys.RETURN)
actions.perform()#############print(driver.find_element_by_tag_name('body').text)driver.close()


方法 1 在两个字段上调用 send_keys,然后点击“提交”按钮;而方法 2 用一个动作链来点击每个字段并填写内容,这些行为是在 perform 调用之后才发生的。两个方法的结果都是一样:一句问候语。这两个方法还有一个差异:注意第一个方法提交表单时点击的是“提交”按钮,而第二个方法提交表单时用的是回车键(Keys.RETURN)。

(1)鼠标拖放动作
Selenium 可以轻松地完成鼠标拖放动作。使用它的拖放功能,你需要指定一个被拖放的元素以及拖放的距离或者拖放到的目标元素。
演示拖放代码如下:

from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver import ActionChainsdriver = webdriver.PhantomJS(executable_path='D:/Web_crawler/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.get('http://pythonscraping.com/pages/javascript/draggableDemo.html')print(driver.find_element_by_id('message').text)element = driver.find_element_by_id('draggable')
target = driver.find_element_by_id('div2')
actions = ActionChains(driver)
actions.drag_and_drop(element, target).perform()print(driver.find_element_by_id('message').text)

很多验证码都使用拖动来证明访问者不是机器人。这些验证码库的优势在于那些简单任务可以实现大量的变化,而且每种变化的使用频率都不高,另外也不会有人愿意花时间去开发一个能够搞定所有任务的机器人。

(2)截屏
截屏可以在单元测试中创建,而无须点击截屏按钮:(脚本访问网站,将主业的屏幕截图保存在本地指定文件夹下。截屏可保存为多种文件格式。)

driver = webdriver.PhantomJS()
driver.get('http://www.pythonscraping.com/')
driver.get_screenshot_as_file('tmp/pythonscraping.png')

4.单元测试与Selenium单元测试的选择
Selenium 可以轻易地获取网站的信息,而单元测试可以评估这些信息是否满足通过测试的条件。两者组合是最佳拍档。
创建带拖放动作的网站单元测试,代码如下:(url网站手动拖拽未成功,该代码运行也未显示“You are definitely not a bot!”文字)

from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver import ActionChains
import unittestclass TestDragAndDrop(unittest.TestCase):driver = Nonedef setUp(self):self.driver = webdriver.PhantomJS(executable_path='D:/Web_crawler/phantomjs-2.1.1-windows/bin/phantomjs.exe')url = 'http://pythonscraping.com/pages/javascript/draggableDemo.html'self.driver.get(url)def tearDown(self):print("Tearing down the test")def test_drag(self):element = self.driver.find_element_by_id('draggable')target = self.driver.find_element_by_id('div2')actions = ActionChains(self.driver)actions.drag_and_drop(element, target).perform()self.assertEqual('You are definitely not a bot!', self.driver.find_element_by_id('message').text)if __name__ == '__main__':unittest.main(argv=[''], exit=False)

15.用爬虫测试网站相关推荐

  1. 测试网站访问速度的几个小方法

    1:用Ping命令简单测网站速度的方法 Ping可以用来检查网络是否通畅或者网络连接速度,点击开始→运行 在运行中输入"cmd"回车或点击确定,输入ping www.你的网址.co ...

  2. 测试网站访问速度的5个方法

    网页载入速度对于一个网站来讲很关键,Google已经将一个网站的载入速度列入了网站关键字排名的考虑因素当中,也就是说如果你的网站有足够的内容,而且载入速度比别人的网站更快一步的话,那么你就是获得更好的 ...

  3. 63个优秀测试网站地址【个人总结】

    http://bdonline.sqe.com/ 一个关于网站测试方面的网页,对这方面感兴趣的人可以参考 http://citeseer.nj.nec.com/ 一个丰富的电子书库,内容很多,而且提供 ...

  4. 您应该遵循的15个UI测试自动化最佳实践(上)

    本文转载自晨小菜订阅号,感谢大佬的分享 我们知道,在过去二十年UI端的自动化测试一直是我们项目上做自动化测试的重点.随着敏捷的发展,慢慢的越来越多人开始诟病UI自动化测试,觉得在UI端做自动化其稳定性 ...

  5. Python爬虫——12306网站车次信息

    Python爬虫--12306网站车次信息 相信每一个人都听说过谷歌.百度等浏览器,我们在在输入栏中输入我们想要的关键字,便会出现与我们输入关键字有关的网页.那么这些数据时是怎么来的呢?其实这跟网络爬 ...

  6. python测试网站功能_网站测试流程、要求及测试报告

    网站测试流程.要求及测试报告 一个网站基本完工后,需要通过下面三步测试才可以交活. 一. 制作者测试,包括美工测试页面.程序员测试功能.在做完后第一时间内有制作者本人进行测试. a) 页面 包括首页. ...

  7. python爬虫捕鱼网站_Python爬虫从太平洋地震工程研究中心数据库自动下载地震波时程...

    python app开发自动捕鱼" 引子-- 最近小编在沉迷捕鱼之余,扫到了某问答网站里的一个网友提问的标题叫做"Python真的有那么神吗?",各位被邀嘉宾们针对最近P ...

  8. 15款最好的网站音乐播放器

    在互联网上有很多的脚本和插件,可以很容易将音乐播放功能集成到网站,以下是15款最好的网站音乐播放器. Flash MP3 Player Flash MP 3 player is free script ...

  9. 【推荐】一个不错的密码强度测试网站

    http://password.mx500.com/ 一个不错的密码强度测试网站,在危险重重的互联网,真的需要一个简单易记而又强度很高的密码. 转载于:https://www.cnblogs.com/ ...

最新文章

  1. 文件存储服务器英文,文件存储服务器
  2. “人工智能进行临床诊断,至少在今天看来不靠谱”
  3. 身份证号信息后台匹配
  4. videoleap怎么导出本地_视频号小视频怎么制作?(附工具软件)
  5. 提升你的职场竞争力——“低代码开发师”来了!
  6. SFB2015 多SIP域
  7. spring 属性占位符_Spring属性占位符配置器–一些不太明显的选项
  8. Nginx访问403异常问题处理
  9. 今天来谈谈内容溢出和文字溢出的问题
  10. c语言小车倒车程序,STC12C5A60S2串口演示程序(C语言版)
  11. UDP报文观测以及DNS的工作原理
  12. 智能计算机翻译,爱译网-智能翻译技术-人工智能翻译技术
  13. 第7周 文件和数据格式化
  14. 用phpstudy安装DVWA
  15. JavaScript 编写Date 格式化方法『Python风格』
  16. 计算机桌面图标设置密码,教你怎么设置电脑开机密码
  17. 使用C/C++的#include命令(文件包含命令)时,文件名用尖括号或双撇号(双引号)括起来的区别
  18. 技术领导力1-CTO 能力、素质与战略类
  19. 我的第一个博客----浅谈人生观价值观
  20. ERROR: You must give at least one requirement to install (see pip help install)

热门文章

  1. 区块链基本概念和名词解释
  2. 奔跑的业绩,需要配上奔跑的Excel条形图
  3. 微信小程序 - 实现手机号登录--授权并获取手机号保存至本地
  4. 计算机硬件是怎么影响性能的,哪些硬件影响电脑的性能
  5. 红黑树(一)的原理和算法详细介绍
  6. 软件工程作业一:从产品经理人角度分析微信求职招聘小程序
  7. CAD图纸如何转换成Word文档呢?
  8. OneDrive不能上了?DNS被污染,解决方法很简单
  9. easyloader [easyui_1.4.2] 分析源码,妙手偶得之
  10. 2020年保育员(中级)多少分及格及保育员(中级)模拟考试系统