Python Web Scraping 简明教程
Python Web Scraping - Testing with Scrapers
本章介绍如何在 Python 中使用网络抓取进行测试。
Introduction
在大型网络项目中,网站后端的自动化测试会定期进行,但前端测试往往会被跳过。其主要原因在于,网站的编程就像各种标记和编程语言的网络。我们可以针对一种语言编写单元测试,但如果交互是使用另一种语言完成的,就会变得具有挑战性。这就是说,我们必须拥有一套测试,以确保我们的代码按预期执行。
Testing using Python
当我们谈论测试时,意思是说单元测试。在深入探究使用 Python 进行测试之前,我们必须了解单元测试。以下是单元测试的一些特征:
-
单元测试中会测试组件功能的一个方面。
-
每个单元测试都是独立的,还可以独立运行。
-
单元测试不会影响任何其他测试的成功或失败。
-
单元测试可以按任意顺序运行,且必须包含至少一个断言。
Unittest − Python Module
名为 Unittest 的 Python 模块用于单元测试,该模块附带所有标准 Python 安装。我们只需要导入它,其余的就是 unittest.TestCase 类的任务,它将执行以下操作:
-
unittest.TestCase 类提供了 SetUp 和 tearDown 函数。这些函数可以在每个单元测试前和后运行。
-
它还提供 assert 语句以使测试能够通过或失败。
-
它会运行所有以 test_ 开头的函数,作为单元测试。
Example
在这个示例中,我们将结合 unittest 使用网络抓取。我们将测试 Wikipedia 页面,以搜索字符串“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)
Testing with Selenium
让我们讨论如何使用 Python Selenium 进行测试。这也被称为 Selenium 测试。Python unittest 和 Selenium 并没有太多共同点。我们知道 Selenium 将标准的 Python 命令发送到不同的浏览器,尽管它们的浏览器设计存在差异性。请记住,我们已经在之前的章节中安装了 Selenium 并使用过它。我们将在 Selenium 中创建测试脚本,并将其用于自动化。
Example
在此 Python 脚本的帮助下,我们为 Facebook 登录页面的自动化创建了测试脚本。你可以修改该示例来自动化你所选择的其他表单和登录,但其概念是一样的。
首先要连接到 Web 浏览器,我们要从 selenium 模块导入 webdriver −
from selenium import webdriver
现在,我们需要从 selenium 模块导入 Keys。
from selenium.webdriver.common.keys import Keys
接下来我们需要提供用于登录 Facebook 帐户的用户名和密码
user = "gauravleekha@gmail.com"
pwd = ""
接下来,提供 Chrome 的 Web 驱动程序路径。
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 进行搜索,但我们可以通过按 name driver.find_element_by_name("email") 进行搜索来执行此操作。
element = driver.find_element_by_id("email")
element.send_keys(user)
通过下面的代码行,我们正在将值发送到密码部分。我们在这里通过其 id 进行搜索,但我们可以通过按 name 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 Web 浏览器将会打开,并且您可以看到电子邮件和密码正在被插入并单击登录按钮。
Comparison: unittest or 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()