0

I need to get a download link from a site. to get it i need to wait 10 seconds until it will be available to click. is is possible to get the download link with WebBrowser()?

this is the source of button.

<input type="submit" id="btn_download" class="btn btn-primary txt-bold" value="Download File">

this is what i tried:

WebBrowser wb = new WebBrowser();
wb.ScriptErrorsSuppressed = true;
wb.AllowNavigation = true;
wb.Navigate(url);
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
     Application.DoEvents();
}
Thread.Sleep(10000);   
HtmlElement element = wb.Document.GetElementById("btn_download");
element.InvokeMember("submit");
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
     Application.DoEvents();
}
string x = wb.Url.ToString();

what is wrong here?

Edited - tried this but still not working - btw i think i little messed up the code I'm noob :)

        public void WebBrowser()
        {
                WebBrowser wb = new WebBrowser();
                wb.ScriptErrorsSuppressed = true;
                wb.AllowNavigation = true;
                wb.Navigate(URL);
                wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
                while (wb.ReadyState != WebBrowserReadyState.Complete)
                    Application.DoEvents();
                wb.Dispose();
}

    public void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
            {
                WebBrowser wb = (WebBrowser)sender;
                string x = wb.Url.ToString();
                if (!x.Contains("server")) // download link must conatin server
                {
                    System.Timers.Timer t = new System.Timers.Timer();
                    t.Interval = 10000;
                    t.AutoReset = true;
                    t.Elapsed += new ElapsedEventHandler(TimerElapsed);
                    t.Start();
                    HtmlElement element = wb.Document.GetElementById("btn_download");
                    element.InvokeMember("Click");
                    while (wb.ReadyState != WebBrowserReadyState.Complete)
                        Application.DoEvents();
                }
                else
                    MessageBox.Show(x);
              }
        public void TimerElapsed(object sender, ElapsedEventArgs e)
        {
                Application.DoEvents();
        }
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Dorel
  • 103
  • 12
  • It's hard to say what's wrong, when you doesn't tell us what exactly isn't working. But I think at first you should use InvokeMember("Click"); instead of InvokeMember("submit");. Second you try to read the url after the click. But I think when you did the invoke, the browser starts a new navigation. So you should catch the actual url at the beginning of the DocumentCompleted-Handler and check if it's the waiting site or the download site. If waiting, then invoke. If download, then string x = wb.Url.ToString(); – netblognet Aug 29 '14 at 13:34
  • 1
    You are blocking the UI thread (`Thread.Sleep(10000);`). In that duration webbrowser can not do anything. – L.B Aug 29 '14 at 13:39
  • You could use a Timer to avoid blocking. Have a look at this: http://stackoverflow.com/questions/8496275/c-sharp-wait-for-a-while-without-blocking – netblognet Aug 29 '14 at 13:44
  • Seems like the code to check the download link should be in the `wb_DocumentCompleted` delegate method instead of along side your other code. – xDaevax Aug 29 '14 at 13:46
  • You should not be waiting ten seconds in any case. Wait for the DocumentCompleted event. – John Saunders Aug 29 '14 at 14:21
  • Also, if this is Windows Forms, then the WebBrowser control should be on a form. You should not be creating a `new` instance of it. You should also have the `+=` done before you call `Navigate()`. – John Saunders Aug 29 '14 at 14:23
  • Would you provide us with some example links, so that we can check the website and try to give you a better example. – netblognet Aug 29 '14 at 14:27
  • i'm tring to create auto downloader for: sfshare.se (example link id: vydjxq40g503) – Dorel Aug 29 '14 at 16:04

1 Answers1

0

I am not comfortable with answering this, but hope this can show how it can be done differently;

a) You don't need to use Webbrowser control o download a web page

b) You don't need these busy-waitings to await something..

c) It may help to show the use of HttpClient, HtmlAgilityPack + async/await

Now, write a method like below

async Task<string> DownloadLink(string linkID)
{   
    string url = "http://sfshare.se/" + linkID;
    using (var clientHandler = new HttpClientHandler() { CookieContainer = new CookieContainer(), AllowAutoRedirect = false })
    {
        using (HttpClient client = new HttpClient(clientHandler))
        {
            //download html
            var html = await client.GetStringAsync(url).ConfigureAwait(false);

            //Parse it
            var doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);

            var inputs = doc.DocumentNode.SelectNodes("//input[@type='hidden']")
                           .ToDictionary(i => i.Attributes["name"].Value, i => i.Attributes["value"].Value);
            inputs["referer"] = url;

            //Wait 10 seconds
            await Task.Delay(1000 * 10).ConfigureAwait(false);

            //Click :) Send the hidden inputs. op=download2&id=ssmwvrxx815l......
            var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Post, url) { Content = new FormUrlEncodedContent(inputs) })
                                       .ConfigureAwait(false);

            //Get the download url
            var downloadUri = response.Headers.Location.ToString();

            var localFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(downloadUri));

            //Download
            using (var file = File.Create(localFileName))
            {
                var stream = await client.GetStreamAsync(downloadUri).ConfigureAwait(false); ;
                await stream.CopyToAsync(file).ConfigureAwait(false); 
            }

            return localFileName;
        }
    }
}

and invoke it in a method marked async as below

async void Test()
{
    var downloadedFile = await DownloadLink("vydjxq40g503");
}

PS: This answer requires HtmlAgilityPack to parse the returned html.

EZI
  • 15,209
  • 2
  • 27
  • 33
  • thanks but i already know this..the problem is when i try to download other types of files like rar. link id: ssmwvrxx815l – Dorel Aug 30 '14 at 08:06
  • wow thanks for the answer, but i have a problem with the code, its giving me this error: 'HtmlAgilityPack.HtmlNodeCollection' does not contain a definition for 'ToDictionary' and no extension method 'ToDictionary' accepting a first argument of type 'HtmlAgilityPack.HtmlNodeCollection' could be found (are you missing a using directive or an assembly reference?) – Dorel Aug 30 '14 at 14:00
  • I think you are missing `using System.Linq` – EZI Aug 30 '14 at 14:22