如何使用Selenium WebDriver查找破损的图片

266 阅读19分钟

DZone>Web Dev Zone>如何使用Selenium WebDriver查找破损的图像

如何使用Selenium WebDriver查找破损的图片

我们看看如何使用Python、Java、C#和PHP的Selenium WebDriver来查找网站上的破损图片,以便改善页面的用户体验。

Praveen Mishra user avatar通过

普拉维恩-米什拉

-

Harshit Paul user avatar通过

Harshit Paul

-

Nov. 03, 21 - Web Dev Zone -教程

喜欢 (2)

评论

保存

鸣叫

78次浏览

加入DZone社区,获得完整的会员体验。

免费加入

一个网络产品的用户体验是帮助用户获得和保留的关键因素之一。虽然应该对新产品功能的设计和开发给予极大的关注,但也应该对整个用户体验进行持续的观察。像404页面(或死链接)一样,网站(或网络应用程序)上的破损图像也会让终端用户感到不安。手动检查和删除破损的图像不是一个可行的和可扩展的方法。你应该利用Selenium自动化测试,看看如何使用Selenium WebDriver在你的网站上找到破损的图像,而不是使用第三方工具来检查破损的图像。

Selenium教程的这一部分,我们看看如何使用Selenium WebDriver找到网站上的破损图片。从终端用户的角度来看,即使页面上有一张破损的图片,也可能会影响用户的体验--这是寻找网站上破损图片的首要原因。

在本博客结束时,你将能够使用Python、Java、C#和PHP的Selenium WebDriver来查找破损的图片。

什么是网络测试中的破损图片?

破损的图片是指一个不显示图片的链接/图片,点击后会把最终用户带到一个不存在的图片。用户在点击破损的图片时,会遇到404错误。这个错误意味着图片的URL有问题,而图片没有被正确加载(由于各种原因)。

下面显示的是一个网站上破损图片的例子。

从最终用户体验和保留的角度来看,修复破损的图片应该被认为与修复网站上的破损链接同样重要。Selenium WebDriver可以用来查找网站上的破损图片。定位破损图片的内部逻辑可能会根据图片从服务器上获取的方式而有所不同。

以下是两种从服务器上读取图片的方式。

  • 绝对路径 - 顾名思义,网站在src 属性中使用绝对路径(或完整路径),该属性指定了通往预定图像的路径。HTML中的<img> 标签为引用的图像创建了一个保留空间。下面显示的是一个在<img> 标签的src 属性中使用绝对路径的例子。

上面显示的图像是从一个绝对位置获取的(即在<src> 属性中使用了HostName)。

  • 相对路径 - 在许多网站上,路径上的相对图像被放在属性中。相对路径总是相对于文档的根(即网站/网络应用)。

例如,在<img src=”assets/img/image.jpg” alt=”some text”> ,image.jpg的路径是相对于根的。如果网站的URL是www.someexample.com,图像的相对路径(image.jpg)将等同于https://www.someex…

下面是一个在<img> 标签的<src> 属性中使用相对路径的例子。

你可能很想知道是什么导致了网站上图像的损坏。让我们来看看破损图片的 "原因 "部分。

网页上图片损坏的主要原因

以下是一些导致网站或网络应用中图片损坏(即找不到文件或图片404错误)的突出原因。

  • 不正确的图像格式- 如果你已经上传了.jpg格式的图像,但在代码中被识别为.png格式的图像,当图像被显示时就会导致错误。在上传到服务器和在代码中引用相同的图片时,有必要确保图片格式一致。
  • 不正确的图像URL- 当渲染指定的图像时,浏览器会从<img> 标签中的<src> 属性中读取图像位置。如果在<src> 属性中提到错误的图像路径或错误的文件名,就会导致显示图像的问题(以及404错误)。
  • 删除的****图像文件- HTML代码链接可能提到了一个在代码中拼写错误的文件,或者在服务器上不再存在。
  • 网站搬迁- 在将网站从一个供应商搬迁到另一个供应商后,应进行彻底的检查,以验证所有的网站资产在新的服务器上是否可用和可访问。
  • 301重定向- 在网站重新设计活动中,应该对网站内容和网站上使用的图像进行301重定向。随着URLs的重定向,应该对驻留在这些URLs中的图像的重定向给予最大的关注。
  • 服务器的不可用性- 在服务器没有在一定的时间范围内给予回应的情况下,图像将不能出现在网站上。

像断链一样,应注意确保你的网络产品没有断裂的图像。

为什么你要检查破损的图像

以下是检查网站上破损图像的两个主要原因。

  • 网站上的破损图像妨碍了最终用户的体验,这可能对产品的增长产生负面影响。
  • 图片是内容营销战略的一个重要组成部分。然而,破损的图片可能会造成SEO问题。从SEO的角度来看,缺少ALT标签的图片和破损的内部图片是有问题的,应该高度重视。

如何使用Selenium WebDriver查找破损的图片

当用户访问一个网站时,用户的请求被发送到网站的服务器,由服务器来处理该请求。为了响应浏览器的请求,服务器会向浏览器发送一个三位数的代码,称为HTTP状态代码。

一些常用的HTTP状态代码类别是1xx、2xx、3xx、4xx和5xx。

为了使用Selenium WebDriver找到破损的图像,我们将使用4xx类状态代码,表示特定的页面或整个网站无法到达。2xx类的状态代码(尤其是200)表明网络浏览器发送的请求是成功的,并且向浏览器发送了适当的响应。

当服务器上的图像不可用时,响应代码404(Page Not Found)会被发送给网络浏览器。你可以参考我们之前的博客,了解关于HTTP状态代码的详细信息,以及关于检测破损链接/图像的状态代码的介绍

无论使用哪种编程语言来检测破损的图像,其基本原则都是一样的。以下是在网站上查找破损图像的一些步骤。

  1. 使用<img> 标签来收集页面上存在的图像的详细信息。
  2. 对于每个<img> 标签,从该标签中获取属性<src>
  3. 将从<src> 属性中获得的路径转换为 "绝对路径"。对于Selenium Java、Selenium C#和Selenium Python,可能不需要转换为绝对路径。当使用Selenium PHP时,将图像的 "相对路径 "转换为 "绝对路径 "是必须的。
  4. 向步骤3中获得的图像链接发送HTTP请求,并捕获响应请求时收到的响应代码。
  5. 根据服务器发送的响应代码,你应该验证图像是否被破坏。响应代码200(即HttpStatusCode.OK )意味着该图像在服务器上是可用的。
  6. 根据服务器发送的响应代码,验证该链接是否断裂。
  7. 对页面上出现的每张图片重复步骤2-6。

naturalWidth 属性返回图像的原始宽度,对于破损的图像,它是零。对于使用Java的Selenium,你也可以检查图片的naturalWidth 属性是否为零。

在这个Selenium教程中,我们演示了如何使用Selenium WebDriver在Java、Python、C#和PHP中查找破损的图像。测试是在Windows 10平台上最新版本的Chrome浏览器上运行的。执行是在LambdaTest提供的基于云的Selenium网格上进行的。

要开始使用LambdaTest,你应该在网站上创建一个账户,并注意LambdaTest的个人资料部分的用户名和访问密钥。浏览器能力是使用LambdaTest能力生成器生成的。

以下是在网站上寻找破损图像的测试场景。

  1. 用Chrome浏览器(最新)进入该网站
  2. 读取页面上存在的图像的详细信息。
  3. 为每张图片发送HTTP请求。
  4. 检查HTTP请求的响应代码。如果响应代码是200,说明图像没有被破坏;否则,图像被破坏。
  5. 在终端上打印图像是否被破坏。

被测试的URL有两个破损的图像和两个正常的图像。

下面显示的是该网站上的两张破损的图片。

下面是该网站上的两张正确的(或没有损坏的)图片。

如何使用Selenium Java查找破损的图片

文件名 - pom.xml

实施

XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
     	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.brokenimages</groupId>
    <artifactId>BrokenImages</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.9.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.28</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.0.0-alpha-7</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-remote-driver</artifactId>
            <version>4.0.0-alpha-7</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chrome-driver</artifactId>
            <version>4.0.0-alpha-7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>install</defaultGoal>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

文件名 - testng.xml

XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Broken Images Detection Demo">
    <test verbose="2" preserve-order="true" name="Detect broken images in Selenium WebDriver">
        <classes>
            <class name="brokenimages.test_brokenimages">
            </class>
        </classes>
    </test>
</suite>

文件名 - test_brokenimages.java

语法

package brokenimages;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.openqa.selenium.By;
import java.net.URL;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class test_brokenimages
{
    /*  protected static ChromeDriver driver; */
    WebDriver driver = null;
    String URL = "https://the-internet.herokuapp.com/broken_images";
    public static String status = "passed";
    String username = "user-name";
    String access_key = "access-key";
    @BeforeClass
    public void testSetUp() throws MalformedURLException {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("build", "[Java] Finding broken images on a webpage using Selenium");
        capabilities.setCapability("name", "[Java] Finding broken images on a webpage using Selenium");
        capabilities.setCapability("platform", "Windows 10");
        capabilities.setCapability("browserName", "Chrome");
        capabilities.setCapability("version","latest");
        capabilities.setCapability("tunnel",false);
        capabilities.setCapability("network",true);
        capabilities.setCapability("console",true);
        capabilities.setCapability("visual",true);
        driver = new RemoteWebDriver(new URL("http://" + username + ":" + access_key + "@hub.lambdatest.com/wd/hub"),
                capabilities);
        System.out.println("Started session");
    }
    @Test(description="Approach 1: Find broken images on a web page using Selenium WebDriver", enabled=true)
    protected void test_selenium_broken_images_appr_1()
    {
        Integer iBrokenImageCount = 0;
        driver.navigate().to(URL);
        driver.manage().window().maximize();
        try
        {
            iBrokenImageCount = 0;
            List<WebElement> image_list = driver.findElements(By.tagName("img"));
            /* Print the total number of images on the page */
            System.out.println("The page under test has " + image_list.size() + " images");
            for (WebElement img : image_list)
            {
                if (img != null)
                {
                    HttpClient client = HttpClientBuilder.create().build();
                    HttpGet request = new HttpGet(img.getAttribute("src"));
                    HttpResponse response = client.execute(request);
                    /* For valid images, the HttpStatus will be 200 */
                    if (response.getStatusLine().getStatusCode() != 200)
                    {
                        System.out.println(img.getAttribute("outerHTML") + " is broken.");
                        iBrokenImageCount++;
                    }
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            status = "failed";
            System.out.println(e.getMessage());
        }
        status = "passed";
        System.out.println("The page " + URL + " has " + iBrokenImageCount + " broken images");
    }
    @Test(description="Approach 2: Find broken images on a web page using Selenium WebDriver", enabled = true)
    protected void test_selenium_broken_images_appr_2()
    {
        Integer iBrokenImageCount = 0;
        driver.navigate().to(URL);
        driver.manage().window().maximize();
        try
        {
            iBrokenImageCount = 0;
            List<WebElement> image_list = driver.findElements(By.tagName("img"));
            /* Print the total number of images on the page */
            System.out.println("The page under test has " + image_list.size() + " images");
            for (WebElement img : image_list)
            {
                if (img != null)
                {
                    if (img.getAttribute("naturalWidth").equals("0"))
                    {
                        System.out.println(img.getAttribute("outerHTML") + " is broken.");
                        iBrokenImageCount++;
                    }
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            status = "failed";
            System.out.println(e.getMessage());
        }
        status = "passed";
        System.out.println("The page " + URL + " has " + iBrokenImageCount + " broken images");
    }
    @AfterClass
    public void tearDown()
    {
        if (driver != null) {
            ((JavascriptExecutor) driver).executeScript("lambda-status=" + status);
            driver.quit();
        }
    }
}

代码演练。方法1

1.导入所需的包。A pache HttpClient库用于处理HTTP请求。要使用最新版本的HttpClient库,需要在Maven构建文件(pom.xml)中添加该库的依赖性

爪哇

<dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.13</version>
</dependency>

为了找到被测试页面上的破损图片,HttpClient库被用来检查页面上图片的状态代码。必要的包被导入,以便在实现中使用其方法。

爪哇

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;

2.找到页面上的所有图像**。** Selenium中的findElements 方法被用来获取页面上所有图像的细节。使用tagName "img" 来定位图片。

这些图片被放置在一个列表中,这个列表将被进一步迭代以找到页面上的破损图片。

爪哇

List<WebElement> image_list = driver.findElements(By.tagName("img"));
System.out.println("The page under test has " + image_list.size() + " images");

3.创建一个HttpClient的新实例**。**HttpClient类提供了一个API,主要由三个核心类组成。HttpClient,HttpRequest, 和HttpResponseHttpResponse 描述了HttpRequest调用的结果。为了读取响应体,我们创建了一个新的HttpClient 的实例并请求对象。该类的新实例是通过HttpClientBuilder 类的build() 方法创建的。

爪哇

HttpClient client = HttpClientBuilder.create().build();

4.创建一个HttpGet的新实例。 CloseableHttpClient提供了发送和接收数据的执行方法。execute方法使用HttpUriRequest类型的参数,它有许多子类,包括HttpGetHttpPost

我们首先创建一个新的HttpGet 对象,其HttpUriRequest设置为通过读取WebElement img中的src 属性而获取的路径。

爪哇

HttpGet request = new HttpGet(img.getAttribute("src"));

例如,getAttribute(“src”) "Fork me on GitHub "的图片将返回/img/forkme_right_green_007200.png。

5.检索响应对象。 execute 方法使用默认上下文执行HTTP请求。它返回响应体(即:HttpResponse )。

爪哇

HttpResponse response = client.execute(request);

6.读取状态代码。 HttpResponse 类的getStatusLine 方法获得响应的状态行(从步骤5获得)。getStatusCode 方法以整数格式返回HttpStatus。响应代码200(SC_OK)意味着HTTP请求被成功执行。

爪哇

if (response.getStatusLine().getStatusCode() != 200)
{
System.out.println(img.getAttribute("outerHTML") + " is broken.");
iBrokenImageCount++;
}

如果HttpStatus是200,相关的图像没有被破坏,而被破坏的图像的HttpStatus是404。对图像列表中的所有WebElement条目重复步骤3-6。破损图像的外层HTML属性被打印出来,供终端参考。

代码演练。方法2

**1.找到页面上的所有图片。**与方法1中的步骤2类似,Selenium中的findElements 方法被用来获取图片上存在的细节。tagName imgfindElements 方法一起使用,以实现同样的目的。

爪哇

List< WebElement > image_list = driver.findElements(By.tagName("img"));

2.读取naturalWidth属性。在步骤1中确定的WebElements的naturalWidth 属性被读取。对于破损的图像,naturalWidth 将是零,而对于正常的图像,它是不为零的。

爪哇

f (img.getAttribute("naturalWidth").equals("0"))
{
System.out.println(img.getAttribute("outerHTML") + " is broken.");
      iBrokenImageCount++;
}

对于在步骤1中获得的列表image_list 中的所有WebElements,重复步骤2。变量iBrokenImageCount 表示页面上破碎图像的数量。

执行情况

下面显示的是方法1和方法2的执行快照。正如预期的那样,我们看到在被测试的网页上有两个破损的图片。

如何使用Selenium Python查找破损的图片

执行

文件名 - test_brokenimages.py

Python

import requests
import urllib3
import pytest
from requests.exceptions import MissingSchema, InvalidSchema, InvalidURL
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
capabilities = {
    "build": "[Python] Finding broken images on a webpage using Selenium",
    "name": "[Python] Finding broken images on a webpage using Selenium",
    "platform": "Windows 10",
    "browserName": "Chrome",
    "version": "latest"
}
user_name = "user-name"
app_key = "access-key"
URL = "https://the-internet.herokuapp.com/broken_images"
iBrokenImageCount = 0
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
remote_url = "http://" + user_name + ":" + app_key + "@hub.lambdatest.com/wd/hub"
driver = webdriver.Remote(command_executor=remote_url, desired_capabilities=capabilities)
driver.maximize_window()
driver.get(URL)
image_list = driver.find_elements(By.TAG_NAME, "img")
print('Total number of images on '+ URL + ' are ' + str(len(image_list)))
for img in image_list:
    try:
        response = requests.get(img.get_attribute('src'), stream=True)
        if (response.status_code != 200):
            print(img.get_attribute('outerHTML') + " is broken.")
            iBrokenImageCount = (iBrokenImageCount + 1)
    except requests.exceptions.MissingSchema:
        print("Encountered MissingSchema Exception")
    except requests.exceptions.InvalidSchema:
        print("Encountered InvalidSchema Exception")
    except:
        print("Encountered Some other Exception")
driver.quit()
print('The page ' + URL + ' has ' + str(iBrokenImageCount) + ' broken images')

代码演练

**1.导入模块。**请求模块被导入,这样我们就可以向目标URL发送HTTP请求。如果开发机器上没有安装requests模块,请运行pip install requests ,安装相同的模块。

Python

import requests
import urllib3
from requests.exceptions import MissingSchema, InvalidSchema, InvalidURL

2.获取页面上存在的图像的详细信息。使用Selenium的find_elements 方法读取带有"img" 标签的WebElements。

读取

image_list = driver.find_elements(By.TAG_NAME, "img")

3.发送一个HTTP请求。 requests模块中的get() 方法向传递给它的URL发送一个GET请求。img 标签中的src 属性包含服务器上的图像位置。它被传递给requests.get() 方法。get() 方法中的Stream 被设置为真,所以对 HTTP 请求的响应被立即下载。

Python

response = requests.get(img.get_attribute('src'), stream=True)

作为回报,我们得到requests.Response() 对象,其中包含服务器对HTTP请求的响应。

4.从响应对象中读取状态代码。 requests.Response() 对象中的status_code 属性表示HTTP请求的状态。HTTP状态代码为200意味着图像没有被破坏,而如果状态代码为404,则图像被破坏。

蟒蛇

if (response.status_code != 200):
   print(img.get_attribute('outerHTML') + " is broken.")
   iBrokenImageCount = (iBrokenImageCount + 1)

对列表中的所有WebElement条目重复步骤3到4(即image_list )。

执行

我们通过在终端上触发命令python <file_name.py> 来运行该文件。如下图所示,在被测试的页面上发现了两个破损的图片。

如何使用Selenium C#查找破损的图片

执行

文件名 - BrokenImageTest.cs

C#

using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Chrome;
using NUnit.Framework;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using OpenQA.Selenium.Remote;
using System;
using System.Threading;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestBrokenImages
{
    [TestFixture("chrome", "latest", "Windows 10")]
    public class TestBrokenImages
    {
        private String browser;
        private String version;
        private String os;
        IWebDriver driver;
        public TestBrokenImages(String browser, String version, String os)
        {
            this.browser = browser;
            this.version = version;
            this.os = os;
        }
        [SetUp]
        public void Init()
        {
            String username = "user-name";
            String accesskey = "access-key";
            String gridURL = "@hub.lambdatest.com/wd/hub";
            DesiredCapabilities capabilities = new DesiredCapabilities();
            capabilities.SetCapability("user", username);
            capabilities.SetCapability("accessKey", accesskey);
            capabilities.SetCapability("browserName", browser);
            capabilities.SetCapability("version", version);
            capabilities.SetCapability("platform", os);
            capabilities.SetCapability("build", "[C#] Finding broken images on a webpage using Selenium");
            capabilities.SetCapability("name", "[C#] Finding broken images on a webpage using Selenium");
            driver = new RemoteWebDriver(new Uri("https://" + username + ":" + accesskey + gridURL), capabilities, TimeSpan.FromSeconds(600));
            System.Threading.Thread.Sleep(2000);
        }
        [Test]
        public async Task LT_Broken_Images_Test()
        {
            int broken_images = 0;
            String test_url = "https://the-internet.herokuapp.com/broken_images";
            driver.Url = test_url;
            using var client = new HttpClient();
            var image_list = driver.FindElements(By.TagName("img"));
            /* Loop through all the images */
            foreach (var img in image_list)
            {
                try
                {
                    /* Get the URI */
                    HttpResponseMessage response = await client.GetAsync(img.GetAttribute("src"));
                    /* Reference - https://docs.microsoft.com/en-us/dotnet/api/system.net.httpwebresponse.statuscode?view=netcore-3.1 */
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        System.Console.WriteLine("Image at the link " + img.GetAttribute("src") + " is OK, status is "
                                + response.StatusCode);
                    }
                    else
                    {
                        System.Console.WriteLine("Image at the link " + img.GetAttribute("src") + " is Broken, status is "
                                + response.StatusCode);
                        broken_images++;
                    }
                }
                catch (Exception ex)
                {
                    if ((ex is ArgumentNullException) ||
                   	(ex is NotSupportedException))
                    {
                        System.Console.WriteLine("Exception occured\n");
                    }
                }
            }
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
            Console.WriteLine("\nThe page " + test_url + " has " + broken_images + " broken images");
        }
        [TearDown]
        public void Cleanup()
        {
            if (driver != null)
                driver.Quit();
        }
    }
}

代码演练

我们使用了NUnit框架进行演示。你可以查看我们早期的博客:NUnit测试自动化与Selenium C#来开始使用NUnit框架。

1.包括HttpClient命名空间。 HttpClient类提供了用于发送HTTP请求并从URI标识的资源中接收相应响应的基类。

建议使用HttpClient ,而不是HttpWebRequest (属于System.Net.HttpWebRequest 命名空间),以便使用Selenium WebDriver检测破碎的图像。

C#

using System.Net.Http;
using System.Threading.Tasks;

2.创建一个方法,返回一个异步任务。 GetAsync 方法用于向指定的URI发送一个GET请求,作为一个异步操作。

C#

[Test]
public async Task LT_Broken_Images_Test()
{

**3.创建一个HttpClient的实例。**一个HttpClient 的实例被创建。HttpClient 类所提供的方法将被进一步用于获取被测试页面上的图像的详细信息。

C#

using var client = new HttpClient();

4.读取页面上的图像。通 过使用TagName "img" 属性定位WebElements来获取页面上存在的图像的详细信息。

C#

var image_list = driver.FindElements(By.TagName("img"));

findElements 方法返回一个列表,通过迭代来检查页面上破碎的图像。

5.遍历图像列表以检查破碎的图像。H ttpClient类中的GetAsync 方法会向相应的URI发送一个异步GET请求。使用GetAttribute 方法收集的锚的src 属性的值被传递到GetAsync 方法中。

C#

foreach (var img in image_list)
{
  try
  {
    /* Get the URI */
    HttpResponseMessage response=await client.GetAsync(img.GetAttribute("src"));

6.读取HttpStatus代码。在 步骤5中的Async操作完成后,会返回HttpResponseMessage。该响应包括数据和状态代码。响应代码HttpStatusCode.OK (即200)表示图像位于服务器上,并且被成功读取。我们保留一个页面上破损图片数量的计数器。

C#

if (response.StatusCode == HttpStatusCode.OK)
{
System.Console.WriteLine("Image at the link " + img.GetAttribute("src") + " is OK, status is "+ response.StatusCode);
}
else
{
System.Console.WriteLine("Image at the link " + img.GetAttribute("src") + " is Broken, status is "+ response.StatusCode);
broken_images++;
}

异常NotSupportedExceptionArgumentNullException 是作为异常处理的一部分来处理的。

C#

catch (Exception ex)
{
if ((ex is ArgumentNullException) ||  (ex is NotSupportedException))
{
   	System.Console.WriteLine("Exception occured\n");
}
}

执行情况

这里是执行快照,它表明在被测试的页面上有两个破碎的图像。

如何使用Selenium PHP查找破损的图片

执行

文件名 - composer.json

脚本

{
   "require":{
      "php":">=7.1",
      "phpunit/phpunit":"^9",
      "phpunit/phpunit-selenium": "*",
      "php-webdriver/webdriver":"*"
   }
}

文件名 - tests\BrokenImageTest.php

脚本

<?php
require 'vendor/autoload.php';
use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;
$GLOBALS['LT_USERNAME'] = "user-name";
# accessKey:  AccessKey can be generated from automation dashboard or profile section
$GLOBALS['LT_APPKEY'] = "access-key";
class BrokenImageTest extends TestCase
{
  protected $webDriver;
  
  public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" => "[PHP] Finding broken images on a webpage using Selenium",
      "name" => "[PHP] Finding broken images on a webpage using Selenium",
      "platform" => "macOS High Sierra",
      "browserName" => "MicrosoftEdge",
      "version" => "latest"
    );
    return $capabilities;
  }
  
  public function setUp(): void
  {
    $capabilities = $this->build_browser_capabilities();
    /* Download the Selenium Server 3.141.59 from
    https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar
    */
    $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub";
    $this->webDriver = RemoteWebDriver::create($url, $capabilities);
  }
  public function tearDown(): void
  {
    $this->webDriver->quit();
  }
  /*
  * @test
  */
  public function test_searchbrokenimages()
  {
    $test_url = "https://the-internet.herokuapp.com/broken_images";
    # For site with absolute path
    # $test_url = "https://www.lambdatest.com/blog";
    # End - For site with absolute path
    $base_url = "https://the-internet.herokuapp.com/";
    
    $driver = $this->webDriver;
    $driver->get($test_url);
    $this->assertEquals("The Internet", $driver->getTitle());
    # For site with absolute path
    # $this->assertEquals("LambdaTest | A Cross Browser Testing Blog", $driver->getTitle());
    # End - For site with absolute path
    $driver->manage()->window()->maximize();
    $iBrokenImageCount = 0;
    
    /* file_get_contents is used to get the page's HTML source */
    $html = file_get_contents($test_url);
    /* Instantiate the DOMDocument class */
    $htmlDom = new DOMDocument;
    /* The HTML of the page is parsed using DOMDocument::loadHTML */
    @$htmlDom->loadHTML($html);
    /* Extract the links from the page */
    $image_list = $htmlDom->getElementsByTagName('img');
    /* The DOMNodeList object is traversed to check for its validity */
    foreach($image_list as $img)
    {
        $img_path = $img->getAttribute('src');
        # Convert relative path to absolute path
        $search_path = "/" . $img_path;
        $abs_path = relative2absolute($search_path, $base_url);
        # When absolute path is used for fetching the images
        # For site with absolute path
        # $abs_path = $img_path;
        # For site with absolute path
        $response = @get_headers($abs_path);
        if (preg_match("|200|", $response[0]))
        {
          print($abs_path . " is not broken\n");
        }
        else
        {
          print($abs_path . " is broken\n");
          $iBrokenImageCount = $iBrokenImageCount + 1;
        }
    }
    print("\nThe page " . $test_url . " has " . $iBrokenImageCount . " broken images");
  }
}
?>
<?php
    function relative2absolute($rel_path, $base_path)
    {
        /* return if already absolute URL */
        if (parse_url($rel_path, PHP_URL_SCHEME) != '') return $rel_path;
    
        /* queries and anchors */
        if ($rel_path[0]=='#' || $rel_path[0]=='?') return $base_path.$rel_path;
    
        /* parse base URL and convert to local variables:
            $scheme, $host, $path */
        extract(parse_url($base_path));
    
        /* remove non-directory element from path */
        $new_path = preg_replace('#/[^/]*$#', '', $base_path);
    
        /* destroy path if relative url points to root */
        if ($rel_path[0] == '/') $new_path = '';
    
        /* dirty absolute URL */
        $abs_path = "$host$new_path/$rel_path";
    
        /* replace '//' or '/./' or '/foo/../' with '/' */
        $repl = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
        for($counter=1; $counter>0; $abs_path=preg_replace($repl, '/', $abs_path, -1, $counter)) {}
    
        /* absolute URL is ready! */
        return $scheme.'://'.$abs_path;
    }
?>

代码演练

为了用Selenium PHP找到破损的图像,我们将使用PHPUnit框架和Selenium。请参考我们详细的 Selenium PHP 教程,快速回顾一下 Selenium 与 PHPUnit 的关系。

在终端上运行 composer 命令,安装 composer.json 中提到的软件包。

下面是源代码的整体演练。

**1.阅读页面源代码。**使用PHP中的file_get_contents 函数读取被测页面的HTML源(即the-internet.herokuapp.com/)。HTML源被读入一个本地字符串变量$html

脚本

$html = file_get_contents($test_url);

2.实例化DOMDocument类。整个HTML文档被表示在DOMDocument 类中。它也作为源树的根。

编写PHP

$htmlDom = new DOMDocument;

**3.解析页面的HTML源。**PHP中的DOMDocument::loadHTML() 函数解析了String变量中的HTML源$html 。该函数在成功执行后返回一个DOMDocument对象。

PHP

@$htmlDom->loadHTML($html);

4.使用 "img "标签提取图片。 <img> HTML标签中的条目是使用DOMDocument类的getElementsByTagName 方法读取的。由于我们正在寻找破碎的图像,搜索是基于解析的HTML源中的<img> 标签。

PHP

$image_list = $htmlDom->getElementsByTagName('img');

5.读取 "src "属性中所包含的条目。 "src" 属性的值是从步骤4中提取的<img> 条目中读取的。

读取

$img_path = $img->getAttribute('src');

例如,<img src=”img/avatar-blank.jpg”> 中的src 属性是“img/avatar-blank.jpg”

6.将相对路径转换为绝对路径。这一步只适用于<img> 标签中的src 属性从文档的根部返回相对路径。

这种情况下,图片是使用相对路径读取的。

以LambdaTest博客为例,博客中的图片是使用服务器上图片的绝对路径读取的。下面显示的是一个例子,说明图片的绝对路径是如何在<img> 标签的src 属性中使用的。

我们创建了一个新的函数relative2absolute() ,它接受以下参数:从<src> 属性中获得的相对路径和被测URL的根文档。

PHP

<?php
function relative2absolute($rel_path, $base_path)
{
        /* return if already absolute URL */
        if (parse_url($rel_path, PHP_URL_SCHEME) != '') return $rel_path;
    
        /* queries and anchors */
        if ($rel_path[0]=='#' || $rel_path[0]=='?') return $base_path.$rel_path;
    
        /* parse base URL and convert to local variables:
            $scheme, $host, $path */
        extract(parse_url($base_path));
  .............................................
        .............................................
        .............................................
}
  • 相对路径(样本)
    • 这个例子中,相对路径相当于/$img_path 。如果$img_pathimg/avatar-blank.jpg ,那么relative2absolute 函数最终使用的相对路径将是/img/avatar-blank.jpg 。基本的URL被设置为the-internet.herokuapp.com/

PHP

$test_url = "https://the-internet.herokuapp.com/broken_images";
..........................................................
..........................................................
..........................................................
# Convert relative path to absolute path
$search_path = "/" . $img_path;
$abs_path = relative2absolute($search_path, $base_url);
  • 绝对路径(样本)
    • 如果在<src> 属性中使用了绝对路径,那么绝对路径和相对路径将是一样的。在这种情况下,步骤6就成为可有可无的了。

脚本

$test_url = "https://www.lambdatest.com/blog";
..........................................................
..........................................................
..........................................................
$img_path = $img->getAttribute('src');
$abs_path = $img_path;
  • 在StackOverflow社区的支持下,我们想出了relative2absolute 这个函数☺。

7.将相对路径转换为绝对路径。 get_headers() 函数用于获取服务器响应HTTP请求时发送的所有头文件。对于破损的图片,HTTP状态码是404,而如果图片在服务器上存在,则状态码是200。

PHP中的preg_match() 函数对响应代码中的 "200"(如果请求成功完成的HTTP状态代码)进行不区分大小写的搜索。当页面上有破损的图像时,本地变量iBrokenImageCount 被递增。

脚本

$response = @get_headers($abs_path);
if (preg_match("|200|", $response[0]))
{
print($abs_path . " is not broken\n");
}
else
{
print($abs_path . " is broken\n");
$iBrokenImageCount = $iBrokenImageCount + 1;
}

执行

要运行使用PHPUnit框架的测试,从根文件夹中运行以下命令。

PHP

vendor\bin\phpunit  --debug test

当测试针对the-internet.herokuapp.com/broken_imag…它显示页面有两个破损的图片。

我们在对 "对于有绝对路径的网站 "注释下的代码做了最小的修改后,针对LambdaTest博客执行了同样的测试。

该网站在img 标签的<src> 属性中使用绝对路径。如下图所示,LambdaTest博客上的图片没有任何损坏。

这就是全部,伙计们

就像网页上的破损链接一样,破损的图片也可能阻碍整个用户体验。它还会对搜索排名产生负面影响,从而妨碍你的SEO工作。与其依赖第三方工具,将隐私和数据置于危险之中,不如使用Selenium WebDriver来查找破损的图片。在这个Selenium教程中,我们看了如何用Java、Python、C#和PHP语言的Selenium WebDriver来寻找破损的图片。

你是按照什么策略来寻找网页上的破损图片的?请在评论区留下你的想法。

测试愉快☺。

主题。

webdriver

经DZone MVB的Praveen Mishra许可,发表于DZone。点击这里查看原文。

DZone贡献者所表达的观点属于他们自己。

DZone上的热门文章


评论

网络开发 合作伙伴资源