使用 k6 下载整个网站

Posted

技术标签:

【中文标题】使用 k6 下载整个网站【英文标题】:Downloading whole websites with k6 【发布时间】:2020-03-30 09:33:16 【问题描述】:

我目前正在评估 k6 是否适合我们的负载测试需求。我们有一个相当传统的网站架构,它使用带有 phpmysql 数据库的 Apache 网络服务器。使用 k6 发送简单的 HTTP 请求看起来很简单,我认为我们将能够使用它测试所有主要功能,因为我们不那么依赖 javascript,而且大多数页面都是静态的。

但是,我不确定如何处理请求中返回的 html 中引用的资源(样式表、图像等)。我们也需要加载它们,因为这有时会导致数据库请求,这必须是负载测试的一部分。

k6 中是否有一些开箱即用的功能,可以让您像浏览器一样加载所有资源?我知道 k6 确实 NOT 呈现页面,我不需要它。我只需要请求 HTML 中的所有资源。

【问题讨论】:

【参考方案1】:

您基本上有两个选择,都有各自的注意事项:

    Record your session - 您可以直接从浏览器中导出 har,如图所示,或者在您的浏览器中使用 extension made,这里是 firefox 和 chromes。两者都应该可以在没有 k6 云帐户的情况下使用,您只需将它们设置为下载 har,当您点击停止时它会自动(并且有点静默)下载它们。然后使用 in k6 har 转换器(已弃用,但仍然有效)或新的 har-to-k6 一个。

    如果你有很多页面和/或资源,这个方法特别好,如果你有一个单一页面样式的应用程序,它甚至可以工作,因为它只是获取浏览器请求的HAR,然后将其转换为脚本。如果没有需要输入的动态内容(用户名/密码),则大多数情况下都可以使用最终脚本。

    这种方法最大的问题是,如果你添加了一个 css 文件,你需要重做整个练习。如果您在每次更改时更改 css/js 文件名或类似的东西,这将更加成问题。下一个方法有什么好处:

    使用parseHTML,然后找到您关心的元素并提出请求。
import http from "k6/http";
import parseHTML from "k6/html";

export default function() 
    const res = http.get("https://***.com");
    const doc = parseHTML(res.body);
    doc.find("link").toArray().forEach(function (item) 
        console.log(item.attr("href"));
        // make http gets for it
        // or added them to an array and make one batch request
     );

会产生

NFO[0001] https://cdn.sstatic.net/Sites/***/img/favicon.ico?v=4f32ecc8f43d
INFO[0001] https://cdn.sstatic.net/Sites/***/img/apple-touch-icon.png?v=c78bd457575a
INFO[0001] https://cdn.sstatic.net/Sites/***/img/apple-touch-icon.png?v=c78bd457575a
INFO[0001] /opensearch.xml
INFO[0001] https://cdn.sstatic.net/Shared/stacks.css?v=53507c7c6e93
INFO[0001] https://cdn.sstatic.net/Sites/***/primary.css?v=d3fa9a72fd53
INFO[0001] https://cdn.sstatic.net/Shared/Product/product.css?v=c9b2e1772562
INFO[0001] /feeds
INFO[0001] https://cdn.sstatic.net/Shared/Channels/channels.css?v=f9809e9ffa90

如您所见,有些网址是相对的而非绝对的,因此您需要处理此问题。在这个例子中只有一些是 css,所以可能需要更多的过滤。 这里的问题是您需要编写代码,并且如果您添加相对链接或其他内容,您需要处理它。幸运的是,k6 是可编写脚本的,因此您可以重用代码:D。

【讨论】:

【参考方案2】:

我遵循了 Михаил Стойков 的建议并编写了自己的函数来加载资源。也许它可以帮助一些未来的读者。您可以设置资源的加载方式(使用options.concurrentResourceLoading 批量或顺序获取)。

/**
* @param http.RefinedResponse<http.ResponseType> response
*/
export function getResources(response) 
const resources = [];
response
    .html()
    .find('*[href]:not(a)')
    .each((index, element) => 
    resources.push(element.attributes().href.value);
    );
response
    .html()
    .find('*[src]:not(a)')
    .each((index, element) => 
    resources.push(element.attributes().src.value);
    );

if (options.concurrentResourceLoading) 
    const responses = http.batch(
    resources.map((r) => 
        return ['GET', resolveUrl(r, response.url), null,  headers: createHeader() ];
    )
    );
    responses.forEach(() => 
    check(response, 
        'resource returns status 200': (r) => r.status === 200,
    );
    );
 else 
    resources.forEach((r) => 
    const res = http.get(resolveUrl(r, response.url), 
        headers: createHeader(),
    );
    !check(res, 
        'resource returns status 200': (r) => r.status === 200,
    );
    );


【讨论】:

这缺少很多定义,例如 resolveUrlcreateHeader

以上是关于使用 k6 下载整个网站的主要内容,如果未能解决你的问题,请参考以下文章

markdown 使用wget下载整个网站以供离线使用。

如何使用 k6/loadimpact 解析 img 标签?

wget 递归下载整个网站(网站扒皮必备)

wget 递归下载整个网站(网站扒皮必备)

如何下载整个网站的图片(只能通过网址访问,无超链接)

wget下载网站整个目录