pagina - Captura de página web como imagen en c#, asegurando que los elementos renderizados de JavaScript sean visibles
full page screen capture (4)
Thread.Sleep
simplemente suspenderá el hilo en el que se ejecuta su navegador web, ¿cómo espera que muestre algo cuando se suspende? :)
En cambio, debe permitir que el hilo procese el trabajo. Puede lograr esto con una combinación de Thread.Sleep(0)
y Application.DoEvents()
, con algo como lo siguiente:
DateTime finish = DateTime.Now.AddSeconds(3);
while (DateTime.Now < finish) {
Application.DoEvents();
Thread.Sleep(0);
}
Estoy tratando de capturar la siguiente página usando el código c .net estándar. He buscado los diversos métodos de la gente, la mayoría de los cuales implican crear instancias de un objeto del navegador y usar un método de dibujar a mapa de bits. Sin embargo, ninguno de estos recoge el contenido del cuadro en esta página:
http://www.highcharts.com/demo/combo-dual-axes
Quizás el javascript no tenga tiempo para ejecutarse, pero agregar Thread.Sleep (x) no ha ayudado.
Este componente comercial lo captura correctamente, pero prefiero evitar una dependencia adicional en mi proyecto y pagar $ 150 cuando las otras soluciones son tan cercanas.
¿Alguien encuentra que su solución lo procesa correctamente?
Probablemente hayas probado IECapt . Creo que es el camino correcto a seguir. Creé una versión modificada y uso un timer
lugar de Thread.Sleep
captura su sitio como se esperaba.
------EDITAR------
Aquí está la fuente fea. Simplemente agregue una referencia a la Microsoft HTML Object Library
.
Y este es el uso:
HtmlCapture capture = new HtmlCapture(@"c:/temp/myimg.png");
capture.HtmlImageCapture += new HtmlCapture.HtmlCaptureEvent(capture_HtmlImageCapture);
capture.Create("http://www.highcharts.com/demo/combo-dual-axes");
void capture_HtmlImageCapture(object sender, Uri url)
{
this.Close();
}
Archivo1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace MyIECapt
{
public class HtmlCapture
{
private WebBrowser web;
private Timer tready;
private Rectangle screen;
private Size? imgsize = null;
//an event that triggers when the html document is captured
public delegate void HtmlCaptureEvent(object sender, Uri url);
public event HtmlCaptureEvent HtmlImageCapture;
string fileName = "";
//class constructor
public HtmlCapture(string fileName)
{
this.fileName = fileName;
//initialise the webbrowser and the timer
web = new WebBrowser();
tready = new Timer();
tready.Interval = 2000;
screen = Screen.PrimaryScreen.Bounds;
//set the webbrowser width and hight
web.Width = 1024; //screen.Width;
web.Height = 768; // screen.Height;
//suppress script errors and hide scroll bars
web.ScriptErrorsSuppressed = true;
web.ScrollBarsEnabled = false;
//attached events
web.Navigating +=
new WebBrowserNavigatingEventHandler(web_Navigating);
web.DocumentCompleted += new
WebBrowserDocumentCompletedEventHandler(web_DocumentCompleted);
tready.Tick += new EventHandler(tready_Tick);
}
public void Create(string url)
{
imgsize = null;
web.Navigate(url);
}
public void Create(string url, Size imgsz)
{
this.imgsize = imgsz;
web.Navigate(url);
}
void web_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
//start the timer
tready.Start();
}
void web_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
//stop the timer
tready.Stop();
}
void tready_Tick(object sender, EventArgs e)
{
try
{
//stop the timer
tready.Stop();
mshtml.IHTMLDocument2 docs2 = (mshtml.IHTMLDocument2)web.Document.DomDocument;
mshtml.IHTMLDocument3 docs3 = (mshtml.IHTMLDocument3)web.Document.DomDocument;
mshtml.IHTMLElement2 body2 = (mshtml.IHTMLElement2)docs2.body;
mshtml.IHTMLElement2 root2 = (mshtml.IHTMLElement2)docs3.documentElement;
// Determine dimensions for the image; we could add minWidth here
// to ensure that we get closer to the minimal width (the width
// computed might be a few pixels less than what we want).
int width = Math.Max(body2.scrollWidth, root2.scrollWidth);
int height = Math.Max(root2.scrollHeight, body2.scrollHeight);
//get the size of the document''s body
Rectangle docRectangle = new Rectangle(0, 0, width, height);
web.Width = docRectangle.Width;
web.Height = docRectangle.Height;
//if the imgsize is null, the size of the image will
//be the same as the size of webbrowser object
//otherwise set the image size to imgsize
Rectangle imgRectangle;
if (imgsize == null) imgRectangle = docRectangle;
else imgRectangle = new Rectangle() { Location = new Point(0, 0), Size = imgsize.Value };
//create a bitmap object
Bitmap bitmap = new Bitmap(imgRectangle.Width, imgRectangle.Height);
//get the viewobject of the WebBrowser
IViewObject ivo = web.Document.DomDocument as IViewObject;
using (Graphics g = Graphics.FromImage(bitmap))
{
//get the handle to the device context and draw
IntPtr hdc = g.GetHdc();
ivo.Draw(1, -1, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, hdc, ref imgRectangle,
ref docRectangle, IntPtr.Zero, 0);
g.ReleaseHdc(hdc);
}
//invoke the HtmlImageCapture event
bitmap.Save(fileName);
bitmap.Dispose();
}
catch
{
//System.Diagnostics.Process.GetCurrentProcess().Kill();
}
if(HtmlImageCapture!=null) HtmlImageCapture(this, web.Url);
}
}
}
y File2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
namespace MyIECapt
{
[ComVisible(true), ComImport()]
[GuidAttribute("0000010d-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IViewObject
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Draw(
[MarshalAs(UnmanagedType.U4)] UInt32 dwDrawAspect,
int lindex,
IntPtr pvAspect,
[In] IntPtr ptd,
IntPtr hdcTargetDev,
IntPtr hdcDraw,
[MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcBounds,
[MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcWBounds,
IntPtr pfnContinue,
[MarshalAs(UnmanagedType.U4)] UInt32 dwContinue);
[PreserveSig]
int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
int lindex, IntPtr pvAspect, [In] IntPtr ptd,
IntPtr hicTargetDev, [Out] IntPtr ppColorSet);
[PreserveSig]
int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
[PreserveSig]
int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
}
}
@LB, gracias por la ayuda!
Solo un FYI para cualquiera que desee ejecutarlo en una biblioteca de clases, WebBrowser necesita Single Single Threaded Apartment, así que haga algo como esto:
var t = new Thread(InitAndDo); //InitAndDo would have your code creating the webbrowser object etc...
t.SetApartmentState(ApartmentState.STA);
t.Start();
Luego, el Gotcha, después de finalizar la llamada de navegación, agregue esta línea de código para que pueda obtener el evento de navegación completo:
web.Navigate(Url);
Application.Run();
Creé un paquete nuget para este propósito https://github.com/dcumin39/RenderHighCharts/wiki