어쨌든 "BrowserSession"을 사용하여 파일을 다운로드합니까? 기음#

c# cookies download html-agility-pack

문제

파일을 다운로드하기 전에 로그인이 필요한 사이트가 있습니다. 현재 BrowserSession 클래스를 사용하여 로그인하고 모든 스크래핑 작업을 수행합니다 (적어도 대부분).

게시물 하단의 BrowserSession 클래스 소스 :

다운로드 링크가 문서 노드에 나타납니다. 하지만 그 클래스에 다운로드 기능을 추가하는 방법을 모르겠다. 웹 클라이언트와 함께 다운로드하려고하면 이미 BrowserSession 클래스를 많이 수정해야한다. (부분적으로 수정해야하지만, t) 그래서 나는 BrowserSession 클래스 사용을 바꾸고 싶지 않습니다.

htmlAgilityPack.HtmlWeb을 사용하여 웹 페이지를 다운로드하고로드한다고 생각합니다.

BrowserSession을 쉽게 수정할 수있는 방법이 없다면 CookieCollection을 Webclient와 함께 사용할 수 있습니까?

추신 : 파일을 다운로드하려면 로그인해야합니다. 그렇지 않으면 링크가 로그인 화면으로 리디렉션됩니다. 그래서 WebClient를 단순히 사용할 수 없으며 다운로드 할 수 있도록 BrowserSession 클래스를 수정하거나 페이지를 받기 전에 쿠키를 사용하도록 WebClient를 수정해야합니다.

나는 내가 쿠키를 잘 이해하지 못한다는 것을 인정할 것이다. (GET이 사용될 때마다 사용되는지 아니면 POST시에만 사용되는지는 모르겠다.) 그러나 지금까지 BrowserSession이 모든 것을 처리했다.

조달청 : 내가 올린 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 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

셋째,이 클래스를 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 인 것처럼 쿠키 만 설정하십시오 이렇게 :

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

인기 답변

웹 페이지에 로그인하여 다운로드하는 것은 쉽지 않습니다. 최근에 같은 문제가 생겼습니다. 이 솔루션에서 해결책을 찾을 수 있다면 제공해주십시오.

이제 필자는 PhantomJS에서 Selenium을 사용했다. Selenium을 사용하면 내가 선택한 웹 브라우저와 상호 작용할 수 있습니다.

또한 Browser 클래스는 Nuget을 통해 사용할 수있는 타사 라이브러리 인 Html Agility Pack을 사용하지 않습니다.

Selenium을 사용하는 방법의 전체 예제와 HtmlDocument를 다운로드하고 xpath를 사용하여 필요한 정보를 필터링하는 방법에 대한 예제를 작성한이 질문 을 참조하겠습니다.



Related

아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow