Привет! Для реализации моей задачи необходимо разбирать данные входящего трафика, а точнее XHR данные, которые можно увидеть в браузере Chrome → Открыть DevTools (F12) → Вкладка Network → Фильтр Fetch/XHR. Я видел примеры, где для перехвата трафика используют BrowserMob Proxy, но также увидел, что Selenium 4 может напрямую работать с CDP (Chrome DevTools Protocol), которому отдал предпочтение.
У меня возникла проблема – не у всех успешно полученных XHR пакетов (статус 200) выходит успешно извлечь тело getResponseBody. Возможно, я делаю что-то не так.
Ниже я выложил рабочий пример, который заходит в Instagram и записывает XHR пакеты. По окончанию всех действий, смотрим количество неудачно извлеченных тел XHR пакетов (обычно от 1 до 3). Подчеркну, что всех XHR пакеты имеют статус 200, поэтому не понимаю в чем проблема получения данных из них.
namespace SeleniumCDP
{
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.DevTools;
using DevToolsVer = OpenQA.Selenium.DevTools.V93;
class Program
{
private static IWebDriver Driver = null;
private static IDevTools Tools = null;
private static IDevToolsSession Session = null;
private static DevToolsVer.DevToolsSessionDomains Domains = null;
private static ConcurrentBag<Task<Response>> CollectionXHR = null;
public struct Response
{
public string RequestId { get; set; }
public string ResponseUrl { get; set; }
public long ResponseStatus { get; set; }
public bool ResponseBodySuccess { get; set; }
public string ResponseBody { get; set; }
}
private static async Task Main()
{
// Инициализация
Driver = new ChromeDriver();
Driver.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, 10);
Driver.Manage().Timeouts().AsynchronousJavaScript = new TimeSpan(0, 0, 30);
Driver.Manage().Timeouts().PageLoad = new TimeSpan(0, 0, 30);
Driver.Manage().Window.Maximize();
Tools = Driver as IDevTools;
Session = Tools.GetDevToolsSession();
Domains = Session.GetVersionSpecificDomains<DevToolsVer.DevToolsSessionDomains>();
await Domains.Network.Enable(new DevToolsVer.Network.EnableCommandSettings());
// Подготавливаем хранилище данных
CollectionXHR = new ConcurrentBag<Task<Response>>();
// Включаем запись получаемых данных
Domains.Network.ResponseReceived += ResponseReceived;
// Какие-то действия на сайте
Instagram("username", "password"); // ! ввести логин и пароль
// Отключаем запись получаемых данных
Domains.Network.ResponseReceived -= ResponseReceived;
// Ожидаем завершение извлечения полученных данных
Task.WaitAll(CollectionXHR.ToArray());
// Количество неудачных извлечений полученных данных
var failResponseBody = CollectionXHR.Where(w => w.Result.ResponseBodySuccess == false).Count();
// Выводим данные неудачных извлечений полученных данных
string failDescr = string.Empty;
foreach (var i in CollectionXHR.Where(w => w.Result.ResponseBodySuccess == false).ToList())
{
failDescr += $"RequestId = {i.Result.RequestId} | ResponseStatus = {i.Result.ResponseStatus} | ResponseBodySuccess = {i.Result.ResponseBodySuccess} \n";
}
}
private static void ResponseReceived(object sender, DevToolsVer.Network.ResponseReceivedEventArgs e)
{
if (e.Type == DevToolsVer.Network.ResourceType.XHR)
{
CollectionXHR.Add(GetResponseBodyAsync(e));
}
}
private static async Task<Response> GetResponseBodyAsync(DevToolsVer.Network.ResponseReceivedEventArgs e)
{
try
{
var cmd = new DevToolsVer.Network.GetResponseBodyCommandSettings();
cmd.RequestId = e.RequestId;
var data = await Domains.Network.GetResponseBody(cmd);
return new Response()
{
RequestId = e.RequestId,
ResponseUrl = e.Response.Url,
ResponseStatus = e.Response.Status,
ResponseBodySuccess = true,
ResponseBody = data.Body
};
}
catch
{
return new Response()
{
RequestId = e.RequestId,
ResponseUrl = e.Response.Url,
ResponseStatus = e.Response.Status,
ResponseBodySuccess = false,
ResponseBody = null
};
}
}
private static void Instagram(string username, string password)
{
// Переходим на instagram.com
Driver.Navigate().GoToUrl("https://www.instagram.com/");
// Вводим логин и пароль
{
var byUsernameInput = By.XPath("//form[@id='loginForm']//input[@name='username']");
var byPasswordInput = By.XPath("//form[@id='loginForm']//input[@name='password']");
var byLoginButton = By.XPath("//form[@id='loginForm']//button[@type='submit']");
if (Driver.FindElements(byLoginButton).Count > 0)
{
Driver.FindElement(byUsernameInput).SendKeys(username);
Driver.FindElement(byPasswordInput).SendKeys(password);
Driver.FindElement(byLoginButton).Click();
}
}
// Отказываемся от сохранения данных для входа
{
var byNotAutoLoginButton = By.XPath("//button[contains(text(),'Не сейчас')]");
if (Driver.FindElements(byNotAutoLoginButton).Count > 0)
{
Driver.FindElement(byNotAutoLoginButton).Click();
}
}
// Отказываемся от включения уведомлений
{
var byNotNotifyButton = By.XPath("//button[contains(text(),'Не сейчас')]");
if (Driver.FindElements(byNotNotifyButton).Count > 0)
{
Driver.FindElement(byNotNotifyButton).Click();
}
}
// Переходим в директ
{
var byMessengerLink = By.XPath("//a[@href='/direct/inbox/']");
if (Driver.FindElements(byMessengerLink).Count > 0)
{
Driver.FindElement(byMessengerLink).Click();
}
}
}
}
}