以编程方式获取页面的屏幕截图
我正在编写一个专门的爬虫和parsing器供内部使用,而且我需要能够截取网页的截图,以便检查整个过程中使用的是什么颜色。 该程序将采取约十个url,并将其保存为位图图像。
从那里我计划使用LockBits为了创build图像中五个最常用的颜色的列表。 据我所知,这是获取网页内容的最简单方法,但是如果有更简单的方法,请使用您的build议。
无论如何,我打算使用ACA WebThumb ActiveX控件,直到看到价格标签。 我对C#也是相当新的,只用了几个月。 有没有解决我的问题,采取一个网页的截图,以提取配色scheme?
只需使用Websnapr或https://snapito.io/webshot-doc/ 。 你可以每月做10万张图片。 有一个小水印,不应该影响你的颜色(如果是这样,只是不考虑右下angular)。 额外的好处是他们有最受欢迎的urlcaching,所以你会得到非常快的响应时间。
您将需要使用HttpWebRequest来下载图像的二进制文件。 这是一个例子:
HttpWebRequest request = HttpWebRequest.Create("http://images.websnapr.com/?size=s&url=http%3A%2F%2Fwww.google.com") as HttpWebRequest; Bitmap bitmap; using (Stream stream = request.GetResponse().GetResponseStream()) { bitmap = new Bitmap(stream); } // now that you have a bitmap, you can do what you need to do...
我不隶属于ACA Systems。
一个快速和肮脏的方法将是使用WinForms WebBrowser控件并将其绘制到位图。 在独立的控制台应用程序中执行此操作有点棘手,因为您必须了解使用基本asynchronous编程模式时托pipeSTAThread控件的含义。 但是,这是一个概念的工作certificate,它将一个网页捕获到一个800×600的BMP文件:
namespace WebBrowserScreenshotSample { using System; using System.Drawing; using System.Drawing.Imaging; using System.Threading; using System.Windows.Forms; class Program { [STAThread] static void Main() { int width = 800; int height = 600; using (WebBrowser browser = new WebBrowser()) { browser.Width = width; browser.Height = height; browser.ScrollBarsEnabled = true; // This will be called when the page finishes loading browser.DocumentCompleted += Program.OnDocumentCompleted; browser.Navigate("https://stackoverflow.com/"); // This prevents the application from exiting until // Application.Exit is called Application.Run(); } } static void OnDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { // Now that the page is loaded, save it to a bitmap WebBrowser browser = (WebBrowser)sender; using (Graphics graphics = browser.CreateGraphics()) using (Bitmap bitmap = new Bitmap(browser.Width, browser.Height, graphics)) { Rectangle bounds = new Rectangle(0, 0, bitmap.Width, bitmap.Height); browser.DrawToBitmap(bitmap, bounds); bitmap.Save("screenshot.bmp", ImageFormat.Bmp); } // Instruct the application to exit Application.Exit(); } } }
要编译这个,创build一个新的控制台应用程序,并确保为System.Drawing
和System.Windows.Forms
添加程序集引用。
更新:我重写了代码,以避免使用哈希轮询WaitOne / DoEvents模式。 这个代码应该更贴近以下最佳实践。
更新2:您指出您要在Windows窗体应用程序中使用此。 在这种情况下,忘记dynamic创buildWebBrowser
控件。 你想要的是在你的窗体上创build一个WebBrowser
的隐藏(Visible = false)实例,并以上面显示的方式使用它。 这里是另一个示例,它显示了带有文本框( webAddressTextBox
),button( generateScreenshotButton
)和隐藏浏览器( webBrowser
)的表单的用户代码部分。 当我正在处理这个问题的时候,我发现了一个我以前没有处理过的特性 – 根据页面的性质,DocumentCompleted事件实际上可以被多次提升。 这个示例应该一般工作,你可以扩展它来做你想做的任何事情:
namespace WebBrowserScreenshotFormsSample { using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Windows.Forms; public partial class MainForm : Form { public MainForm() { this.InitializeComponent(); // Register for this event; we'll save the screenshot when it fires this.webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(this.OnDocumentCompleted); } private void OnClickGenerateScreenshot(object sender, EventArgs e) { // Disable button to prevent multiple concurrent operations this.generateScreenshotButton.Enabled = false; string webAddressString = this.webAddressTextBox.Text; Uri webAddress; if (Uri.TryCreate(webAddressString, UriKind.Absolute, out webAddress)) { this.webBrowser.Navigate(webAddress); } else { MessageBox.Show( "Please enter a valid URI.", "WebBrowser Screenshot Forms Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); // Re-enable button on error before returning this.generateScreenshotButton.Enabled = true; } } private void OnDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { // This event can be raised multiple times depending on how much of the // document has loaded, if there are multiple frames, etc. // We only want the final page result, so we do the following check: if (this.webBrowser.ReadyState == WebBrowserReadyState.Complete && e.Url == this.webBrowser.Url) { // Generate the file name here string screenshotFileName = Path.GetFullPath( "screenshot_" + DateTime.Now.Ticks + ".png"); this.SaveScreenshot(screenshotFileName); MessageBox.Show( "Screenshot saved to '" + screenshotFileName + "'.", "WebBrowser Screenshot Forms Sample", MessageBoxButtons.OK, MessageBoxIcon.Information); // Re-enable button before returning this.generateScreenshotButton.Enabled = true; } } private void SaveScreenshot(string fileName) { int width = this.webBrowser.Width; int height = this.webBrowser.Height; using (Graphics graphics = this.webBrowser.CreateGraphics()) using (Bitmap bitmap = new Bitmap(width, height, graphics)) { Rectangle bounds = new Rectangle(0, 0, width, height); this.webBrowser.DrawToBitmap(bitmap, bounds); bitmap.Save(fileName, ImageFormat.Png); } } } }
有一个伟大的基于Webkit的浏览器PhantomJS允许从命令行执行任何JavaScript。
从http://phantomjs.org/download.html安装它并从命令行执行以下示例脚本:;
./phantomjs ../examples/rasterize.js http://www.panoramio.com/photo/76188108 test.jpg
它将在JPEG文件中创build给定页面的屏幕截图。 这种方法的好处是,你不依赖任何外部提供商,并可以轻松自动化屏幕截图大量。
这个问题是旧的,但是,或者,您可以使用nuget包冰柜 。 它是免费的,使用最近的壁虎网页浏览器(支持HTML5和CSS3),并只站在一个DLL。
var screenshotJob = ScreenshotJobBuilder.Create("https://google.com") .SetBrowserSize(1366, 768) .SetCaptureZone(CaptureZone.FullPage) .SetTrigger(new WindowLoadTrigger()); System.Drawing.Image screenshot = screenshotJob.Freeze();
看看这个 。 这似乎是做你想要的,从技术上讲,它通过网页浏览器控制非常相似的方式来解决问题。 它似乎已经迎合了一系列参数传入,并且内置了良好的error handling。 唯一的缺点是它是一个外部进程(exe),你产卵,它创build一个物理文件,你会在稍后阅读。 从你的描述,你甚至考虑web服务,所以我不认为这是一个问题。
在解决关于如何同时处理多个问题的最新评论时,这将是完美的。 您可以同时产生3,4,5或更多进程的并行,或者在另一个捕获进程正在进行时,将颜色位分析为线程。
对于image processing,我最近遇到了Emgu ,没有用过它自己,但它似乎很迷人。 它声称速度很快,并且对包括像素颜色读取在内的graphics分析有很多支持。 如果我现在有任何graphics处理项目,我会尝试一下。
你也可以看看QT jambi http://qt.nokia.com/doc/qtjambi-4.4/html/com/trolltech/qt/qtjambi-index.html
他们有一个很好的基于webkit的浏览器的Java实现,你可以做一个简单的截图像做:
QPixmap pixmap; pixmap = QPixmap.grabWidget(browser); pixmap.save(writeTo, "png");
看看样品 – 他们有一个很好的浏览器演示。
我使用了WebBrowser,对于我来说这并不完美,特别是当需要等待JavaScript呈现完成时。 我尝试了一些Api(s),发现selenium , selenium最重要的是,它不需要STAThread,并可以在简单的控制台应用程序以及服务运行。
试一试 :
class Program { static void Main() { var driver = new FirefoxDriver(); driver.Navigate() .GoToUrl("http://stackoverflow.com/"); driver.GetScreenshot() .SaveAsFile("stackoverflow.jpg", ImageFormat.Jpeg); driver.Quit(); } }