Можно ли использовать «BrowserSession» для загрузки файлов? C #

c# cookies download html-agility-pack

Вопрос

У меня есть сайт, который требует входа в систему, прежде чем он позволит вам загружать файлы. В настоящее время я использую класс BrowserSession для входа и выполнения всех необходимых исправлений (по крайней мере, по большей части).

Источник BrowserSession в нижней части сообщения:

Ссылки загрузки отображаются на узлах документа. Но я не знаю, как добавить функциональность загрузки к этому классу, и если я попытаюсь загрузить их с помощью веб-клиента, это не сработает, мне уже пришлось сильно модифицировать класс BrowserSession (я должен был изменить его как часть, но didn ' t) Таким образом, я действительно не хочу переходить от использования класса BrowserSession.

Я считаю, что он использует htmlAgilityPack.HtmlWeb для загрузки и загрузки веб-страниц.

Если нет простого способа изменить BrowserSession, можно ли каким-то образом использовать CookieCollection с Webclient?

PS: Мне нужно войти в систему, чтобы загрузить файл, иначе ссылка перенаправляется на экран входа в систему. Вот почему я не могу просто использовать WebClient и должен либо модифицировать класс BrowserSession для загрузки, либо изменить WebClient для использования файлов cookie перед тем, как получить страницу.

Я признаю, что не очень хорошо разбираюсь в файлах cookie (я не уверен, что они используются каждый раз, когда используется GET, или если его просто на POST), но до сих пор BrowserSession позаботился обо всем этом.

PPS: The BrowserSession, который я написал, не тот, который я добавил, тоже, но основные функции все одинаковы.

public class BrowserSession
{
private bool _isPost;
private HtmlDocument _htmlDoc;

/// <summary>
/// System.Net.CookieCollection. Provides a collection container for instances of Cookie class 
/// </summary>
public CookieCollection Cookies { get; set; }

/// <summary>
/// Provide a key-value-pair collection of form elements 
/// </summary>
public FormElementCollection FormElements { get; set; }

/// <summary>
/// Makes a HTTP GET request to the given URL
/// </summary>
public string Get(string url)
{
    _isPost = false;
    CreateWebRequestObject().Load(url);
    return _htmlDoc.DocumentNode.InnerHtml;
}

/// <summary>
/// Makes a HTTP POST request to the given URL
/// </summary>
public string Post(string url)
{
    _isPost = true;
    CreateWebRequestObject().Load(url, "POST");
    return _htmlDoc.DocumentNode.InnerHtml;
}

/// <summary>
/// Creates the HtmlWeb object and initializes all event handlers. 
/// </summary>
private HtmlWeb CreateWebRequestObject()
{
    HtmlWeb web = new HtmlWeb();
    web.UseCookies = true;
    web.PreRequest = new HtmlWeb.PreRequestHandler(OnPreRequest);
    web.PostResponse = new HtmlWeb.PostResponseHandler(OnAfterResponse);
    web.PreHandleDocument = new HtmlWeb.PreHandleDocumentHandler(OnPreHandleDocument);
    return web;
}

/// <summary>
/// Event handler for HtmlWeb.PreRequestHandler. Occurs before an HTTP request is executed.
/// </summary>
protected bool OnPreRequest(HttpWebRequest request)
{
    AddCookiesTo(request);               // Add cookies that were saved from previous requests
    if (_isPost) AddPostDataTo(request); // We only need to add post data on a POST request
    return true;
}

/// <summary>
/// Event handler for HtmlWeb.PostResponseHandler. Occurs after a HTTP response is received
/// </summary>
protected void OnAfterResponse(HttpWebRequest request, HttpWebResponse response)
{
    SaveCookiesFrom(response); // Save cookies for subsequent requests
}

/// <summary>
/// Event handler for HtmlWeb.PreHandleDocumentHandler. Occurs before a HTML document is handled
/// </summary>
protected void OnPreHandleDocument(HtmlDocument document)
{
    SaveHtmlDocument(document);
}

/// <summary>
/// Assembles the Post data and attaches to the request object
/// </summary>
private void AddPostDataTo(HttpWebRequest request)
{
    string payload = FormElements.AssemblePostPayload();
    byte[] buff = Encoding.UTF8.GetBytes(payload.ToCharArray());
    request.ContentLength = buff.Length;
    request.ContentType = "application/x-www-form-urlencoded";
    System.IO.Stream reqStream = request.GetRequestStream();
    reqStream.Write(buff, 0, buff.Length);
}

/// <summary>
/// Add cookies to the request object
/// </summary>
private void AddCookiesTo(HttpWebRequest request)
{
    if (Cookies != null && Cookies.Count > 0)
    {
        request.CookieContainer.Add(Cookies);
    }
}

/// <summary>
/// Saves cookies from the response object to the local CookieCollection object
/// </summary>
private void SaveCookiesFrom(HttpWebResponse response)
{
    if (response.Cookies.Count > 0)
    {
        if (Cookies == null)  Cookies = new CookieCollection(); 
        Cookies.Add(response.Cookies);
    }
}

/// <summary>
/// Saves the form elements collection by parsing the HTML document
/// </summary>
private void SaveHtmlDocument(HtmlDocument document)
{
    _htmlDoc = document;
    FormElements = new FormElementCollection(_htmlDoc);
}
}

Класс FormElementCollection:

/// <summary>
/// Represents a combined list and collection of Form Elements.
/// </summary>
public class FormElementCollection : Dictionary<string, string>
{
/// <summary>
/// Constructor. Parses the HtmlDocument to get all form input elements. 
/// </summary>
public FormElementCollection(HtmlDocument htmlDoc)
{
    var inputs = htmlDoc.DocumentNode.Descendants("input");
    foreach (var element in inputs)
    {
        string name = element.GetAttributeValue("name", "undefined");
        string value = element.GetAttributeValue("value", "");
        if (!name.Equals("undefined")) Add(name, value);
    }
}

/// <summary>
/// Assembles all form elements and values to POST. Also html encodes the values.  
/// </summary>
public string AssemblePostPayload()
{
    StringBuilder sb = new StringBuilder();
    foreach (var element in this)
    {
        string value = System.Web.HttpUtility.UrlEncode(element.Value);
        sb.Append("&" + element.Key + "=" + value);
    }
    return sb.ToString().Substring(1);
}
}

Принятый ответ

Мне удалось заставить его работать, используя BrowserSession и измененный webClient:

Во-первых, измените _htmlDoc на Public для доступа к документам. Узлы:

public class BrowserSession
{
    private bool _isPost;
    public string previous_Response { get; private set; }
    public HtmlDocument _htmlDoc { get; private set; }
}

Во-вторых, добавьте этот метод в BrowserSession:

 public void DownloadCookieProtectedFile(string url, string Filename)
    {
        using (CookieAwareWebClient wc = new CookieAwareWebClient())
        {
            wc.Cookies = Cookies;
            wc.DownloadFile(url, Filename);
        }
    }
//rest of BrowserSession

Третий Добавить этот класс Где-то, что позволяет передавать файлы cookie из BrowserSession в WebClient.

public class CookieAwareWebClient : WebClient
{
    public CookieCollection Cookies = new CookieCollection();
    private void AddCookiesTo(HttpWebRequest request)
    {
        if (Cookies != null && Cookies.Count > 0)
        {
            request.CookieContainer.Add(Cookies);
        }
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
        HttpWebRequest webRequest = request as HttpWebRequest;
        if (webRequest != null)
        {
            if (webRequest.CookieContainer == null) webRequest.CookieContainer = new CookieContainer();
            AddCookiesTo(webRequest);
        }
        return request;
    }
}

Это должно дать вам возможность использовать BrowserSession, как обычно, и когда вам нужно получить файл, доступ к которому вы можете получить. Если вы вошли в систему, просто вызовите BrowserSession.DownloadCookieProtectedFile () Как если бы это был WebClient, установите только файлы cookie вот так:

Using(wc = new CookieAwareWebClient())
{
    wc.Cookies = BrowserSession.Cookies
    //Download with WebClient As normal
    wc.DownloadFile();
}

Популярные ответы

Нелегко войти в систему и загрузить веб-страницы. У меня недавно была такая же проблема. Если вы найдете решение aisde из этого, предоставьте его.

Теперь, что я сделал, я использовал Selenium с PhantomJS. С Selenium я могу взаимодействовать с веб-браузером по своему выбору.

Также класс Browser не использует Html Agility Pack, который является сторонней библиотекой, доступной через nuget.

Я хочу передать вам этот вопрос , где я создал целый пример использования Selenium и как загрузить HtmlDocument и отфильтровать необходимую информацию с помощью xpath.



Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow