selenium C#等待后台请求(不是由c#代码发起)
selenium C# wait for background requests(not initiated by c# code)
我正在使用 selenium chrome 驱动程序结合 cefsharp,我正在处理的页面会在每次单击元素时发送某种 ping 请求(fetch/xhr)问题是这些请求不是由 selenium chrome 驱动程序发起,所以我无法跟踪它们并等待完成。 selenium 或 js 有什么方法可以跟踪这些请求吗?
使用 Selenium 4,您实际上可以 intercept requests
调用 Enable
开始请求跟踪
调用WaitForRequestResponse
等待具体请求
如果您可以使用相同的请求,您可以使用 Clear
清除已经捕获的请求
public class WebDriverNetworkController
{
private const string RequestWillBeSent = "requestWillBeSent";
private const string ResponseReceived = "responseReceived";
private readonly IDriverProvider _driverProvider;
private readonly ILogger _log;
private readonly ConcurrentDictionary<DevToolsSession, List<HttpRequestModel>> _sentRequests = new();
public WebDriverNetworkController(IDriverProvider driverProvider, ILogger log)
{
_driverProvider = driverProvider;
_log = log;
}
private void HandleDevToolsEvent(object sender, DevToolsEventReceivedEventArgs e)
{
var session = sender as DevToolsSession;
switch (e.EventName)
{
case RequestWillBeSent:
{
OnRequestWillBeSent(session, e.EventData);
break;
}
case ResponseReceived:
{
OnResponseReceived(session, e.EventData);
break;
}
}
}
public void Enable()
{
_log.Information("Enabling network tracing");
var session = GetDevToolsSession();
session.DevToolsEventReceived += HandleDevToolsEvent;
var enableTask = session.Domains.Network.EnableNetwork();
enableTask.Wait();
}
public void Disable()
{
_log.Information("Disabling network tracing");
var session = GetDevToolsSession();
session.DevToolsEventReceived -= HandleDevToolsEvent;
var disableTask = session.Domains.Network.DisableNetwork();
disableTask.Wait();
}
public void Clear()
{
_log.Information("Clearing captured network tracing requests");
var sentRequests = GetRequests();
sentRequests.Clear();
}
public HttpRequestModel[] GetAllRequests() => GetRequests().ToArray();
public HttpRequestModel WaitForRequestResponse(HttpMethod method, string uri)
{
_log.Debug($"Waiting for {method.Method} request to {uri}");
var session = GetDevToolsSession();
HttpRequestModel request = null;
var waiter = new ConditionWaiter
{
Message = $"{method.Method} request to {uri}"
};
waiter.Until(() =>
{
request = GetLastSentRequest(method, uri, session);
return request?.Response != null;
});
return request;
}
private HttpRequestModel GetLastSentRequest(HttpMethod method, string uri, DevToolsSession session) =>
GetRequests(session).LastOrDefault(request => request.Method == method && request.Uri.EndsWith(uri));
private DevToolsSession GetDevToolsSession()
{
var driver = _driverProvider.GetDriver();
if (driver is IDevTools devTools)
{
return devTools.GetDevToolsSession();
}
throw new WebDriverException($"Could not cast {driver.GetType().Name} to {nameof(IDevTools)}");
}
private List<HttpRequestModel> GetRequests(DevToolsSession session = null) =>
_sentRequests.GetOrAdd(session ?? GetDevToolsSession(), _ => new());
private void OnRequestWillBeSent(DevToolsSession session, JToken eventData)
{
var requestModel = new HttpRequestModel
{
Id = eventData.SelectToken("requestId", true)!.Value<string>(),
Method = new(eventData.SelectToken("request.method", true)!.Value<string>()!),
Uri = eventData.SelectToken("request.url", true)!.Value<string>(),
Body = eventData.SelectToken("request")!.Value<string>("postData")
};
var sentRequests = _sentRequests.GetOrAdd(session, _ => new());
sentRequests.Add(requestModel);
}
private void OnResponseReceived(DevToolsSession session, JToken eventData)
{
var requestId = eventData.SelectToken("requestId", true)!.Value<string>();
var responseModel = new HttpResponseModel
{
Uri = eventData.SelectToken("response.url", true)!.Value<string>(),
StatusCode = (HttpStatusCode)eventData.SelectToken("response.status", true)!.Value<long>()
};
var sentRequests = _sentRequests[session];
var request = sentRequests.Last(request => request.Id == requestId);
request.Response = responseModel;
}
}
上面的代码不能立即使用,但应该可以让您大致了解该方法。
我正在使用 selenium chrome 驱动程序结合 cefsharp,我正在处理的页面会在每次单击元素时发送某种 ping 请求(fetch/xhr)问题是这些请求不是由 selenium chrome 驱动程序发起,所以我无法跟踪它们并等待完成。 selenium 或 js 有什么方法可以跟踪这些请求吗?
使用 Selenium 4,您实际上可以 intercept requests
调用 Enable
开始请求跟踪
调用WaitForRequestResponse
等待具体请求
如果您可以使用相同的请求,您可以使用 Clear
public class WebDriverNetworkController
{
private const string RequestWillBeSent = "requestWillBeSent";
private const string ResponseReceived = "responseReceived";
private readonly IDriverProvider _driverProvider;
private readonly ILogger _log;
private readonly ConcurrentDictionary<DevToolsSession, List<HttpRequestModel>> _sentRequests = new();
public WebDriverNetworkController(IDriverProvider driverProvider, ILogger log)
{
_driverProvider = driverProvider;
_log = log;
}
private void HandleDevToolsEvent(object sender, DevToolsEventReceivedEventArgs e)
{
var session = sender as DevToolsSession;
switch (e.EventName)
{
case RequestWillBeSent:
{
OnRequestWillBeSent(session, e.EventData);
break;
}
case ResponseReceived:
{
OnResponseReceived(session, e.EventData);
break;
}
}
}
public void Enable()
{
_log.Information("Enabling network tracing");
var session = GetDevToolsSession();
session.DevToolsEventReceived += HandleDevToolsEvent;
var enableTask = session.Domains.Network.EnableNetwork();
enableTask.Wait();
}
public void Disable()
{
_log.Information("Disabling network tracing");
var session = GetDevToolsSession();
session.DevToolsEventReceived -= HandleDevToolsEvent;
var disableTask = session.Domains.Network.DisableNetwork();
disableTask.Wait();
}
public void Clear()
{
_log.Information("Clearing captured network tracing requests");
var sentRequests = GetRequests();
sentRequests.Clear();
}
public HttpRequestModel[] GetAllRequests() => GetRequests().ToArray();
public HttpRequestModel WaitForRequestResponse(HttpMethod method, string uri)
{
_log.Debug($"Waiting for {method.Method} request to {uri}");
var session = GetDevToolsSession();
HttpRequestModel request = null;
var waiter = new ConditionWaiter
{
Message = $"{method.Method} request to {uri}"
};
waiter.Until(() =>
{
request = GetLastSentRequest(method, uri, session);
return request?.Response != null;
});
return request;
}
private HttpRequestModel GetLastSentRequest(HttpMethod method, string uri, DevToolsSession session) =>
GetRequests(session).LastOrDefault(request => request.Method == method && request.Uri.EndsWith(uri));
private DevToolsSession GetDevToolsSession()
{
var driver = _driverProvider.GetDriver();
if (driver is IDevTools devTools)
{
return devTools.GetDevToolsSession();
}
throw new WebDriverException($"Could not cast {driver.GetType().Name} to {nameof(IDevTools)}");
}
private List<HttpRequestModel> GetRequests(DevToolsSession session = null) =>
_sentRequests.GetOrAdd(session ?? GetDevToolsSession(), _ => new());
private void OnRequestWillBeSent(DevToolsSession session, JToken eventData)
{
var requestModel = new HttpRequestModel
{
Id = eventData.SelectToken("requestId", true)!.Value<string>(),
Method = new(eventData.SelectToken("request.method", true)!.Value<string>()!),
Uri = eventData.SelectToken("request.url", true)!.Value<string>(),
Body = eventData.SelectToken("request")!.Value<string>("postData")
};
var sentRequests = _sentRequests.GetOrAdd(session, _ => new());
sentRequests.Add(requestModel);
}
private void OnResponseReceived(DevToolsSession session, JToken eventData)
{
var requestId = eventData.SelectToken("requestId", true)!.Value<string>();
var responseModel = new HttpResponseModel
{
Uri = eventData.SelectToken("response.url", true)!.Value<string>(),
StatusCode = (HttpStatusCode)eventData.SelectToken("response.status", true)!.Value<long>()
};
var sentRequests = _sentRequests[session];
var request = sentRequests.Last(request => request.Id == requestId);
request.Response = responseModel;
}
}
上面的代码不能立即使用,但应该可以让您大致了解该方法。