2010-08-12 20 views
12

मैं के लिए लॉग इन और बाद में फेसबुक के आसपास नेविगेट करने HtmlAgilityPack साथ मिलकर रोहित अग्रवाल के BrowserSession वर्ग का उपयोग करने के कोशिश कर रहा हूँ के माध्यम से फेसबुक में प्रवेश करने की BrowserSession और HtmlAgilityPack का उपयोग करना।नेट

मैं पहले अपने ही HttpWebRequest के लिख कर एक ही कर रही है प्रबंधित किया है। हालांकि, यह तब काम करता है जब मैं मैन्युअल रूप से कुकी को अपने ब्राउज़र से लाता हूं और हर बार जब मैं नया "सत्र" कर रहा हूं तो अनुरोध पर ताजा कुकी-स्ट्रिंग डालें। अब मैं स्मार्ट नेविगेशन प्राप्त करने के लिए ब्राउज़र सत्र का उपयोग करने की कोशिश कर रहा हूं।

BrowserSession b = new BrowserSession(); 

b.Get(@"http://www.facebook.com/login.php"); 
b.FormElements["email"] = "[email protected]"; 
b.FormElements["pass"] = "xxxxxxxx"; 
b.FormElements["lsd"] = "qDhIH"; 
b.FormElements["trynum"] = "1"; 
b.FormElements["persistent_inputcheckbox"] = "1"; 

var response = b.Post(@"https://login.facebook.com/login.php?login_attempt=1"); 

ऊपर ठीक काम करता है:

यहाँ वर्तमान कोड है। समस्या तब आती है जब मैं एक और पेज लाने के लिए इस ब्राउज़र सत्र का फिर से उपयोग करने का प्रयास करता हूं। मैं इसे इस तरह से कर रहा हूं क्योंकि ब्राउज़र सत्र आखिरी प्रतिक्रिया से कुकीज़ को सहेजता है और उन्हें अगले अनुरोध में डालता है, इस प्रकार मुझे अपने ब्राउजर से मैन्युअल रूप से पकाया गया पकाया गया नहीं होना चाहिए।

हालांकि

, जब मैं कुछ इस तरह से करने की कोशिश:

var profilePage = b.Get(@"https://m.facebook.com/profile.php?id=1111111111"); 

डॉक मैं वापस पाने खाली है। मैं जो भी गलत कर रहा हूं उस पर किसी भी इनपुट की सराहना करता हूं।

उत्तर

9

क्षमा करें, मैं HTML चपलता पैक या BrowserSession वर्ग आप उल्लेख किया है के बारे में ज्यादा पता नहीं है। लेकिन मैंने HtmlUnit के साथ एक ही परिदृश्य का प्रयास किया और यह ठीक काम कर रहा है। मैं एक .NET आवरण (जिनमें से स्रोत कोड here पाया जा सकता है और थोड़ा अधिक here समझाया गया है) का उपयोग कर रहा है, और यहाँ कोड मैं का उपयोग किया है है (कुछ विवरण मासूम की रक्षा करने के लिए निकाला गया):

var driver = new HtmlUnitDriver(true); 
driver.Url = @"http://www.facebook.com/login.php"; 

var email = driver.FindElement(By.Name("email")); 
email.SendKeys("[email protected]"); 

var pass = driver.FindElement(By.Name("pass")); 
pass.SendKeys("xxxxxxxx"); 

var inputs = driver.FindElements(By.TagName("input")); 
var loginButton = (from input in inputs 
        where input.GetAttribute("value").ToLower() == "login" 
        && input.GetAttribute("type").ToLower() == "submit" 
        select input).First(); 
loginButton.Click(); 

driver.Url = @"https://m.facebook.com/profile.php?id=1111111111"; 
Assert.That(driver.Title, Is.StringContaining("Title of page goes here")); 

उम्मीद है कि यह मदद करता है।

+0

धन्यवाद! यह एक अच्छा समाधान था और ठीक काम किया :) –

+0

आपका स्वागत है। आपकी परियोजना के साथ शुभकामनाएँ :) – Mhmmd

+0

मैंने सोचा कि यह केवल जावा के लिए था, इसका उपयोग .net – Smith

0

क्या आपने अपनी नई एपीआई जांच ली है? http://developers.facebook.com/docs/authentication/

आप एक OAuth2.0 पहुंच टोकन प्राप्त करने के लिए एक सीधा URL को कॉल और देते हैं कि आपके अनुरोधों के बाकी पर कर सकते हैं ...

https://graph.facebook.com/oauth/authorize? 
    client_id=...& 
    redirect_uri=http://www.example.com/oauth_redirect 

जो कुछ यूआरएल आप चाहते हैं redirect_uri बदलें, और यह होगा उस पर "access_token" नामक पैरामीटर के साथ वापस कॉल करें। इसे प्राप्त करें और जो भी स्वचालित एसडीके कॉल आप चाहते हैं उसे बनाएं।

+0

उत्तर के लिए धन्यवाद। मैं केवल सामाजिक ग्राफिंग में एक निजी शोध कर रहा हूं और पृष्ठों को मैन्युअल रूप से सहेजने के बजाय केवल अपने दोस्तों के माध्यम से अपनी ब्राउज़िंग स्वचालित करने की आवश्यकता है। शायद इसे मैन्युअल रूप से करने में बहुत कम समय लगेगा, लेकिन यह अधिक मजेदार स्वचालित होगा :) मुझे आवश्यकता नहीं है या चाहते हैं और वास्तविक फेसबुक ऐप। इसके अलावा, एपीआई उन सभी को नहीं देख सकता जो मैं स्वयं को लॉग इन उपयोगकर्ता के रूप में देख सकता हूं, और किसी भी तरह से मेरा वर्तमान कार्य जो मैं अटक गया हूं, ब्राउजर सत्र का सही तरीके से उपयोग करना सीख रहा है। –

2

आप अपने ब्राउज़र को ड्राइव करने के लिए WatiN (Web Application Testing In .Net) या Selenium का उपयोग करना चाह सकते हैं। इससे यह सुनिश्चित करने में मदद मिलेगी कि आपको कुकीज़ के साथ परेशान नहीं होना है और बाद में अनुरोध करने के लिए कोई कस्टम काम करना है क्योंकि आप वास्तविक उपयोगकर्ता को अनुकरण कर रहे हैं।

+0

उत्तर के लिए धन्यवाद, मुझे अभी मेरा समाधान मिला है लेकिन बाद में आपके उदाहरणों पर वापस आ सकता है :) –

1

आज मुझे एक ही समस्या का सामना करना पड़ रहा था। मैंने रोहित अग्रवाल की BrowserSession कक्षा के साथ एचटीएमएलएगिलिटीपैक के साथ भी काम किया। पूरे दिन परीक्षण और त्रुटि प्रोग्रामिंग के बाद, मुझे पता चला कि समस्या का कारण बनता है, क्योंकि बाद के अनुरोधों में सही कुकीज़ सेट नहीं किया जाता है। मैंने प्रारंभिक ब्राउज़र सत्र कोड को सही तरीके से काम करने के लिए नहीं बदला है, लेकिन मैंने निम्नलिखित फ़ंक्शंस जोड़े और समान रूप से समानक्यूफ्रो-फ़ंक्शन को संशोधित किया। अंत में यह मेरे लिए अच्छी तरह से काम किया।

class BrowserSession{ 
    private bool _isPost; 
    private HtmlDocument _htmlDoc; 
    public CookieContainer cookiePot; //<- This is the new CookieContainer 

... 

    public string Get2(string url) 
    { 
     HtmlWeb web = new HtmlWeb(); 
     web.UseCookies = true; 
     web.PreRequest = new HtmlWeb.PreRequestHandler(OnPreRequest2); 
     web.PostResponse = new HtmlWeb.PostResponseHandler(OnAfterResponse2); 
     HtmlDocument doc = web.Load(url); 
     return doc.DocumentNode.InnerHtml; 
    } 
    public bool OnPreRequest2(HttpWebRequest request) 
    { 
     request.CookieContainer = cookiePot; 
     return true; 
    } 
    protected void OnAfterResponse2(HttpWebRequest request, HttpWebResponse response) 
    { 
     //do nothing 
    } 
    private void SaveCookiesFrom(HttpWebResponse response) 
    { 
     if ((response.Cookies.Count > 0)) 
     { 
      if (Cookies == null) 
      { 
       Cookies = new CookieCollection(); 
      }  
      Cookies.Add(response.Cookies); 
      cookiePot.Add(Cookies);  //-> add the Cookies to the cookiePot 
     } 
    } 

यह क्या करता है:

जोड़ा/संशोधित कार्यों अनुसरण कर रहे हैं यह मूल रूप से प्रारंभिक "पोस्ट-रिस्पांस" से कुकीज़ की बचत होती है और अनुरोध बाद में कहा जाता है के लिए एक ही CookieContainer कहते हैं। मैं पूरी तरह समझ नहीं पा रहा हूं कि यह प्रारंभिक संस्करण में क्यों काम नहीं कर रहा था क्योंकि यह किसी भी तरह AddCookiesTo-function में समान होता है। (यदि (कुकीज़! = शून्य & & कुकीज़.काउंट> 0) अनुरोध। कूकी कंटनर। जोड़ें (कुकीज़);) किसी भी तरह, इन अतिरिक्त कार्यों के साथ इसे अभी ठीक काम करना चाहिए।

यह इस तरह इस्तेमाल किया जा सकता:

//initial "Login-procedure" 
BrowserSession b = new BrowserSession(); 
b.Get("http://www.blablubb/login.php"); 
b.FormElements["username"] = "yourusername"; 
b.FormElements["password"] = "yourpass"; 
string response = b.Post("http://www.blablubb/login.php"); 

बाद के सभी कॉल का उपयोग करना चाहिए:

response = b.Get2("http://www.blablubb/secondpageyouwannabrowseto"); 
response = b.Get2("http://www.blablubb/thirdpageyouwannabrowseto"); 
... 

मुझे आशा है कि यह एक ही समस्या का सामना करना पड़ कई लोगों को मदद करता है!

12

यदि कोई परवाह करता है तो मैंने इसका मूल कारण तय कर दिया है। यह पता चला है कि कुकीज़ को अनुरोध वस्तु के कुकी कॉन्टेनर में सहेजा जा रहा था, प्रतिक्रिया प्रतिक्रिया नहीं। मैंने फ़ाइल डाउनलोड करने की क्षमता भी जोड़ा (बशर्ते कि फ़ाइल स्ट्रिंग आधारित है)। संहिता निश्चित रूप से थ्रेड-सुरक्षित नहीं है, लेकिन वस्तु थ्रेड-सुरक्षित नहीं किया गया था के साथ शुरू:

public class BrowserSession 
{ 
    private bool _isPost; 
    private bool _isDownload; 
    private HtmlDocument _htmlDoc; 
    private string _download; 

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

    public string GetDownload(string url) 
    { 
     _isPost = false; 
     _isDownload = true; 
     CreateWebRequestObject().Load(url); 
     return _download; 
    } 

    /// <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(request, response); // Save cookies for subsequent requests 

     if (response != null && _isDownload) 
     { 
      Stream remoteStream = response.GetResponseStream(); 
      var sr = new StreamReader(remoteStream); 
      _download = sr.ReadToEnd(); 
     } 
    } 

    /// <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(HttpWebRequest request, HttpWebResponse response) 
    { 
     //save the cookies ;) 
     if (request.CookieContainer.Count > 0 || response.Cookies.Count > 0) 
     { 
      if (Cookies == null) 
      { 
       Cookies = new CookieCollection(); 
      } 

      Cookies.Add(request.CookieContainer.GetCookies(request.RequestUri)); 
      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); 
    } 
} 

/// <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 (!this.ContainsKey(name)) 
      { 
       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); 
    } 
} 
2

मैं था इसी तरह के लक्षण - लॉगिन काम किया लेकिन प्रमाणीकरण कुकी कुकी कंटेनर में मौजूद नहीं था और इसलिए यह नहीं था बाद के अनुरोधों पर भेजा गया। मुझे पता चला कि ऐसा इसलिए था क्योंकि वेब अनुरोध स्थान को संभालने में था: आंतरिक रूप से शीर्षलेख, दृश्यों के पीछे एक नए पृष्ठ पर रीडायरेक्ट करना, प्रक्रिया में कुकीज़ खोना। मैं जोड़कर इस तय:

request.AllowAutoRedirect = false; // Location header messing up cookie handling! 

... OnPreRequest() फ़ंक्शन करने के लिए। अब यह इस तरह दिखता है:

protected bool OnPreRequest(HttpWebRequest request) 
    { 
     request.AllowAutoRedirect = false; // Location header messing up cookie handling! 

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

मुझे उम्मीद है कि यह किसी को भी एक ही समस्या का सामना करने में मदद कर सकता है।