Автоматизированное тестирование производительности страниц на основе Selenium и ChromeDriver.
Автоматизированное тестирование производительности страниц на основе Selenium и ChromeDriver.

Всем привет, мы снова встретились, я ваш друг Цюаньчжаньцзюнь.

Потому что работа в последнее время была очень напряженной,На первомайские праздники пришлось долго откладывать это дело.SeleniumВнедрить автоматизированные страницыпроизводительностьтестДобавлена ​​часть реализации кода,Надеюсь, в будущем я смогу быть более прилежным,Больше производства знаний。 Selenium WebDriver (далее — ПО) предоставляет набор инструментов автоматического тестирования веб-приложений. Программное обеспечение можно разделить на различные сценарии применения в соответствии со сценариями его применения: (1) реализация без интерфейса на основе HtmlUnit, которая не использует для тестирования реальные браузеры (2) имитирует реальный ввод, поддерживает и тестирует несколько браузеров, включая FirefoxDriver; InternetExplorerDriver, OperaDriver и ChromeDriver (3) Тестирование мобильных приложений, включая AndroidDriver и iPhoneDriver; Уже существует множество статей и книг по функциональному проектированию ПО.,Например, как получить содержимое элемента страницы。В этой статье речь пойдет о том, как на основеSeleniumиChromeDriverСоздать страницупроизводительностьтест,Например, получите время загрузки запроса страницы, получите время завершения загрузки элемента DOM страницы и т. д. Он похож на прототипы реализации некоторых зрелых продуктов для дозвона (это тоже проект, над которым работает автор). Я думаю, что это очень значимое исследование.

1. Зависимости Maven

Прежде всего, в проекте необходимо ввести зависимые пакеты селена: selenium-api и selenium-java. Необходимо учитывать совместимость разных версий и версий JDK. Автор — JDK 1.8.

Язык кода:javascript
копировать
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-api -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-api</artifactId>
    <version>3.5.3</version>
</dependency>
Язык кода:javascript
копировать
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.5.3</version>
</dependency>

2. Подробное объяснение использования ChromeDriver.

Ссылка на этот разделhttps://sites.google.com/a/chromium.org/chromedriver/home,Кроме того, установка ChromeDriver,Автор находится в《CentOS Сборка в среде 7.x: Headless chrome + Selenium + ChromeDriver выполнить Автоматизация》Подробно в。

2.1、DesiredCapabilities & ChromeOptions

CapabilitiesСвойства могут быть определеныинастроить свойChromeDriverсессия,для выполнения соответствующих функцийинуждаться。 существоватьJavaвыполнитьсередина,добрыйChromeOptionsидобрыйDesiredCapabilitiesможет использоваться для конкретных определенийCapabilities。 Например, следующий код,проходитьChromeOptionsопределитьChromeизwindow-sizeсвойство:

Язык кода:javascript
копировать
// Установить путь к хромдрайверу
System.setProperty("webdriver.chrome.driver","/opt/drivers/chromedriver");

ChromeOptions options = new ChromeOptions();
// Установить размер при запуске Chrome
options.addArguments("--window-size=1980,1000");
// Создать экземпляр ChromeDriver на основе ChromeOptions
WebDriver driver = new ChromeDriver(options);
try {
    // Открыть Suning.com
    driver.get("https://www.suning.com");
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    // Закрыть браузер
    driver.quit();
}

конечно,Приведенный выше пример также можно переписать какпроходитьDesiredCapabilitiesПриходитьвыполнить:

Язык кода:javascript
копировать
// Установить путь к хромдрайверу
System.setProperty("webdriver.chrome.driver","/opt/drivers/chromedriver");

ChromeOptions options = new ChromeOptions();
// Установить размер при запуске Chrome
options.addArguments("--window-size=1980,1000");
DesiredCapabilities cap = DesiredCapabilities.chrome();
cap.setCapability(ChromeOptions.CAPABILITY, options);
// Создание экземпляра ChromeDriver на основе желаемых возможностей
WebDriver driver = new ChromeDriver(cap);
try {
    // Открыть Suning.com
    driver.get("https://www.suning.com");
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    // Закрыть браузер
    driver.quit();
}

2.2、Performance Log

ChromeDriver поддерживает журналы производительности (Производительность Журнал) сбор данных. Подумайте о консоли Chrome F12. Мы можем собрать «Сеть», «Страница» и т. д., и это основа для тестирования производительности страницы. Performance LogПо умолчанию он не включенизсвойство,так что мы можемпроходить В предыдущем разделе говорилосьизDesiredCapabilitiesсуществоватьсоздавать новыесессияизпора открыватьPerformance Log。 И собрализбревно,мы можемпроходитьLogEntryвывод объекта вConsole。конкретный кодвыполнитьследующее:

Язык кода:javascript
копировать
package com.suning.webdrivertest.chromedemo;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.util.logging.Level;

/** * * Created by zhuyiquan90 on 2018/1/3. */
public class ChromeDriverDemo1 { 
   

    public static void main(String[] args) {

        // Установить путь к хромдрайверу
        System.setProperty("webdriver.chrome.driver", "/opt/drivers/chromedriver");

        DesiredCapabilities cap = DesiredCapabilities.chrome();
        LoggingPreferences logPrefs = new LoggingPreferences();
        // Включить производительность Сбор журналов
        logPrefs.enable(LogType.PERFORMANCE, Level.ALL);
        cap.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);

        // Создание экземпляра ChromeDriver на основе желаемых возможностей
        WebDriver driver = new ChromeDriver(cap);
        try {
            // Открыть Suning.com
            driver.get("https://www.suning.com");
            for (LogEntry entry : driver.manage().logs().get(LogType.PERFORMANCE)) {
                // Вывод собранных журналов производительности
                System.out.println(Thread.currentThread().getName() + entry.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Закрыть браузер
            driver.quit();
        }
    }
}

Вывод следующий:

Язык кода:javascript
копировать
Starting ChromeDriver 2.34.522932 (4140ab217e1ca1bec0c4b4d1b148f3361eb3a03e) on port 29777
Only local connections are allowed.
апрель 30, 2018 3:06:27 полдень org.openqa.selenium.remote.ProtocolHandshake createSession
информация: Detected dialect: OSS
main[2018-04-30T15:06:27+0800] [INFO] {
  
  "message":{
  
  "method":"Page.frameAttached","params":{
  
  "frameId":"49C70573CE1145CEB5B38A270213A48","parentFrameId":"28DAFE9FE90E9292F1B8EDB3315608EC","stack":{
  
  "callFrames":[{
  
  "columnNumber":240,"functionName":"","lineNumber":0,"scriptId":"21","url":""}]}}},"webview":"28DAFE9FE90E9292F1B8EDB3315608EC"}
main[2018-04-30T15:06:27+0800] [INFO] {
  
  "message":{
  
  "method":"Page.frameStartedLoading","params":{
  
  "frameId":"49C70573CE1145CEB5B38A270213A48"}},"webview":"28DAFE9FE90E9292F1B8EDB3315608EC"}
main[2018-04-30T15:06:27+0800] [INFO] {
  
  "message":{
  
  "method":"Page.frameNavigated","params":{
  
  "frame":{
  
  "id":"49C70573CE1145CEB5B38A270213A48","loaderId":"EE699DC52C8ACA226069D24DC92E16","mimeType":"text/html","name":"chromedriver dummy frame","parentId":"28DAFE9FE90E9292F1B8EDB3315608EC","securityOrigin":"://","url":"about:blank"}}},"webview":"28DAFE9FE90E9292F1B8EDB3315608EC"}

2.3、Chrome DevTools Protocol View

этот раздел,Давайте поговорим об этомNetworkиPageВключатьизсодержание,То есть для вывода контента в предыдущем разделе,Как мы можем эффективно использовать,проходить它们Приходить计算页面производительность(ссылкаChrome DevTools Protocol)。

2.3.1、Network

Основными событиями, которые мы используем в Network, являются requestWillBeSent, responseReceived, loadingFailed и loadingFinished:

Network.requestWillBeSent

Срабатывает, когда страница собирается отправить HTTP-запрос, ее формат Json:

Язык кода:javascript
копировать
{
    "message": { "method": "Network.requestWillBeSent", "params": { "documentURL": "about:blank", "frameId": "C80F96297F4216E35079CFD86251AB8B", "initiator": { "lineNumber": 0, "type": "parser", "url": "https://www.suning.com/" }, "loaderId": "58DDB2CF16600EAE484A541DF9440089", "redirectResponse": { "connectionId": 639, "connectionReused": false, "encodedDataLength": 497, "fromDiskCache": false, "fromServiceWorker": false, "headers": { "Cache-Control": "no-cache", "Connection": "keep-alive", "Content-Length": "0", "Date": "Mon, 30 Apr 2018 07:06:42 GMT", "Expires": "Thu, 01 Jan 1970 00:00:00 GMT", "Location": "https://cm.g.doubleclick.net/pixel?google_nid=ipy&google_cm", "P3P": "CP=\"NON DSP COR CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa CONa HISa TELa OTPa OUR UNRa IND UNI COM NAV INT DEM CNT PRE LOC\"", "Pragma": "no-cache", "Server": "nginx/1.10.2", "Set-Cookie": "CMBMP=IWl; Domain=.ipinyou.com; Expires=Thu, 10-May-2018 07:06:42 GMT; Path=/" }, "headersText": "HTTP/1.1 302 Found\r\nServer: nginx/1.10.2\r\nDate: Mon, 30 Apr 2018 07:06:42 GMT\r\nContent-Length: 0\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\r\nP3P: CP=\"NON DSP COR CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa CONa HISa TELa OTPa OUR UNRa IND UNI COM NAV INT DEM CNT PRE LOC\"\r\nSet-Cookie: CMBMP=IWl; Domain=.ipinyou.com; Expires=Thu, 10-May-2018 07:06:42 GMT; Path=/\r\nLocation: https://cm.g.doubleclick.net/pixel?google_nid=ipy&google_cm\r\n\r\n", "mimeType": "", "protocol": "http/1.1", "remoteIPAddress": "127.0.0.1", "remotePort": 1086, "requestHeaders": { "Accept": "image/webp,image/apng,image/*,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Cookie": "sessionId=I4UF6b1WcgGMC; PYID=I4UF6b1Wcg99; CMTMS=p7Ik3Ve; CMSTMS=p7Ik3Ve; CMPUB=ADV-DefaultAdv; CMBMP=IW2", "Host": "cm.ipinyou.com", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" }, "requestHeadersText": "GET /baidu/cms.gif?baidu_error=1&timestamp=1525072001 HTTP/1.1\r\nHost: cm.ipinyou.com\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: sessionId=I4UF6b1WcgGMC; PYID=I4UF6b1Wcg99; CMTMS=p7Ik3Ve; CMSTMS=p7Ik3Ve; CMPUB=ADV-DefaultAdv; CMBMP=IW2\r\n", "securityDetails": { "certificateId": 0, "cipher": "AES_256_GCM", "issuer": "RapidSSL SHA256 CA", "keyExchange": "ECDHE_RSA", "keyExchangeGroup": "P-256", "protocol": "TLS 1.2", "sanList": ["*.ipinyou.com", "ipinyou.com"], "signedCertificateTimestampList": [{ "hashAlgorithm": "SHA-256", "logDescription": "Symantec log", "logId": "DDEB1D2B7A0D4FA6208B81AD8168707E2E8E9D01D55C888D3D11C4CDB6ECBECC", "origin": "Embedded in certificate", "signatureAlgorithm": "ECDSA", "signatureData": "3045022024364934CBC90A8529E327E6EF853E3EF5E48B7F1598414E0F10059DC92685FC022100A74F93A8CF23D6572D7597C072368D69EC43AFB6A9EDAA4B01B43921AADEFDC2", "status": "Verified", "timestamp": 1511173770857.0 }, { "hashAlgorithm": "SHA-256", "logDescription": "Google 'Pilot' log", "logId": "A4B90990B418581487BB13A2CC67700A3C359804F91BDFB8E377CD0EC80DDC10", "origin": "Embedded in certificate", "signatureAlgorithm": "ECDSA", "signatureData": "3046022100F319D0F56F27C82228E2B01934A1C7F46915A1509F094EE91508F08C3B5AE2B2022100B0D94DD6FD00CB435EC33B916B52EC76FE5FFCC5D5BD8CB559248243AEDFE3CE", "status": "Verified", "timestamp": 1511173770923.0 }], "subjectName": "*.ipinyou.com", "validFrom": 1511136000, "validTo": 1547942399 }, "securityState": "secure", "status": 302, "statusText": "Found", "timing": { "connectEnd": 772.852999994939, "connectStart": 0.566999995498918, "dnsEnd": -1, "dnsStart": -1, "proxyEnd": -1, "proxyStart": -1, "pushEnd": 0, "pushStart": 0, "receiveHeadersEnd": 1226.29800000141, "requestTime": 42129.997749, "sendEnd": 773.012999998173, "sendStart": 772.960999995121, "sslEnd": 772.844999999506, "sslStart": 1.62599999748636, "workerReady": -1, "workerStart": -1 }, "url": "https://cm.ipinyou.com/baidu/cms.gif?baidu_error=1&timestamp=1525072001" }, "request": { "headers": { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" }, "initialPriority": "Low", "method": "GET", "mixedContentType": "none", "referrerPolicy": "no-referrer-when-downgrade", "url": "https://cm.g.doubleclick.net/pixel?google_nid=ipy&google_cm" }, "requestId": "20524.247", "timestamp": 42131.225431, "type": "Image", "wallTime": 1525072000.35906 } },
    "webview": "28DAFE9FE90E9292F1B8EDB3315608EC" }

Описание параметра:

параметр

тип

иллюстрировать

requestId

String

Уникальный идентификатор запроса

loaderId

String

Идентификатор загрузки

documentURL

String

URL-адрес документа страницы

request

Request

Запросить объект данных

timestamp

float

В качестве базовой точки принимается произвольный момент времени в прошлом, временная метка, которая монотонно увеличивается в секундах с момента открытия страницы.

wallTime

float

время UTC

initiator

Initiator

Запросить объект инициализации

redirectResponse

Response

Перенаправить объект ответа

type

String

Тип ресурсов

frameId

String

FrameID

hasUserGesture

boolean

Whether the request is initiated by a user gesture. Defaults to false.

в, Requestобъект:

параметр

тип

иллюстрировать

url

String

URL запроса

method

String

Тип HTTP-запроса

headers

Object

Запросить информацию заголовка

postData

String

Данные запроса публикации

hasPostData

boolean

True, если это запрос на публикацию

mixedContentType

String

Есть ли проблема с запутанным контентом: блокируемый, опционально блокируемый, нет.

initialPriority

String

Приоритет загрузки ресурсов: VeryLow, Low, Medium, High, VeryHigh.

referrerPolicy

String

Междоменная политика: без реферера при переходе на более раннюю версию, без реферера, происхождение, происхождение при перекрестном происхождении, одно и то же происхождение, строгое происхождение, строгое происхождение при перекрестном происхождении

isLinkPreload

boolean

Загружать ли через предварительную загрузку

Responseобъект:

параметр

тип

иллюстрировать

url

String

URL запроса

status

int

Код статуса ответа

statusText

String

Содержимое кода состояния

headers

Object

Заголовок ответа, формат json

headersText

String

Заголовок ответа, текстовый формат

mimeType

String

Resource mimeType

requestHeaders

Obeject

Заголовок запроса, формат json

requestHeadersText

String

Заголовок запроса, текстовый формат

connectionReused

boolean

Будет ли соединение использоваться повторно

connectionId

long

Идентификатор физического соединения

remoteIPAddress

String

Remote IP address

remotePort

int

Remote port

fromDiskCache

boolean

Получать ли ресурсы непосредственно из кеша браузера

fromServiceWorker

boolean

Specifies that the request was served from the ServiceWorker

encodedDataLength

long

Байты ответа

timing

ResourceTiming

Ресурс Тиминг Обжект

protocol

String

протокол

securityState

String

Security state of the request resource:unknown, neutral, insecure, secure, info

securityDetails

SecurityDetails

Security details for the request

ResourceTimingобъект:

параметр

тип

иллюстрировать

requestTime

float

базовое время

proxyStart

float

Started resolving proxy.

proxyEnd

float

Finished resolving proxy.

dnsStart

float

Started DNS address resolve.

dnsEnd

float

Finished DNS address resolve.

connectStart

float

Started connecting to the remote host.

connectEnd

float

Connected to the remote host.

sslStart

float

Started SSL handshake.

sslEnd

float

Finished SSL handshake.

workerStart

float

Started running ServiceWorker.

workerReady

float

Finished Starting ServiceWorker.

sendStart

float

Started sending request.

sendEnd

float

Finished sending request.

pushStart

float

Time the server started pushing request.

pushEnd

float

Time the server finished pushing request.

receiveHeadersEnd

float

Finished receiving response headers.

Network.responseReceived

Запускается, когда доступен HTTP-ответ, его формат Json:

Язык кода:javascript
копировать
{
    "message": { "method": "Network.responseReceived", "params": { "frameId": "28DAFE9FE90E9292F1B8EDB3315608EC", "loaderId": "44DBCD0BEBFCEE5AED6388366BCB719B", "requestId": "20524.277", "response": { "connectionId": 468, "connectionReused": true, "encodedDataLength": 439, "fromDiskCache": false, "fromServiceWorker": false, "headers": { "Cache-Control": "no-cache, max-age=0, must-revalidate", "Connection": "keep-alive", "Content-Length": "43", "Content-Type": "image/gif", "Date": "Mon, 30 Apr 2018 07:06:42 GMT", "Expires": "Fri, 01 Jan 1980 00:00:00 GMT", "Last-Modified": "Mon, 28 Sep 1970 06:00:00 GMT", "Pragma": "no-cache", "Server": "nginx/1.6.3", "X-Dscp-Value": "0", "X-Via": "1.1 dxun38:1 (Cdn Cache Server V2.0), 1.1 shb115:4 (Cdn Cache Server V2.0), 1.1 ls10:0 (Cdn Cache Server V2.0)" }, "headersText": "HTTP/1.1 200 OK\r\nDate: Mon, 30 Apr 2018 07:06:42 GMT\r\nServer: nginx/1.6.3\r\nContent-Type: image/gif\r\nContent-Length: 43\r\nLast-Modified: Mon, 28 Sep 1970 06:00:00 GMT\r\nExpires: Fri, 01 Jan 1980 00:00:00 GMT\r\nPragma: no-cache\r\nCache-Control: no-cache, max-age=0, must-revalidate\r\nX-Dscp-Value: 0\r\nX-Via: 1.1 dxun38:1 (Cdn Cache Server V2.0), 1.1 shb115:4 (Cdn Cache Server V2.0), 1.1 ls10:0 (Cdn Cache Server V2.0)\r\nConnection: keep-alive\r\n\r\n", "mimeType": "image/gif", "protocol": "http/1.1", "remoteIPAddress": "127.0.0.1", "remotePort": 1086, "requestHeaders": { "Accept": "image/webp,image/apng,image/*,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Cookie": "_snstyxuid=ADFD3F4299718846; _snvd=152507199416958111", "Host": "sa.suning.cn", "Referer": "https://www.suning.com/", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" }, "requestHeadersText": "GET /ajaxSiteExpro.gif?oId=152507199969277498&pvId=152507199147454663&expoInfo=index3_homepage1_32618013033_word03,index3_homepage1_32618013033_word04,index3_homepage1_newUser_tankuang&expoType=1&pageUrl=https://www.suning.com/&visitorId=&loginUserName=&memberID=-&sessionId=&pageType=web&hidUrlPattern=&iId=log_1525071999692 HTTP/1.1\r\nHost: sa.suning.cn\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nReferer: https://www.suning.com/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: _snstyxuid=ADFD3F4299718846; _snvd=152507199416958111\r\n", "securityDetails": { "certificateId": 0, "cipher": "AES_256_GCM", "issuer": "WoSign OV SSL CA", "keyExchange": "ECDHE_RSA", "keyExchangeGroup": "P-256", "protocol": "TLS 1.2", "sanList": ["*.suning.cn", "suning.cn"], "signedCertificateTimestampList": [], "subjectName": "*.suning.cn", "validFrom": 1479721356, "validTo": 1574329356 }, "securityState": "secure", "status": 200, "statusText": "OK", "timing": { "connectEnd": -1, "connectStart": -1, "dnsEnd": -1, "dnsStart": -1, "proxyEnd": -1, "proxyStart": -1, "pushEnd": 0, "pushStart": 0, "receiveHeadersEnd": 656.157999997959, "requestTime": 42130.56839, "sendEnd": 1.03800000215415, "sendStart": 0.979999997070991, "sslEnd": -1, "sslStart": -1, "workerReady": -1, "workerStart": -1 }, "url": "https://sa.suning.cn/ajaxSiteExpro.gif?oId=152507199969277498&pvId=152507199147454663&expoInfo=index3_homepage1_32618013033_word03,index3_homepage1_32618013033_word04,index3_homepage1_newUser_tankuang&expoType=1&pageUrl=https://www.suning.com/&visitorId=&loginUserName=&memberID=-&sessionId=&pageType=web&hidUrlPattern=&iId=log_1525071999692" }, "timestamp": 42131.22618, "type": "Image" } },
    "webview": "28DAFE9FE90E9292F1B8EDB3315608EC" }

Описание параметра:

параметр

тип

иллюстрировать

requestId

String

Уникальный идентификатор запроса

timestamp

float

В качестве базовой точки принимается произвольный момент времени в прошлом, временная метка, которая монотонно увеличивается в секундах с момента открытия страницы.

type

String

Тип ресурсов

response

Response

объект ответа

frameId

String

FrameID

Сценарии применения:в соответствии сResponseМожет быстро идентифицировать запросыиз Различные коды состояния исключений(5XX、4XX),и распределение времени.

Network.loadingFailed

Срабатывает, когда HTTP-запрос не может быть загружен, его формат Json:

Язык кода:javascript
копировать
{
    "message": { "method": "Network.loadingFailed", "params": { "canceled": true, "errorText": "net::ERR_ABORTED", "requestId": "20524.271", "timestamp": 42130.877864, "type": "Image" } },
    "webview": "28DAFE9FE90E9292F1B8EDB3315608EC" }

Описание параметра:

параметр

тип

иллюстрировать

requestId

String

Уникальный идентификатор запроса

loaderId

String

Идентификатор загрузки

timestamp

float

В качестве базовой точки принимается произвольный момент времени в прошлом, временная метка, которая монотонно увеличивается в секундах с момента открытия страницы.

type

String

Тип ресурсов

errorText

String

Подскажите причину ошибки

canceled

boolean

Истинно, если запрошенная загрузка была отменена

blockedReason

String

Причина, по которой запрос заблокирован

Сценарии применения:мы можемпроходитьloadingFailedиrequestWillBeSentОпределите, какие запросы не удалось загрузить。

Network.loadingFinished

Срабатывает, когда HTTP-запрос завершает загрузку, его формат Json:

Язык кода:javascript
копировать
{
    "message": { "method": "Network.loadingFinished", "params": { "blockedCrossSiteDocument": false, "encodedDataLength": 327, "requestId": "20524.262", "timestamp": 42130.87542 } },
    "webview": "28DAFE9FE90E9292F1B8EDB3315608EC" }

Описание параметра:

параметр

тип

иллюстрировать

requestId

String

Уникальный идентификатор запроса

timestamp

float

В качестве базовой точки принимается произвольный момент времени в прошлом, временная метка, которая монотонно увеличивается в секундах с момента открытия страницы.

encodedDataLength

long

Байты ответа

blockedCrossSiteDocument

boolean

Истинно, если ответ заблокирован из-за перекрестного происхождения

Сценарии применения:в соответствии сencodedDataLength,Рассчитайте окончательный размер ответа.

Для четырех объектов requestWillBeSent, responseReceived, loadingFailed и loadingFinished модель построения Java выглядит следующим образом:

2.3.2、Page

События, которые мы используем в Page, в основном — это domContentEventFired и loadEventFired:

Page.domContentEventFired

Время завершения загрузки содержимого страницы.

Язык кода:javascript
копировать
{
    "message": { "method": "Page.domContentEventFired", "params": { "timestamp": 42124.003701 } },
    "webview": "28DAFE9FE90E9292F1B8EDB3315608EC" }
Page.loadEventFired

Время завершения загрузки страницы.

Язык кода:javascript
копировать
{
    "message": { "method": "Page.loadEventFired", "params": { "timestamp": 42133.108263 } },
    "webview": "28DAFE9FE90E9292F1B8EDB3315608EC" }

Выше мы можем завершить автоматическое тестирование анализа производительности загрузки страниц на основе ChromeDriver.

3. Использование постоянного ChromeDriverService.

Введение в этот разделChromeDriverService,Это сделано исключительно ради улучшения вашей производительности. Мы знаем, что каждый раз, когда создается ChromeDriver,Освободите этот объект после завершения теста,Подожди, пока в следующий раз не придет новый,Все еще хочу создать новый объект,Неоднократно. Это эквивалентно открытию браузера каждый раз.,Снова Закрыть браузер,Откройте браузер еще раз. Этот метод реализации не подходит для сценариев с высоким уровнем параллелизма. Мы надеемся, что у нас будет та же идея, что и в конструкции пула Java.,Инициализация генерирует несколько постоянных объектов браузера.,Каждый последующий тест будет выполняться с использованием этих объектов браузера.,Это значительно улучшит тестпроизводительность (подумайте об этом,Избегайте повторного созданияизакрыть процессиз Процесс!)。Поэтому введеныChromeDriverService,ChromeDriverServiceэто менеджментChromeDriver Пример персистентности сервера:

The purpose of ChromeDriverService is to manage a persistent instance of the ChromeDriver server. Standard practice is to use the ChromeDriver class or the Selenium standalone server to obtain Chrome driver instances, but this practice sacrifices performance for convenience. In this scenario, each driver instance is associated with its own instance of the ChromeDriver server, which gets launched when the driver is requested and terminated when the driver exits. This per-instance server management adds overhead to test execution, both in terms of run-time and resource utilization. Using ChromeDriverService, this overhead can be reduced to a minimum by enabling your test framework to launch a server instance at the start of the test suite and shut it down when the suite finishes. An example of this approach can be found on the ChromeDriver Getting started page under the heading Controlling ChromeDriver’s lifetime.

Его использование можетссылка:Java Code Examples for org.openqa.selenium.chrome.ChromeDriverService。 Ниже приведена реализованная мной демонстрация. Я создал три потока, каждый из которых содержит объект ChromeDrvierService, что эквивалентно каждому потоку, управляющему процессом браузера. Блокирующая очередь BQ используется для реализации модели производитель-потребитель. Когда в очереди есть задача, она будет назначена потоку для тестирования. ChromeDrvierService не будет уничтожен, если в очереди нет задач. Глубину очереди блокировки и размер пула потоков можно динамически регулировать в зависимости от производительности сервера.

Язык кода:javascript
копировать
package com.suning.webdrivertest.chromedemo;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;

/** * Created by zhuyiquan90 on 2018/1/9. */
public class ChromeDriverDemo2 { 
   
    // Длина очереди блокировки
    private static final int BLOCK_QUEUE_SIZE = 100;
    // Количество потоков драйвера браузера
    private static final int THREAD_SIZE = 3;
    // адрес хромдрайвера
    private static final String chromedriverPath = "opt/drivers/chromedriver";

    private static final BlockingQueue<String> reqQuene = new ArrayBlockingQueue<String>(BLOCK_QUEUE_SIZE);

    static class DriverRunnable implements Runnable {
        private WebDriver driver;
        CountDownLatch latch;

        public DriverRunnable(CountDownLatch latch) {
            ChromeDriverService chromeDriverService = new ChromeDriverService.Builder()
                    .usingDriverExecutable(new File(chromedriverPath))
                    .usingAnyFreePort()
                    .build();

            DesiredCapabilities cap = DesiredCapabilities.chrome();
            LoggingPreferences logPrefs = new LoggingPreferences();
            logPrefs.enable(LogType.PERFORMANCE, Level.ALL);
            cap.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);

            driver = new ChromeDriver(chromeDriverService, cap);
            this.latch = latch;
        }

        public void run() {
            while (true) {
                try {
                    driver.get(reqQuene.take());
                    for (LogEntry entry : driver.manage().logs().get(LogType.PERFORMANCE)) {
                        System.out.println(Thread.currentThread().getName() + entry.toString());
                    }
                    latch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(10);
        for (int i = 0; i < THREAD_SIZE; i++) {
            Thread driverThread = new Thread(new DriverRunnable(latch), "driverThread" + i);
            driverThread.start();
        }
        for (int i = 0; i < 10; i++) {
            reqQuene.put("https://www.suning.com");
        }
        // Цель использования latch.await() — сделать последовательность вывода демо-версии интуитивно понятной и не имеет никакого другого эффекта.
        // Вы можете снять защелку
        latch.await();
    }
}

4. Реализация примера приложения

Ниже приводится последняя часть этой статьи. Я хочу закончить ее относительно полным примером приложения. Этот пример взят из реального сценария приложения. Требуется собрать следующие данные для каждой страницы: Над сгибомпроизводительность,включать:

  • Количество запросов первого экрана
  • Размер выше сгиба
  • Общее количество DOM на первом экране
  • Время завершения загрузки DOM первого экрана
  • Время завершения полной загрузки первого экрана
  • Ненормальный ответ первого экрана
  • Не удалось ответить на первый экран
  • Медленный ответ на первом экране

以及全页面производительность,То есть после открытия страницы вы завершите просмотр всей страницы.,включать:

  • Количество полностраничных запросов
  • полный размер страницы
  • Общее количество DOM на всей странице
  • Время завершения загрузки полной страницы DOM
  • Время завершения полной загрузки страницы
  • Полный ответ на исключение страницы
  • Полный ответ на ошибку страницы
  • Полная страница медленный ответ

Окончательная реализация выглядит следующим образом:

Язык кода:javascript
копировать
package com.suning.webdrivertest.chrome;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.suning.webdrivertest.networkdto.NetworkLoadingFailedDTO;
import com.suning.webdrivertest.networkdto.NetworkLoadingFinishedDTO;
import com.suning.webdrivertest.networkdto.NetworkRequestWillBeSentDTO;
import com.suning.webdrivertest.networkdto.NetworkResponseReceivedDTO;
import com.suning.webdrivertest.performancedto.*;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.logging.Level;

/** * Created by zhuyiquan90 on 2018/1/10. */
public class ChromeTest { 
   

    // Длина очереди блокировки
    private static final int BLOCK_QUEUE_SIZE = 100;
    // Количество потоков драйвера браузера
    private static final int THREAD_SIZE = 1;
    // Fired when page is about to send HTTP request.
    public static final String NETWORK_REQUEST_WILL_BE_SENT = "Network.requestWillBeSent";
    // Fired when HTTP response is available.
    public static final String NETWORK_RESPONSE_RECEIVED = "Network.responseReceived";
    // Fired when HTTP request has finished loading.
    public static final String NETWORK_LOADING_FAILED = "Network.loadingFailed";
    // Fired when HTTP request has failed to load.
    public static final String NETWORK_LOADING_FINISHED = "Network.loadingFinished";
    // DOM Length JS
    public static final String JS_DOM_LENGTH = "return document.getElementsByTagName('*').length";
    // ScrollingTop JS
    public static final String JS_SCROLLINGTOP = "return $(window).scrollTop( {0} * 1000)";
    // Scrolling Y JS
    public static final String JS_SCROLLINGY = "return window.scrollY";
    // Performance Timing JS
    public static final String JS_PERFORMANCE_TIMING = "return performance.timing";

    private static final BlockingQueue<String> reqQuene = new ArrayBlockingQueue<String>(BLOCK_QUEUE_SIZE);

    static class DriverRunnable implements Runnable {
        private WebDriver driver;

        public DriverRunnable() {

            System.setProperty(ChromeDriverService.CHROME_DRIVER_LOG_PROPERTY,
                    System.getProperty("user.dir") + "/target/chromedriver.log");
            System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY,
                    System.getProperty("user.dir") + "/drivers/chromedriver");

            ChromeDriverService chromeDriverService = new ChromeDriverService.Builder()
                    .withVerbose(true)
                    .usingAnyFreePort()
                    .build();

            ChromeOptions options = new ChromeOptions();
            // options.addArguments("--headless");
            options.addArguments("--window-size=1980,1000");
            options.addArguments("--disable-web-security");
            // options.addArguments("--start-fullscreen");
            // options.addArguments("--screenshot");
            // options.addArguments("--golden-screenshots-dir=" + chromedriverPath);


            DesiredCapabilities cap = DesiredCapabilities.chrome();
            LoggingPreferences logPrefs = new LoggingPreferences();
            logPrefs.enable(LogType.PERFORMANCE, Level.ALL);
            cap.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);
            cap.setCapability(ChromeOptions.CAPABILITY, options);

            driver = new ChromeDriver(chromeDriverService, cap);
        }

        public void run() {
            while (true) {
                try {
                    String url = reqQuene.take();
                    TotalPerformanceDTO totalPerformance = new TotalPerformanceDTO();
                    totalPerformance.setFirstScreenPerformance(
                            detectFirstScreenPerformance(url, driver));
                    totalPerformance.setFullPagePerformance(
                            detectFullPagePerformance(url, driver));

                    System.out.println(totalPerformance.toString());

                    // Сдвинуть страницу в самый низ страницы
// long scrollStart = 0, scrollEnd = 1;
// int i = 1;
// while (scrollStart != scrollEnd) { 
   
// scrollStart = (Long) js.executeScript("return window.scrollY");
// String scrollTo = "return $(window).scrollTop(" + i++ + " * 1000)";
// js.executeScript(scrollTo);
// Thread.sleep(200);
// scrollEnd = (Long) js.executeScript("return window.scrollY");
// System.out.println(scrollTo + ":" + scrollEnd);
// }
// System.out.println(Thread.currentThread().getName() + ": " +
// js.executeScript("return document.getElementsByTagName('*').length"));
// for (LogEntry entry : driver.manage().logs().get(LogType.PERFORMANCE)) { 
   
// System.out.println(Thread.currentThread().getName() + entry.getMessage());
// }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /** * Статистика первого экрана * * @param url * @param driver * @return */
    private static FirstScreenPerformanceDTO detectFirstScreenPerformance(String url, WebDriver driver) {
        driver.get(url);
        // объект операции js
        JavascriptExecutor js = (JavascriptExecutor) driver;

        FirstScreenPerformanceDTO firstScreenPerformance = new FirstScreenPerformanceDTO();
        List<NetworkRequestWillBeSentDTO> firstscreenRequestList =
                new ArrayList<NetworkRequestWillBeSentDTO>();
        List<NetworkResponseReceivedDTO> firstscreenResponseList =
                new ArrayList<NetworkResponseReceivedDTO>();
        List<NetworkLoadingFailedDTO> firstscreenFailList =
                new ArrayList<NetworkLoadingFailedDTO>();
        List<NetworkLoadingFinishedDTO> firstscreenFinishedList =
                new ArrayList<NetworkLoadingFinishedDTO>();
        int pageRequestNum = 0;
        double pageSize = 0.0;
        for (LogEntry entry : driver.manage().logs().get(LogType.PERFORMANCE)) {
            JSONObject jsonObj = JSON.parseObject(entry.getMessage()).getJSONObject("message");
            String method = jsonObj.getString("method");
            String params = jsonObj.getString("params");

            if (method.equals(NETWORK_REQUEST_WILL_BE_SENT)) {

                NetworkRequestWillBeSentDTO request = JSON.parseObject(
                        params, NetworkRequestWillBeSentDTO.class);
                pageRequestNum++;
// System.out.println(method + ":" + request.toString());
                firstscreenRequestList.add(request);
            } else if (method.equals(NETWORK_RESPONSE_RECEIVED)) {

                NetworkResponseReceivedDTO response = JSON.parseObject(
                        params, NetworkResponseReceivedDTO.class);
// System.out.println(method + ":" + response.getResponse().getUrl());
                firstscreenResponseList.add(response);
            } else if (method.equals(NETWORK_LOADING_FINISHED)) {

                NetworkLoadingFinishedDTO finished = JSON.parseObject(
                        params, NetworkLoadingFinishedDTO.class);
                pageSize += finished.getEncodedDataLength();
// System.out.println(method + ":" + finished.toString());
                firstscreenFinishedList.add(finished);
            } else if (method.equals(NETWORK_LOADING_FAILED)) {

                NetworkLoadingFailedDTO failed = JSON.parseObject(
                        params, NetworkLoadingFailedDTO.class);
// System.out.println(method + ":" + failed.toString());
                firstscreenFailList.add(failed);
            }
        }
        // Получите номер DOM первого экрана
        firstScreenPerformance.setPageDomNum(executeDomLengthJS(js));
        // получать Время завершения загрузки DOM первого экрана и Время завершения полной загрузки первого экрана
        PerformanceTimingDTO performanceTiming = executePerformanceTimingJS(js);
        firstScreenPerformance.setDomContentLoadedCost(
                performanceTiming.getDomContentLoadedEventEnd() - performanceTiming.getConnectStart());
        firstScreenPerformance.setLoadEventCost(
                performanceTiming.getLoadEventEnd() - performanceTiming.getConnectStart());
        // получать Размер выше сгиба
        firstScreenPerformance.setPageSize(pageSize / (1000 * 1000));
        // получать Количество запросов первого экрана
        firstScreenPerformance.setPageRequestNum(pageRequestNum);
        System.out.println("страница" + url + ":Количество запросов первого экрана:"
                + firstScreenPerformance.getPageRequestNum() + ", Размер выше сгиба:"
                + firstScreenPerformance.getPageSize() + "MB, Общее количество DOM на первом экране:"
                + firstScreenPerformance.getPageDomNum() + ", Время завершения загрузки DOM первого экрана:"
                + firstScreenPerformance.getDomContentLoadedCost() + "ms, Время завершения полной загрузки первого экрана:"
                + firstScreenPerformance.getLoadEventCost() + "ms");
        // Анализируйте ненормальные реакции
        PageErrorsDTO pageErrorsDTO = new PageErrorsDTO();
        pageErrorsDTO.setCodeErrorResponseList(
                analysisCodeErrorResponse(firstscreenResponseList));
        if (!pageErrorsDTO.getCodeErrorResponseList().isEmpty()) {
            System.out.println("Ненормальный ответ первого экрана:");
            for (int i = 0; i < pageErrorsDTO.getCodeErrorResponseList().size(); i++) {
                System.out.println(pageErrorsDTO.
                        getCodeErrorResponseList().get(i).getUrl() + ": " + pageErrorsDTO.
                        getCodeErrorResponseList().get(i).getStatus());
            }
        }
        // Анализ реакции на отказ
        pageErrorsDTO.setFailResponseList(
                analysisFailResponse(firstscreenFailList, firstscreenRequestList));
        if (!pageErrorsDTO.getFailResponseList().isEmpty()) {
            System.out.println("Не удалось ответить на первый экран:");
            for (int i = 0; i < pageErrorsDTO.getFailResponseList().size(); i++) {
                System.out.println(pageErrorsDTO.
                        getFailResponseList().get(i).getUrl() + ": " + pageErrorsDTO.
                        getFailResponseList().get(i).getErrorText() + " " + pageErrorsDTO.
                        getFailResponseList().get(i).getBlockedReason());
            }
        }
        // Анализируйте медленные ответы
        pageErrorsDTO.setSlowReponseList(
                analysisSlowResponse(firstscreenRequestList, firstscreenFinishedList, 3.0));
        if (!pageErrorsDTO.getSlowReponseList().isEmpty()) {
            System.out.println("Медленный ответ на первом экране:");
            for (int i = 0; i < pageErrorsDTO.getSlowReponseList().size(); i++) {
                System.out.println(pageErrorsDTO.
                        getSlowReponseList().get(i).getUrl() + ": " + pageErrorsDTO.
                        getSlowReponseList().get(i).getCost());
            }
        }
        firstScreenPerformance.setPageErrorsDTO(pageErrorsDTO);

        return firstScreenPerformance;
    }


    /** * Полная статистика страницы * * @param url * @param driver * @return */
    private static FullPagePerformanceDTO detectFullPagePerformance(String url, WebDriver driver) {
        driver.get(url);
        // объект операции js
        JavascriptExecutor js = (JavascriptExecutor) driver;
        FullPagePerformanceDTO fullPagePerformance = new FullPagePerformanceDTO();

        // Прокрутите страницу вниз
        scrollToBottom(js);

        List<NetworkRequestWillBeSentDTO> fullPageRequestList =
                new ArrayList<NetworkRequestWillBeSentDTO>();
        List<NetworkResponseReceivedDTO> fullPageResponseList =
                new ArrayList<NetworkResponseReceivedDTO>();
        List<NetworkLoadingFailedDTO> fullPageFailList =
                new ArrayList<NetworkLoadingFailedDTO>();
        List<NetworkLoadingFinishedDTO> fullPageFinishedList =
                new ArrayList<NetworkLoadingFinishedDTO>();
        int pageRequestNum = 0;
        double pageSize = 0.0;
        for (LogEntry entry : driver.manage().logs().get(LogType.PERFORMANCE)) {
            JSONObject jsonObj = JSON.parseObject(entry.getMessage()).getJSONObject("message");
            String method = jsonObj.getString("method");
            String params = jsonObj.getString("params");

            if (method.equals(NETWORK_REQUEST_WILL_BE_SENT)) {

                NetworkRequestWillBeSentDTO request = JSON.parseObject(
                        params, NetworkRequestWillBeSentDTO.class);
                pageRequestNum++;
// System.out.println(method + ":" + request.toString());
                fullPageRequestList.add(request);
            } else if (method.equals(NETWORK_RESPONSE_RECEIVED)) {

                NetworkResponseReceivedDTO response = JSON.parseObject(
                        params, NetworkResponseReceivedDTO.class);
// System.out.println(method + ":" + response.getResponse().getUrl());
                fullPageResponseList.add(response);
            } else if (method.equals(NETWORK_LOADING_FINISHED)) {

                NetworkLoadingFinishedDTO finished = JSON.parseObject(
                        params, NetworkLoadingFinishedDTO.class);
                pageSize += finished.getEncodedDataLength();
// System.out.println(method + ":" + finished.toString());
                fullPageFinishedList.add(finished);
            } else if (method.equals(NETWORK_LOADING_FAILED)) {

                NetworkLoadingFailedDTO failed = JSON.parseObject(
                        params, NetworkLoadingFailedDTO.class);
// System.out.println(method + ":" + failed.toString());
                fullPageFailList.add(failed);
            }
        }
        // Получить номер DOM полной страницы
        fullPagePerformance.setPageDomNum(executeDomLengthJS(js));
        // получать Время завершения загрузки полной страницы DOM и Время завершения полной загрузки первого экрана
        PerformanceTimingDTO performanceTiming = executePerformanceTimingJS(js);
        fullPagePerformance.setDomContentLoadedCost(
                performanceTiming.getDomContentLoadedEventEnd() - performanceTiming.getConnectStart());
        fullPagePerformance.setLoadEventCost(
                performanceTiming.getLoadEventEnd() - performanceTiming.getConnectStart());
        // получатьполный размер страницы
        fullPagePerformance.setPageSize(pageSize / (1000 * 1000));
        // получать Количество полностраничных запросов
        fullPagePerformance.setPageRequestNum(pageRequestNum);
        System.out.println("страница" + url + ":Количество полностраничных запросов:"
                + fullPagePerformance.getPageRequestNum() + ", полный размер страницы:"
                + fullPagePerformance.getPageSize() + "MB, Общее количество DOM на всей странице:"
                + fullPagePerformance.getPageDomNum() + ", Время завершения загрузки полной страницы DOM:"
                + fullPagePerformance.getDomContentLoadedCost() + "ms, Время завершения полной загрузки страницы:"
                + fullPagePerformance.getLoadEventCost() + "ms");
        // Анализируйте ненормальные реакции
        PageErrorsDTO pageErrorsDTO = new PageErrorsDTO();
        pageErrorsDTO.setCodeErrorResponseList(
                analysisCodeErrorResponse(fullPageResponseList));
        if (!pageErrorsDTO.getCodeErrorResponseList().isEmpty()) {
            System.out.println("Полный ответ на исключение страницы:");
            for (int i = 0; i < pageErrorsDTO.getCodeErrorResponseList().size(); i++) {
                System.out.println(pageErrorsDTO.
                        getCodeErrorResponseList().get(i).getUrl() + ": " + pageErrorsDTO.
                        getCodeErrorResponseList().get(i).getStatus());
            }
        }
        // Анализ реакции на отказ
        pageErrorsDTO.setFailResponseList(
                analysisFailResponse(fullPageFailList, fullPageRequestList));
        if (!pageErrorsDTO.getFailResponseList().isEmpty()) {
            System.out.println("Полный ответ на ошибку страницы:");
            for (int i = 0; i < pageErrorsDTO.getFailResponseList().size(); i++) {
                System.out.println(pageErrorsDTO.
                        getFailResponseList().get(i).getUrl() + ": " + pageErrorsDTO.
                        getFailResponseList().get(i).getErrorText() + " " + pageErrorsDTO.
                        getFailResponseList().get(i).getBlockedReason());
            }
        }
        // Анализируйте медленные ответы
        pageErrorsDTO.setSlowReponseList(
                analysisSlowResponse(fullPageRequestList, fullPageFinishedList, 3.0));
        if (!pageErrorsDTO.getSlowReponseList().isEmpty()) {
            System.out.println("Полная страница медленный ответ:");
            for (int i = 0; i < pageErrorsDTO.getSlowReponseList().size(); i++) {
                System.out.println(pageErrorsDTO.
                        getSlowReponseList().get(i).getUrl() + ": " + pageErrorsDTO.
                        getSlowReponseList().get(i).getCost());
            }
        }
        fullPagePerformance.setPageErrorsDTO(pageErrorsDTO);

        return fullPagePerformance;
    }

    /** * Прокрутите страницу вниз * * @param js * @return */
    private static long scrollToBottom(JavascriptExecutor js) {
        long scrollStart = 0, scrollEnd = 1;
        int i = 1;
        while (scrollStart != scrollEnd) {
            scrollStart = (Long) js.executeScript(JS_SCROLLINGY);
            String scrollTo = MessageFormat.format(JS_SCROLLINGTOP, i++);
            System.out.println(scrollTo);
            js.executeScript(scrollTo);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            scrollEnd = (Long) js.executeScript(JS_SCROLLINGY);
            // System.out.println(scrollTo + ":" + scrollEnd);
        }
        return scrollEnd;
    }

    /** * Выполните js, чтобы получить номер DOM страницы. * * @param js * @return */
    private static long executeDomLengthJS(JavascriptExecutor js) {
        return (Long) js.executeScript(JS_DOM_LENGTH);
    }

    /** * Выполните js и получите производительность Timing * * @param js * @return */
    private static PerformanceTimingDTO executePerformanceTimingJS(JavascriptExecutor js) {
        String performance = js.executeScript(JS_PERFORMANCE_TIMING).toString();
        performance = performance.replace("unloadEventEnd=", "\"unloadEventEnd\":")
                .replace("responseEnd=", "\"responseEnd\":")
                .replace("responseStart=", "\"responseStart\":")
                .replace("domInteractive=", "\"domInteractive\":")
                .replace("domainLookupEnd=", "\"domainLookupEnd\":")
                .replace("unloadEventStart=", "\"unloadEventStart\":")
                .replace("domComplete=", "\"domComplete\":")
                .replace("domContentLoadedEventStart=", "\"domContentLoadedEventStart\":")
                .replace("domainLookupStart=", "\"domainLookupStart\":")
                .replace("redirectEnd=", "\"redirectEnd\":")
                .replace("redirectStart=", "\"redirectStart\":")
                .replace("connectEnd=", "\"connectEnd\":")
                .replace("toJSON={},", "")
                .replace("connectStart=", "\"connectStart\":")
                .replace("loadEventStart=", "\"loadEventStart\":")
                .replace("navigationStart=", "\"navigationStart\":")
                .replace("requestStart=", "\"requestStart\":")
                .replace("secureConnectionStart=", "\"secureConnectionStart\":")
                .replace("fetchStart=", "\"fetchStart\":")
                .replace("domContentLoadedEventEnd=", "\"domContentLoadedEventEnd\":")
                .replace("domLoading=", "\"domLoading\":")
                .replace("loadEventEnd=", "\"loadEventEnd\":");
// System.out.println(performance);
        return JSON.parseObject(
                performance, PerformanceTimingDTO.class);
    }

    /** * Анализ ответов на коды состояния исключений * * @param networkResponseReceivedList * @return */
    private static List<CodeErrorResponseDTO> analysisCodeErrorResponse
    (List<NetworkResponseReceivedDTO> networkResponseReceivedList) {

        List<CodeErrorResponseDTO> codeErrorResponseList = new ArrayList<CodeErrorResponseDTO>();
        for (NetworkResponseReceivedDTO r : networkResponseReceivedList) {
            if (r.getResponse().getStatus() >= 400
                    && r.getResponse().getStatus() <= 599) {
                CodeErrorResponseDTO codeErrorResponseDTO = new CodeErrorResponseDTO();
                codeErrorResponseDTO.setUrl(r.getResponse().getUrl());
                codeErrorResponseDTO.setStatus(r.getResponse().getStatus());
                System.out.println(r.toString());

                codeErrorResponseList.add(codeErrorResponseDTO);
            }
        }

        return codeErrorResponseList;
    }

    /** * Анализируйте неудачные ответы * * @param networkLoadingFailedList * @param networkRequestWillBeSentList * @return */
    private static List<FailResponseDTO> analysisFailResponse(
            List<NetworkLoadingFailedDTO> networkLoadingFailedList,
            List<NetworkRequestWillBeSentDTO> networkRequestWillBeSentList) {
        List<FailResponseDTO> failResponseList = new ArrayList<FailResponseDTO>();
        for (NetworkLoadingFailedDTO f : networkLoadingFailedList) {
            for (NetworkRequestWillBeSentDTO r : networkRequestWillBeSentList) {
                if (f.getRequestId().equals(r.getRequestId())) {
                    FailResponseDTO failResponseDTO = new FailResponseDTO();
                    failResponseDTO.setUrl(r.getRequest().getUrl());
                    failResponseDTO.setErrorText(f.getErrorText());
                    failResponseDTO.setBlockedReason(f.getBlockedReason());

                    failResponseList.add(failResponseDTO);
                }
            }
        }

        return failResponseList;
    }

    /** * Анализируйте медленные ответы,единицаs * * @param networkRequestWillBeSentList * @param networkLoadingFinishedList * @param slowThreshold * @return */
    private static List<SlowReponseDTO> analysisSlowResponse(
            List<NetworkRequestWillBeSentDTO> networkRequestWillBeSentList,
            List<NetworkLoadingFinishedDTO> networkLoadingFinishedList,
            double slowThreshold) {
        List<SlowReponseDTO> slowReponseList = new ArrayList<SlowReponseDTO>();
        for (NetworkRequestWillBeSentDTO r : networkRequestWillBeSentList) {
            for (NetworkLoadingFinishedDTO f : networkLoadingFinishedList) {
                if (r.getRequestId().equals(f.getRequestId())) {
                    double cost = f.getTimestamp() - r.getTimestamp();
                    if (cost >= slowThreshold) {
                        SlowReponseDTO slowReponseDTO = new SlowReponseDTO();
                        slowReponseDTO.setUrl(r.getRequest().getUrl());
                        slowReponseDTO.setCost(cost);

                        slowReponseList.add(slowReponseDTO);
                    }
                }
            }
        }

        return slowReponseList;
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < THREAD_SIZE; i++) {
            Thread driverThread = new Thread(new DriverRunnable(), "driverThread" + i);
            driverThread.start();
        }
        for (int i = 0; i < 1; i++) {
            reqQuene.put("https://www.suning.com");
        }
    }
}

Издатель: Лидер стека программистов полного стека, укажите источник для перепечатки: https://javaforall.cn/158899.html Исходная ссылка: https://javaforall.cn

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose