Авторизация из приложения C# на портале BlaBlaCar.ru

от автора

Зачем ?

Из кода Вашего приложения Вы можете авторизоваться на любом web-портале. Это может быть нужно когда Вы хотите получить доступ к ресурсам Вашего аккаунта.

Что можно получить на данном портале ?

Вы можете получить список Ваших поездок, а можете проверить какие поездки запланированы на всем портале от пункта «A» в пункт «B» на конкретную дату. Вы можете больше.

Что понадобится ?

  • Локальный прокси-сервер, рекомендую Fiddler — просто и удобно

  • Visual Studio

Соберем данные

Работа web-клиента и web-сервера происходит по протоколу HTTP. Клиент отправляет HTTP запросы в виде заголовков, сервер отправляет ответ в виде заголовков. Это значит что для нашей задачи нужно отправить на сервер несколько запросов чтобы авторизоваться и получить необходимые данные. Чтобы узнать список запросов мы воспользуемся программой Fiddler. После запуска Fiddler откроем любой браузер, перейдем на портал blablacar.ru, авторизуемся и получим список необходимых HTTP-запросов (лишние запросы удалены).

Перейдем к коду. Авторизация.

Для выполнения HTTP-запросов используется класс HttpWebRequest. Воспользуемся несложными обертками для этого класса: классы GetRequest и PostRequest.

GetRequest
    public class GetRequest     {         private HttpWebRequest _request;         public void Run(ref CookieContainer cookies)         {             _request = (HttpWebRequest)WebRequest.Create(Address);              _request.Headers.Add("DNT", "1");             _request.Method = "Get";             _request.Accept = Accept;             _request.Host = Host;              if (TurnOffProxy) _request.Proxy = null;             else _request.Proxy = Proxy;              if (UseUnsafeHeaderParsing)             {                 var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);                 var settings = (SettingsSection)config.GetSection("system.net/settings");                 settings.HttpWebRequest.UseUnsafeHeaderParsing = true;                 config.Save(ConfigurationSaveMode.Modified);                 ConfigurationManager.RefreshSection("system.net/settings");             }              _request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;              if (!ContentType.IsEmpty()) _request.ContentType = ContentType;              if (TimeOut > 0)             {                 _request.Timeout = TimeOut;                 _request.ReadWriteTimeout = TimeOut;             }             else             {                 _request.Timeout = 35000;                 _request.ReadWriteTimeout = 35000;             }              if (NoCachePolicy == false)             {                 var noCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);                 _request.CachePolicy = noCachePolicy;             }              foreach (KeyValuePair<string, string> keyValuePair in Headers)             {                 _request.Headers.Add(keyValuePair.Key, keyValuePair.Value);             }              if (UserAgent == null) _request.UserAgent = Data.Ie11;             else _request.UserAgent = UserAgent;               if (AllowAutoRedirect != null)                 _request.AllowAutoRedirect = (bool)AllowAutoRedirect;              if (KeepAlive != null)                 _request.KeepAlive = (bool)KeepAlive;              if (Expect100Continue != null)                 _request.ServicePoint.Expect100Continue = (bool)Expect100Continue;               if (!Referer.IsEmpty())                 _request.Referer = Referer;              _request.CookieContainer = cookies;              try             {                 HttpWebResponse response = (HttpWebResponse)_request.GetResponse();                  if ((response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.Redirect) && response.ContentType.StartsWith("image", StringComparison.OrdinalIgnoreCase))                 {                     // if the remote file was found, download oit                     using (Stream inputStream = response.GetResponseStream())                     {                         byte[] buffer = new byte[64000];                         int bytesRead;                          bytesRead = inputStream.Read(buffer, 0, buffer.Length);                         Response = Convert.ToBase64String(buffer, 0, bytesRead);                     }                 }                 else                 {                     var stream = response.GetResponseStream();                      if (stream != null) Response = new StreamReader(stream).ReadToEnd();                     ResponseHeaders = response.Headers;                     RequestHeaders = _request.Headers;                 }                   response.Close();             }             catch (WebException ex)             {                 using (var stream = ex.Response.GetResponseStream())                 using (var reader = new StreamReader(stream))                 {                     Response = reader.ReadToEnd();                 }             }             catch (Exception ex)             {             }          }          Dictionary<string, string> Headers = new Dictionary<string, string>();         public void AddHeader(string headerName, string headerValue)         {             Headers[headerName] = headerValue;         }         public bool NoCachePolicy { get; set; }         public bool AcceptGZipEncoding { get; set; }         public bool UseUnsafeHeaderParsing { get; set; }         public string Address { get; set; }         public string Accept { get; set; }         public string Referer { get; set; }         public string Host { get; set; }         public bool? KeepAlive { get; set; }         public string ContentType { get; set; }         public bool? Expect100Continue { get; set; }         public string Response { get; private set; }         public bool? AllowAutoRedirect { get; set; }         public WebHeaderCollection ResponseHeaders { get; private set; }         public WebHeaderCollection RequestHeaders { get; private set; }         public string UserAgent { get; set; }         public WebProxy Proxy { get; set; }         public bool TurnOffProxy { get; set; }         public int TimeOut { get; set; }      }

PostRequest
    public class PostRequest     {         private HttpWebRequest _request;         public void Run(ref CookieContainer cookies)         {             _request = (HttpWebRequest)WebRequest.Create(Address);             _request.Method = "POST";             _request.Host = Host;             _request.Headers.Add("DNT", "1");             _request.Proxy = Proxy;              _request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;              if (TimeOut > 0)             {                 _request.Timeout = TimeOut;                 _request.ReadWriteTimeout = TimeOut;             }             else             {                 _request.Timeout = 90000;                 _request.ReadWriteTimeout = 90000;             }              var noCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);             _request.CachePolicy = noCachePolicy;              if (Expect100Continue == true) _request.ServicePoint.Expect100Continue = true;             else _request.ServicePoint.Expect100Continue = false;              _request.ContentType = ContentType;             _request.Accept = Accept;             _request.Referer = Referer;              _request.KeepAlive = KeepAlive;              foreach (KeyValuePair<string, string> keyValuePair in Headers)             {                 _request.Headers.Add(keyValuePair.Key, keyValuePair.Value);             }              _request.CookieContainer = cookies;              if (UserAgent == null) _request.UserAgent = Dom.Catalog.Data.Ie11;             else _request.UserAgent = UserAgent;              if (AllowAutoRedirect != null)                 _request.AllowAutoRedirect = (bool)AllowAutoRedirect;               byte[] sentData;             if (ByteData != null) sentData = ByteData;             else sentData = Encoding.UTF8.GetBytes(Data);               _request.ContentLength = sentData.Length;             Stream sendStream = _request.GetRequestStream();             sendStream.Write(sentData, 0, sentData.Length);             sendStream.Close();             WebResponse response = _request.GetResponse();              ResponseHeaders = response.Headers;             RequestHeaders = _request.Headers;              Stream stream = response.GetResponseStream();             if (stream != null)             {                 if (ResponseEncoding.IsEmpty()) Response = new StreamReader(stream).ReadToEnd();                 else Response = new StreamReader(stream, Encoding.GetEncoding(ResponseEncoding)).ReadToEnd();             }             response.Close();         }          Dictionary<string, string> Headers = new Dictionary<string, string>();         public void AddHeader(string headerName, string headerValue)         {             Headers[headerName] = headerValue;         }         public bool NoCachePolicy { get; set; }         public string Response { get; set; }         public string ResponseEncoding { get; set; }         public string Data { get; set; }         public byte[] ByteData { get; set; }         public string Address { get; set; }         public string Accept { get; set; }         public string Host { get; set; }         public string ContentType { get; set; }         public string Referer { get; set; }         public bool KeepAlive { get; set; }         public bool? Expect100Continue { get; set; }         public string UserAgent { get; set; }         public bool? AllowAutoRedirect { get; set; }         public WebHeaderCollection ResponseHeaders { get; private set; }         public WebHeaderCollection RequestHeaders { get; private set; }         public WebProxy Proxy { get; set; }         public int TimeOut { get; set; }     }

В переменные user и password необходимо внести значения Вашего аккаунта.

В cookies у нас будут храниться все cookie выполненных запросов.

proxy — это адрес Вашего прокси. Например, «127.0.0.1:8888» — стандартный адрес запущенного Fiddler.

SecurityProtocolType.Tls12 — указание используемого протокола безопасности.

var user = "user";              // !!! rewrite value from your account !!! var password = "password";      // !!! rewrite value from your account !!!  // We keep cookies here var cookies = new CookieContainer();  // Any proxy, for example Fiddler var proxy = new WebProxy("127.0.0.1:8888");  ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Для выполнения авторизации на портале необходимо получить cookie и некоторые переменные, которые хранятся в результате запроса «https://www.blablacar.ru/».

var getRequest = new GetRequest() {      Address = "https://www.blablacar.ru/",      Accept = "text/html, application/xhtml+xml, image/jxr, */*",      Host = "www.blablacar.ru",      KeepAlive = true,      UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko",      Proxy = proxy }; getRequest.Run(ref cookies);

Используя нехитрые методы работы с текстом, находим значение переменной «visitorId»:

var visitorStart = getRequest.Response.IndexOf("visitorId") + 12; var visitorEnd = getRequest.Response.IndexOf("\"", visitorStart); var visitorId = getRequest.Response.Substring(visitorStart, visitorEnd - visitorStart);

В переменную xCorrelationId необходимо передать случайный GUID.

Теперь все значения готовы чтобы выполнить авторизацию на портале.

// Random value var xCorrelationId = Guid.NewGuid();  // Auth request var data = $"{{\"login\":\"{user}\",\"password\":\"{password}\",\"rememberMe\":true,\"grant_type\":\"password\"}}"; var postRequest = new PostRequest() {     Data = data,     Address = $"https://auth.blablacar.ru/secure-token",     Accept = "application/json",     Host = "auth.blablacar.ru",     ContentType = "application/json",     Referer = "https://www.blablacar.ru/login/email",     KeepAlive = true,     Proxy = proxy }; postRequest.AddHeader("x-client", "SPA|1.0.0"); postRequest.AddHeader("x-correlation-id", xCorrelationId.ToString()); postRequest.AddHeader("x-currency", "RUB"); postRequest.AddHeader("x-forwarded-proto", "https"); postRequest.AddHeader("x-locale", "ru_RU"); postRequest.AddHeader("x-visitor-id", visitorId); postRequest.AddHeader("Origin", "https://www.blablacar.ru"); postRequest.Run(ref cookies);

В ответе на POST-запрос авторизации мы должны получить значение еще одной переменной, назовем ее «bearerCookieValue». Это значение хранится в заголовках «Set-Cookie» ответа.

var bearerCookieValue = string.Empty; var headers = postRequest.ResponseHeaders; for (int i = 0; i < headers.Count; ++i) {     string header = headers.GetKey(i);      if (header == "Set-Cookie")     {          var headerValue = headers.GetValues(i)[0];          headerValue = WebUtility.UrlDecode(headerValue);           var accessTokenStart = postRequest.Response.IndexOf("access_token") + 15;          var accessTokenEnd = postRequest.Response.IndexOf("\"", accessTokenStart);          bearerCookieValue = postRequest.Response.Substring(accessTokenStart, accessTokenEnd - accessTokenStart);     } }

Список выполненных поездок

Теперь все готово чтобы выполнять запросы за необходимой информацией. Весь код сформирован на основании просмотренных заголовков запроса/ответа в прокси-сервере Fiddler.

getRequest = new GetRequest() {     Address = "https://edge.blablacar.ru/bookings-and-tripoffers?active=false",     Accept = "application/json",     Host = "edge.blablacar.ru",     KeepAlive = true,     ContentType = "application/json",     Referer = "https://www.blablacar.ru/rides/history",     Proxy = proxy }; getRequest.AddHeader("x-blablacar-accept-endpoint-version", "2"); getRequest.AddHeader("x-client", "SPA|1.0.0"); getRequest.AddHeader("x-correlation-id", xCorrelationId.ToString()); getRequest.AddHeader("x-currency", "RUB"); getRequest.AddHeader("x-forwarded-proto", "https"); getRequest.AddHeader("x-locale", "ru_RU"); getRequest.AddHeader("x-visitor-id", visitorId); getRequest.AddHeader("authorization", $"Bearer {bearerCookieValue}"); getRequest.AddHeader("Origin", "https://www.blablacar.ru"); getRequest.Run(ref cookies);

Ответ получаем в виде JSON-формата:

Находим список всех поездок на портале

В данном примере найдем список всех поездок из Москвы в Санкт-Петербург на 15 декабря 2020 года.

var date = "2020-12-15"; var searchUid = Guid.NewGuid();  getRequest = new GetRequest() {     Address = $"https://edge.blablacar.ru/trip/search?from_coordinates=55.755826%2C37.617299&from_country=RU&to_coordinates=59.931058%2C30.360909&to_country=RU&departure_date={date}&min_departure_time=00%3A00%3A00&requested_seats=1&passenger_gender=UNKNOWN&search_uuid={searchUid}",     Accept = "application/json",     Host = "edge.blablacar.ru",     KeepAlive = true,     ContentType = "application/json",     Referer = "https://www.blablacar.ru/",     Proxy = proxy }; getRequest.AddHeader("x-blablacar-accept-endpoint-version", "2"); getRequest.AddHeader("x-client", "SPA|1.0.0"); getRequest.AddHeader("x-correlation-id", xCorrelationId.ToString()); getRequest.AddHeader("x-currency", "RUB"); getRequest.AddHeader("x-forwarded-proto", "https"); getRequest.AddHeader("x-locale", "ru_RU"); getRequest.AddHeader("x-visitor-id", visitorId); getRequest.AddHeader("authorization", $"Bearer {bearerCookieValue}"); getRequest.AddHeader("Origin", "https://www.blablacar.ru"); getRequest.Run(ref cookies);

В ответе на запрос получаем JSON-строку с поездками на портале:

Готово

ссылка на оригинал статьи https://habr.com/ru/post/532788/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *