如何基准测试网络解锁器:可重复的测试设计
Senior Cybersecurity Analyst
TL;DR:
- 网络解锁基准测试必须测量可用内容,而不仅仅是HTTP状态。 一个响应可以在技术上成功,同时包含挑战页面、空壳、错误区域或不完整渲染。
- 在测试之前应对URL样本进行分层。 将静态页面、服务渲染页面、JavaScript应用、重定向和流量验证挑战分开,以确保一个简单类别不能隐藏另一个。
- 延迟需要分布。 报告中位数和高百分位数,同时报告响应和内容成功率。
- 有效成本取决于可用交付。 将观察到的支出除以通过内容检查的响应,不是发送的尝试。
- 可重复性来自于清单。 记录每个测试单元的URL类别、预期标记、渲染要求、区域、请求设置和测量代码。
介绍:基准测试是合同
当“成功”仅意味着一个端点返回了响应时,网络解锁基准测试就失败了。
有用的问题是该服务是否以下游解析器可以使用的形式提供了预期的公共内容。这需要一个测试合同:已知URL、类别标签、预期内容标记、一致的请求设置、限制的样本数量和在结果可见之前决定的评分规则。
本指南为Scrapeless Web Unlocker构建了该合同。它使用当前的unlocker.webunlocker演员和POST /api/v2/unlocker/request表面,但设计可以移植到任何管理的解锁服务。
网络解锁器的功能
网络解锁器接受目标URL,并在处理该请求所需的网络和浏览器工作后返回公共页面内容。
这与提供代理地址不同。代理改变了网络路径;调用的应用程序仍然拥有头信息、浏览器执行、Cookie、页面完整性检查和响应解析。管理的网络解锁器接受更高层次的请求,并通过API返回内容。
Scrapeless Web Unlocker接受actor、input和proxy对象。当前端点支持unlocker.webunlocker演员、目标URL、HTTP方法、重定向控制、可选请求头和代理国家。该产品可以返回HTML、JSON、Markdown或截图,只有成功的请求会计费。
基准测试应评估交付的文档,而不是从用于获取它的基础设施推测质量。
在发送请求之前定义成功
基准测试结果应通过四个独立检查。
- 传输成功。 Scrapeless API请求在HTTP语义标准下以成功的HTTP状态完成。
- 目标身份。 响应对应于预期的URL或允许的最终URL。
- 内容成功。 出现特定于目标的标记,而已知的块页面标记不出现。
- 完整性。 交付的主体包含所需部分、记录计数下限或该测试案例的渲染元素。
在原始结果中保持这些检查分开。缺少内容标记的传输成功不是可用交付。具有错误区域的有效标记也是失败,当地理部分是要求时。
构建分层URL样本
一个可重复的网络解锁基准测试从代表生产工作负载的类别开始。
| 类别 | 测试内容 | 清单字段 |
|---|---|---|
| 静态控制 | 基本路由和响应完整性 | URL,预期标题标记 |
| 服务渲染页面 | 来自正常应用的HTML交付 | URL,稳定标题标记 |
| JavaScript渲染页面 | 浏览器执行和水合内容 | URL,渲染标记,渲染要求 |
| 重定向路径 | 最终URL处理 | 起始URL,允许的最终URL |
| 流量验证页面 | 管理访问处理 | URL,预期内容标记,已知挑战标记 |
| 区域页面 | 地理特定交付 | URL,代理国家,区域标记 |
不要从一个域或一个难度类别中提取所有URL。如果生产工作负载是电子商务、新闻、搜索和文档,则应在结果中保持这些组的可见性。每个组应贡献相同数量的请求或接受明确的生产权重。
基准测试清单应属于版本控制。一行应包括case_id、category、url、expected_marker、blocked_markers、proxy_country、redirect和render_required。这使得后续比较能够使用相同的目标和评分逻辑。
尊重每个目标的条款和访问政策。机器人排除协议定义了网站所有者与爬虫偏好的标准沟通方式,但这并不替代法律审查或特定于网站的授权。
发送受控的 Web 解锁请求
当前的 Web 解锁请求使用一个端点和 x-api-token 头中的 API 密钥。
注意:基准块需要 Scrapeless API 密钥和 Python
requests包。请在将分析使用和计费导出到其他账户之前运行该请求。
python
import csv
import os
import statistics
import time
from pathlib import Path
import requests
ENDPOINT = "https://api.scrapeless.com/api/v2/unlocker/request"
API_KEY = os.environ["SCRAPELESS_API_KEY"]
SAMPLES_PER_CASE = 3
CASES = [
{
"case_id": "static-control",
"category": "static",
"url": "https://example.com",
"expected_marker": "Example Domain",
"proxy_country": "ANY",
"redirect": False,
},
{
"case_id": "html-control",
"category": "server-rendered",
"url": "https://httpbin.io/html",
"expected_marker": "Herman Melville",
"proxy_country": "ANY",
"redirect": False,
},
{
"case_id": "js-page",
"category": "javascript",
"url": "https://quotes.toscrape.com/js/",
"expected_marker": "Quotes to Scrape",
"proxy_country": "ANY",
"redirect": False,
},
{
"case_id": "redirect-control",
"category": "redirect",
"url": "https://httpbin.io/redirect/1",
"expected_marker": "url",
"proxy_country": "ANY",
"redirect": True,
},
]
def run_case(case):
payload = {
"actor": "unlocker.webunlocker",
"input": {
"url": case["url"],
"method": "GET",
"redirect": case["redirect"],
},
"proxy": {"country": case["proxy_country"]},
}
started = time.perf_counter()
response = requests.post(
ENDPOINT,
headers={
"Content-Type": "application/json",
"x-api-token": API_KEY,
},
json=payload,
timeout=120,
)
elapsed_ms = round((time.perf_counter() - started) * 1000, 1)
response.raise_for_status()
body = response.text
return {
"case_id": case["case_id"],
"category": case["category"],
"elapsed_ms": elapsed_ms,
"api_status": response.status_code,
"body_bytes": len(response.content),
"marker_found": case["expected_marker"] in body,
}
rows = []
for case in CASES:
for sample in range(1, SAMPLES_PER_CASE + 1):
row = run_case(case)
row["sample"] = sample
rows.append(row)
Path("benchmark-results.csv").write_text("", encoding="utf-8")
with open("benchmark-results.csv", "w", newline="", encoding="utf-8") as handle:
writer = csv.DictWriter(handle, fieldnames=rows[0].keys())
writer.writeheader()
writer.writerows(rows)
latencies = [row["elapsed_ms"] for row in rows]
usable = [row for row in rows if row["marker_found"]]
print({
"requests": len(rows),
"usable_deliveries": len(usable),
"response_rate": len(rows) / len(rows),
"content_success_rate": len(usable) / len(rows),
"latency_p50_ms": statistics.median(latencies),
"result_file": "benchmark-results.csv",
})
该示例故意较小且公开。仅在保护套和评分规则稳定后,才可将其扩展为授权的生产目标。
使用 Scrapeless 开始抓取
使用 Scrapeless 提升您的网络抓取和自动化工作流!
今天注册并获得 $5 的免费积分 — 无需信用卡。立即在 Scrapeless 仪表板 领取您的免费积分。
单独测量响应率和内容成功率
响应率衡量 API 是否成功完成。内容成功率衡量返回的文档是否通过目标特定的检查。
使用以下公式:
- 响应率 = 成功的 API 响应 / 总请求。
- 内容成功率 = 通过身份、标记、阻止页和完整性检查的响应 / 总请求。
- 有条件内容质量 = 可用的交付 / 成功的 API 响应。
第三个比例解释了服务是否返回了技术上成功但不可用的内容。保留每个失败内容检查的原始原因,例如 missing_marker、known_challenge_marker、wrong_final_url 或 below_record_floor。
固定的文本标记仅是起点。对于产品网格,至少需要一个稳定的产品容器和下游架构所需的字段。对于 JavaScript 页面,需要断言一个水合元素,而不是在渲染之前存在的外壳标题。
将延迟报告为 p50 和 p95
延迟应作为分布报告,因为单一的平均值隐藏了工作负载的慢边缘。
记录从 API 请求前立即开始到完整响应体可用的经过时间。对于典型请求报告 p50,对于较慢的边缘报告 p95。W3C 导航时间模型解释了为什么导航包含不同的时间阶段,但是外部 API 基准应使用一个一致的端到端时钟,除非提供者提供了可比较的阶段数据。
计算全样本和每个类别的百分位数。强静态结果不应掩盖弱 JavaScript 或地区分布。在每个百分位数旁边发布样本大小,并避免比较不同计算方法产生的百分位数。
在结果旁边记录分位数方法,以便其他操作员可以重复相同的 p50 和 p95 计算。Python 统计文档使方法选择明确,是文档记录该计算时的有用中立参考。
计算可用交付的有效成本
有效成本将账单转换为工作负载结果。
使用发票或使用导出作为测量窗口,而不是将请求数乘以从营销页面复制的价格。然后计算:
effective cost per usable delivery = observed spend / usable deliveries
如果生产管道提取记录,请添加第二个度量:
effective cost per accepted record = observed spend / records passing schema checks
这使基准与业务任务保持一致。请求价格降低时,如果响应缺少管道所需的字段,则没有帮助。Scrapeless 仅对成功的 Web 解锁请求计费,但基准仍应在调用交付可用之前应用自己的内容质量定义。
检查 JavaScript 完整性
JavaScript 完整性衡量返回的内容是否包括客户端执行后产生的状态。
选择一个仅在应用程序渲染后出现的稳定元素。在清单中记录其选择器或文本标记。更严格的测试还检查最小记录计数和一个从渲染数据填充的字段,而不是初始 HTML 外壳。
不要单独使用主体大小。同意文本、导航界面或挑战文档可能较大,而不包含目标数据。将大小与结构性断言配对。
对于截图输出,在运行之前定义一个视觉区域和一个期望的元素。截图是有用的证据,但它们需要人工或视觉断言才能成为评分结果。
保持实验可重现
可重复的实验记录足够的细节,以便另一个操作员重新运行相同的矩阵。
存储:
- 清单及其版本;
- 基准脚本和依赖锁定文件;
- 请求设置、代理国家和重定向策略;
- 原始数据中的开始和结束时间戳;
- 响应状态、可用时最终 URL、耗时和主体大小;
- 每个内容断言和失败原因;
- 百分位方法和聚合代码;
- 用于有效成本计算的使用或账单导出。
在比较超过一个服务时按平衡顺序运行提供者。域的条件随时间变化,因此在开始另一个服务之前完成一个服务的所有请求可能会引入时间偏差。保持并发性固定且足够小,以便基准测量服务而不是客户端瓶颈。
无夸大地读取结果
网络解锁基准描述所选 URL、设置、位置和测量窗口。
在总体得分之前报告类别级结果。当样本量较小时包括置信区间或原始计数。将不支持的案例与失败案例分开。注意运行后移除的任何目标并保留原因,因为私下更改 URL 集会破坏可比性。
避免普遍性声明,例如“在每个网站上都能工作”。可辩护的结论更狭窄:哪个服务在这些设置下为此清单生成了可用内容。
结论:以可用内容作为成功的单位
可重复的网络解锁基准始于清单,终于可用交付。对 URL 集进行分层,定义内容断言,分别测量响应和内容成功,报告 p50 和 p95 延迟,并根据观察到的每个接受输出的支出计算成本。
查看 Scrapeless 定价,关注当前 Web Unlocker 文档,并使用 Scraper API 指南 将实验放在更广泛的数据管道中。
准备好在您的工作负载上测量 Web Unlocker 吗?
加入 Scrapeless 社区以比较可重复的数据收集实验: Discord · Telegram。
在 app.scrapeless.com 创建一个免费帐户,并在一小组授权公共页面上运行该清单。
常见问题解答
问:网络解锁基准应该测量什么?
网络解锁基准应该测量 API 响应率、内容成功率、延迟分布、JavaScript 完整性以及每个可用交付的有效成本。
问:为什么 HTTP 200 不够算作成功?
HTTP 200 仅描述响应状态。主体仍可能包含错误页面、流量验证文档、空应用程序外壳或不完整目标数据。
问:基准应该包含多少个 URL?
基准应该包含足够的 URL 来代表每个生产类别并报告不确定性,但没有普遍的最低要求。首先从一个小的平衡清单开始,验证工具,然后扩大授权样本。
问:如何计算 p95 延迟?
使用一个记录的分位数方法在明确定义的样本上计算 p95,并在结果旁边发布请求计数。对每个比较的服务和类别使用相同的方法。
问:对公共网站进行基准测试合法吗?
合法性取决于管辖权、目的、目标条款和数据类型。使用授权的公共目标,尽量减少负载,尊重网站政策,并为预期的生产使用寻求法律建议。
问:Web Unlocker 和代理是一样的吗?
不一样。代理改变网络路线,而 Web Unlocker 接受更高级的请求并在 API 后面管理页面访问和内容交付工作流。
在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。



