Est-il possible d'utiliser "BrowserSession" pour télécharger des fichiers? C #

c# cookies download html-agility-pack

Question

J'ai un site qui nécessite une connexion avant de vous permettre de télécharger des fichiers. Actuellement, j'utilise la classe BrowserSession pour me connecter et faire tout le travail de grattage requis (du moins pour la plupart).

Source de la classe BrowserSession au bas du message:

Les liens de téléchargement apparaissent sur les nœuds du document. Mais je ne sais pas comment ajouter une fonctionnalité de téléchargement à cette classe, et si j'essaie de les télécharger avec un client Web, cela signifie que je dois déjà fortement modifier la classe BrowserSession (je l'aurais probablement modifiée en tant que Partielle mais non. t) Je ne veux donc pas vraiment changer d’utilisation de la classe BrowserSession.

Je crois que son utilisation de htmlAgilityPack.HtmlWeb pour télécharger et charger les pages Web.

S'il n'y a pas de moyen facile de modifier BrowserSession, existe-t-il un moyen d'utiliser son CookieCollection With Webclient?

PS: Je dois être connecté pour télécharger le fichier, sinon le lien redirige vers l'écran de connexion. C'est pourquoi je ne parviens pas à utiliser simplement WebClient et que je dois soit modifier la classe BrowserSession pour pouvoir télécharger, soit modifier WebClient afin qu'il utilise des cookies avant d'obtenir une page.

J'admettrai que je ne comprends pas très bien les cookies (je ne suis pas sûr qu'ils soient utilisés chaque fois que GET est utilisé, ou si c'est juste sur POST), mais jusqu'à présent, BrowserSession s'est occupé de tout cela.

PPS: La BrowserSession que j'ai publiée n'est pas celle à laquelle j'ai ajouté des éléments, mais les fonctions principales sont les mêmes.

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);
}
}

Classe 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);
}
}

Réponse acceptée

J'ai réussi à le faire fonctionner à l'aide de BrowserSession et d'un client Web modifié:

Commencez par changer le _htmlDoc en Public pour accéder au document Nodes:

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

Deuxièmement, ajoutez cette méthode à BrowserSession:

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

Troisième Ajouter cette classe quelque part, ce qui permet de transmettre les cookies de BrowserSession au Web Client.

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;
    }
}

Cela devrait vous donner la possibilité d'utiliser BrowserSession comme vous le feriez normalement, et lorsque vous devez obtenir un fichier auquel vous pouvez uniquement accéder. ainsi:

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

Réponse populaire

Il n'est pas facile de se connecter et de télécharger les pages Web. J'ai récemment eu le même problème. Si vous trouvez une solution à partir de celle-ci, merci de la fournir.

Maintenant, ce que j'ai fait, c'est que j'ai utilisé Selenium avec PhantomJS. Avec Selenium, je peux interagir avec le navigateur Web de mon choix.

De plus, la classe de navigateur n'utilise pas Html Agility Pack, une bibliothèque tierce disponible via nuget.

Je souhaite vous renvoyer à cette question , dans laquelle j'ai créé un exemple complet expliquant comment utiliser Selenium et comment télécharger le document HTML et filtrer les informations nécessaires à l'aide de xpath.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow