Python 网页抓取 - 用 Scrapers 测试

本章介绍如何在 Python 中使用网络抓取工具执行测试。


简介

在大型网络项目中,网站后端的自动化测试是定期执行的,但前端测试经常被跳过。 这背后的主要原因是网站的编程就像是各种标记和编程语言组成的网络。 我们可以为一种语言编写单元测试,但如果交互是用另一种语言完成的,它就会变得具有挑战性。 这就是为什么我们必须有一套测试来确保我们的代码按照我们的预期执行。


使用 Python 进行测试

当我们谈论测试时,它指的是单元测试。 在深入使用 Python 进行测试之前,我们必须了解单元测试。 以下是单元测试的一些特征 −

  • 在每个单元测试中至少会测试组件功能的一个方面。

  • 每个单元测试都是独立的,也可以独立运行。

  • 单元测试不会影响任何其他测试的成功或失败。

  • 单元测试可以按任何顺序运行,并且必须至少包含一个断言。


单元测试 − Python 模块

用于单元测试的名为 Unittest 的 Python 模块随所有标准 Python 安装一起提供。 我们只需要导入它,剩下的就是 unittest.TestCase 类的任务,它将执行以下操作 −

  • SetUp 和 tearDown 函数由 unittest.TestCase 类提供。 这些函数可以在每个单元测试前后运行。

  • 它还提供断言语句以允许测试通过或失败。

  • 它运行所有以 test_ 开头的函数作为单元测试。

示例

在这个例子中,我们将把网络抓取与 unittest 结合起来。 我们将测试维基百科页面以搜索字符串"Python"。 它基本上会做两个测试,首先判断标题页是否与搜索字符串相同,即是否为"Python",第二个测试确保页面具有内容 div。

首先,我们将导入所需的 Python 模块。 我们使用 BeautifulSoup 进行网络抓取,当然还使用 unittest 进行测试。

from urllib.request import urlopen
from bs4 import BeautifulSoup
import unittest

现在我们需要定义一个扩展 unittest.TestCase 的类。 全局对象 bs 将在所有测试之间共享。 一个unittest指定的函数setUpClass将完成它。 这里我们将定义两个函数,一个用于测试标题页,另一个用于测试页面内容。

class Test(unittest.TestCase):
   bs = None
   def setUpClass():
      url = '<a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Python">https://en.wikipedia.org/wiki/Python'</a>
      Test.bs = BeautifulSoup(urlopen(url), 'html.parser')
   def test_titleText(self):
      pageTitle = Test.bs.find('h1').get_text()
      self.assertEqual('Python', pageTitle);
   def test_contentExists(self):
      content = Test.bs.find('div',{'id':'mw-content-text'})
      self.assertIsNotNone(content)
if __name__ == '__main__':
   unittest.main()

运行上面的脚本后我们会得到如下输出 −

----------------------------------------------------------------------
Ran 2 tests in 2.773s

OK
An exception has occurred, use %tb to see the full traceback.

SystemExit: False

D:\ProgramData\lib\site-packages\IPython\core\interactiveshell.py:2870:
UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)

使用 Selenium 进行测试

让我们讨论如何使用 Python Selenium 进行测试。 它也称为硒测试。 Python unittest 和 Selenium 没有太多共同点。 我们知道 Selenium 将标准的 Python 命令发送到不同的浏览器,尽管浏览器的设计有所不同。 回想一下,我们已经在前面的章节中安装并使用了 Selenium。 在这里,我们将在 Selenium 中创建测试脚本并将其用于自动化。

示例

借助下一个 Python 脚本,我们正在为 Facebook 登录页面的自动化创建测试脚本。 您可以修改示例以自动执行您选择的其他表单和登录,但概念是相同的。

首先为了连接到网络浏览器,我们将从 selenium 模块导入 webdriver −

from selenium import webdriver

现在,我们需要从 selenium 模块导入 Keys。

from selenium.webdriver.common.keys import Keys

接下来我们需要提供用户名和密码以登录我们的 facebook 帐户

user = "gauravleekha@gmail.com"
pwd = ""

接下来,提供 Chrome 网络驱动程序的路径。

path = r'C:\\Users\\gaurav\\Desktop\\Chromedriver'
driver = webdriver.Chrome(executable_path=path)
driver.get("http://www.facebook.com")

现在我们将使用 assert 关键字来验证条件。

assert "Facebook" in driver.title

在以下代码行的帮助下,我们将值发送到电子邮件部分。 这里我们通过它的 id 搜索它,但我们可以通过名称搜索来完成它,如 driver.find_element_by_name("email")。

element = driver.find_element_by_id("email")
element.send_keys(user)

在以下代码行的帮助下,我们将值发送到密码部分。 这里我们通过它的 id 搜索它,但我们可以通过名称搜索来完成它,如 driver.find_element_by_name("pass")。

element = driver.find_element_by_id("pass")
element.send_keys(pwd)

下一行代码用于在电子邮件和密码字段中插入值后按回车/登录。

element.send_keys(Keys.RETURN)

现在我们将关闭浏览器。

driver.close()

运行上述脚本后,Chrome 网络浏览器将打开,您可以看到正在输入电子邮件和密码并单击登录按钮。

Facebook 登录

比较:unittest 或 Selenium

unittest 和 selenium 的比较是困难的,因为如果你想使用大型测试套件,则需要 unites。 另一方面,如果您要测试网站的灵活性,那么 Selenium 测试将是我们的首选。 但是如果我们可以将它们结合起来呢? 我们可以将 selenium 导入到 Python unittest 中,并充分利用两者。 Selenium 可用于获取有关网站的信息,unittest 可评估该信息是否符合通过测试的标准。

例如,我们正在重写上面的 Python 脚本,通过将它们结合起来实现 Facebook 登录的自动化,如下所示 −

import unittest
from selenium import webdriver

class InputFormsCheck(unittest.TestCase):
   def setUp(self):
      self.driver = webdriver.Chrome(r'C:\Users\gaurav\Desktop\chromedriver')
      def test_singleInputField(self):
      user = "gauravleekha@gmail.com"
      pwd = ""
      pageUrl = "http://www.facebook.com"
      driver=self.driver
      driver.maximize_window()
      driver.get(pageUrl)
      assert "Facebook" in driver.title
      elem = driver.find_element_by_id("email")
      elem.send_keys(user)
      elem = driver.find_element_by_id("pass")
      elem.send_keys(pwd)
      elem.send_keys(Keys.RETURN)
   def tearDown(self):
      self.driver.close()
if __name__ == "__main__":
   unittest.main()