使用 SSL/TLS 从 url 获取图像

Posted

技术标签:

【中文标题】使用 SSL/TLS 从 url 获取图像【英文标题】:GET Image from url with SSL/TSL 【发布时间】:2017-02-08 20:00:22 【问题描述】:

我的应用程序自动填写了近 30 个字段,只留下少数字段供用户和验证码填写。

我需要从 url 获取并显示验证码。

我尝试了不同的方法,但没有一种方法可以满足我的需要。

网址是captcha link

用chrome你会直接得到图片,用IE你会得到一个文件下载。

第一次尝试

使用 WebBrowser 控件打开 url 如果您尝试使用 WebBrowser 打开 url,您将开始下载文件 如果你像 cap.gif 或 JPG 一样保存它,你会得到正确的图像。

此时我正在尝试自动下载任务以避免向用户显示下载对话框。

像其他 SO 回答 Download file and automatically save it to folder 我尝试处理 WebBrowser 导航

private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)

    e.Cancel = true;
    WebClient client = new WebClient();

    client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
    client.DownloadDataAsync(e.Url);

或直接使用 WebClient

WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadFileAsync(new Uri(url), filepath);

在结果的回调中,您将获得空图像文件(0 字节);

如果您查看 AsyncCompletedEventArgs e,它会生成关于 SSL/TSL 的错误。

The request was aborted: Could not create SSL/TLS secure channel.   
in System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
in System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
in System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)

第二次尝试

将 SSL/TSL 堆栈包含到 WebClient 作为 SO answer The request was aborted: Could not create SSL/TLS secure channel

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AllwaysGoodCertificate);
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadFileAsync(new Uri(captchaUrl), filepath);

这将在回调中返回相同的错误

第三次尝试 从 WebBrowser 控件中获取图像并将标签转换为 PictureBox

如果我尝试在主页内容表单上提取图像,它允许我获取图像 按照 SO 回答How to copy the loaded image in webbrowser to picturebox

[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);

public Bitmap CaptureWindow(Control ctl)

    //Bitmap bmp = new Bitmap(ctl.Width, ctl.Height);  // includes borders
    Bitmap bmp = new Bitmap(ctl.ClientRectangle.Width, ctl.ClientRectangle.Height);  // content only
    using (Graphics graphics = Graphics.FromImage(bmp))
    
        IntPtr hDC = graphics.GetHdc();
        try  PrintWindow(ctl.Handle, hDC, (uint)0); 
        finally  graphics.ReleaseHdc(hDC); 
    
    return bmp;


//Methods to get Co-ordinates Of an Element in your webbrowser
public int getXoffset(htmlElement el)

    int xPos = el.OffsetRectangle.Left;
    HtmlElement tempEl = el.OffsetParent;
    while (tempEl != null)
    
        xPos += tempEl.OffsetRectangle.Left;
        tempEl = tempEl.OffsetParent;
    
    return xPos;


public int getYoffset(HtmlElement el)

    int yPos = el.OffsetRectangle.Top;
    HtmlElement tempEl = el.OffsetParent;
    while (tempEl != null)
    
        yPos += tempEl.OffsetRectangle.Top;
        tempEl = tempEl.OffsetParent;
    
    return yPos;


private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)

    // get captcha
    HtmlElement el = webBrowser1.Document.GetElementById("imgCaptcha");
    IHTMLImgElement img = (IHTMLImgElement)el.DomElement;
    Bitmap bmp = new Bitmap(img.width, img.height);

    int CaptchaWidth = getXoffset(el);
    int CaptchaHeight = getYoffset(el);
    Rectangle rect = new Rectangle(CaptchaWidth, CaptchaHeight, img.width, img.height);

    // with this image il always blank
    //webBrowser1.DrawToBitmap(bmp, rect);

    Bitmap bitmap = CaptureWindow(webBrowser1);
    Bitmap croppedImage = bitmap.Clone(rect, System.Drawing.Imaging.PixelFormat.Undefined);
    pictureBox1.BackgroundImage = croppedImage;

这个工作正常,但不幸的是,这只有在你有 WebBrowser 控件可见时才有效...... :(

任何建议将不胜感激。

【问题讨论】:

【参考方案1】:

经过一些解决后,我发现了一个关于 SSL 的问题,服务器进程协议 TSL 1.2 而不是 SSL3

直接替换

//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

现在 WebClient 运行良好,但在给自己一个正确答案之前,我等待其他人是否有其他实现。

【讨论】:

【参考方案2】:

我要做的改变是使用 async/await,这样我就不必担心设置 WebClient 的 DownloadFileCompleted

这部分和你一样,

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

使用异步方法

public async Task DownloadIt(string url ,string filename)

     using (var client = new WebClient())
     
         await client.DownloadFileTaskAsync(new Uri(url), filename);
     

在需要时这样调用它。

await DownloadIt("https://www.com", @"C:\Path\To\Save");

【讨论】:

以上是关于使用 SSL/TLS 从 url 获取图像的主要内容,如果未能解决你的问题,请参考以下文章

请求已中止:无法创建SSL / TLS安全通道

请求被中止:无法创建 SSL/TLS 安全通道

HTTP、HTTPS、SSL/TLS概述

随机“无法为 SSL/TLS 建立安全通道”错误

请求被中止:无法创建 SSL/TLS 安全通道。

Azure APIM URL 引发 System.Net.WebException - SSL/TLS 如何在 azure web api 和 azure APIM 中发挥作用?