网站快照
一个用于拍摄网站图像快照的 Web 应用程序。
引言
我曾经很想知道如何制作一个网页,如果提供了另一个网页的 URL,就能截取该网页的快照。我为此搜索了很多,但最终只找到了一堆第三方组件。正是在这些页面上,我发现你的操作系统中实际上有一个内置的组件来处理网页浏览。而且,碰巧的是,这个组件作为 WebBrowser 控件被打包到你的 VS IDE (2005) 中;我的意思是,这个控件封装了这个组件提供的功能。
背景
这个项目可能与你之前做过的任何其他 Web 项目都不同。确切地说,它不仅仅是一个 Web 项目;它还是一个 Windows 应用程序项目。是的,你可能想知道为什么我们需要一个?拭目以待。
Windows 应用程序 (prjSnapShot)
这里是让我认为截取网页图像的过程是可能的链接。但是你需要进行这个项目并根据你的需要进行调整。这很容易理解。你所需要的只是一个停靠在 Windows Form 上的 WebBrowser 控件,然后是下面的代码让你开始。它几乎与我参考的项目相似,但我做了一些更改以适应我的需要。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Snapshot
{
//This is my windows form class
public partial class browserForm : Form
{
public browserForm()
{
InitializeComponent();
}
//private variables for properties
private string _URL;
private Bitmap docImg;
private bool DownloadingComplete;
//this property accepts a URL.
public string URL
{
get
{
return _URL;
}
set
{
_URL = value;
}
}
//function that fetches the image and return a System.Drawing.Image
//representation of it.
public Image GetSnapshot()
{
if (_URL == null)
throw new Exception("No input url given");
if (_URL.Contains("http://") == false)
throw new Exception("Invalid url input. No http prefix was found");
docImg = new Bitmap(this.Width, this.Height);
Control ctrl = wbCtrl;
wbCtrl.Navigate(_URL);
//blocking until downloading complete
while (!DownloadingComplete)
Application.DoEvents();
return System.Drawing.Image.FromHbitmap(docImg.GetHbitmap());
}
private void wbCtrl_DocumentCompleted
(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//Actual downloading done here.
//Conversion to image is also done here.
DownloadingComplete = true;
Debug.Print("Download Completed @ " + DateTime.Now.ToString());
docImg = new Bitmap(this.Width, this.Height);
Control ctrl = wbCtrl;
ctrl.DrawToBitmap(docImg, new Rectangle(wbCtrl.Location.X, wbCtrl.Location.Y,
wbCtrl.Width, wbCtrl.Height));
}
}
}
你可能需要运行这个项目几次;像我链接的文章中建议的那样,将其添加到另一个 Windows 项目中。整个过程的美妙之处在于,你实际上不会让这个表单可见!测试完成后,将项目转换为 DLL。我们将在下一个项目中添加它。
ASP.NET 项目
将上述 DLL 添加到此项目中。让我警告你,如果你试图在这个时候原样使用它,你可能会遇到很多问题。哦,顺便说一句,这个项目并没有“做”那么多。但是你必须了解一些概念。即 ASP.NET 引擎如何处理你的网页。这本身就是一个庞大的主题,但我只提几件事
- 你的网页是在多线程单元 (MTA) 模型上执行的。我猜 ASP.NET 以这种方式运行以优化网页的加载。网页所需的资源由启动处理的线程处理。你不需要深入研究这个问题。但是,忽略这个事实可能会触发你的 Web 应用程序的异常。
在这里,你必须意识到,我们已经将一个 Windows 项目添加到一个 ASP.NET 项目中。大部分控件,甚至整个表单本身都在单线程单元 (STA) 模型上运行。因此,你会收到一个错误,说明类似线程不是 STA 的内容。
为了克服这个障碍,你所要做的就是将网页的页面AspCompat
页面属性设置为true
。 ASP.NET 引擎将立即意识到必须在 STA 上处理此网页。事实上,我相信这过去是普通 ASP 页面被处理的方式。
下一个障碍是真正困扰你的东西。一切似乎都还好,但是你得到了一个奇怪的 COM 异常和一个看起来很奇怪的错误代码。有时,你第一次运行应用程序时一切顺利,但随后的每个请求都会抛出一个错误。搜索这个错误代码无济于事。你需要一些 COM 知识。但是,我不是这方面的专家,但我可以安全地告诉你,你必须告诉你的操作系统你已经完成了使用你的 COM 对象;否则,使用同一对象的其他应用程序可能会出现异常行为。因此,最终你在那里所见证的可能是 COM 没有被正确地取消引用。如果遇到这样的问题,请停止本地 Web 服务器(由 IDE 为你托管),然后重新启动它;在你的 IDE 中再次运行该项目。
Using the Code
我希望你已经理解了以上所有内容。现在使用代码就像这样简单
protected void btnGenerate_Click(object sender, EventArgs e)
{
browserForm frm = new browserForm();
frm.URL = txtURL.Text;
System.Drawing.Image snapshot;
snapshot = frm.GetSnapshot();
snapshot.Save(Server.MapPath("snap.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);
frm.Dispose();
Image1.ImageUrl = "snap.jpg";
}
哦,而且我的所有 Web 表单都只有一个文本框、一个按钮和一个图像控件。
我想知道的事情
我还没有在生产环境中进行过这个练习。我正在考虑,也许,代码需要一些调整。但是如果你想玩这个,那么你非常欢迎!
历史
哇,在编辑了十年之后,我发表了我的第一篇文章!