Захват веб -страницы как изображение в C#, обеспечивая видные элементы javaScript.
-
25-10-2019 - |
Вопрос
Я пытаюсь запечатлеть следующую страницу, используя стандартный код C# .NET. Я искал различные методы людей, большинство из которых включают в себя экземпляр объекта браузера и использование метода розыгрыша для растрового изображения. Однако никто из них не поднимает содержимое диаграммы на этой странице:
http://www.highcharts.com/demo/combo-dual-axes
Возможно, у JavaScript нет времени для запуска, но добавление Thread.sleep (x) не помогло.
Этот коммерческий компонент Правильно захватывает это, но я бы предпочел, чтобы не требовалась дополнительной зависимости в моем проекте и платить 150 долларов, когда другие решения ооочень близки!
Кто -нибудь обнаруживает, что их решение делает это правильно?
Решение
Вы, возможно, попробовали IECAPT. Анкет Я думаю, что это правильный путь. Я создал модифицированную версию и использую timer
вместо Thread.Sleep
Он захватывает ваш сайт, как и ожидалось.
------РЕДАКТИРОВАТЬ------
Вот уродливый источник. Просто добавьте ссылку на Microsoft HTML Object Library
.
И это использование:
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();
}
Файл1
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);
}
}
}
и файл2
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);
}
}
Другие советы
Thread.Sleep
Будет ли просто приостановить поток, в котором работает ваш веб -браузер - как вы ожидаете, что он будет что -нибудь отображать при приостановке? :)
Вместо этого вам нужно позволить потоке обрабатывать работу. Вы можете достичь этого с помощью комбинации Thread.Sleep(0)
а также Application.DoEvents()
, с чем -то вроде следующего:
DateTime finish = DateTime.Now.AddSeconds(3);
while (DateTime.Now < finish) {
Application.DoEvents();
Thread.Sleep(0);
}
@Lb, спасибо за помощь!
Просто к вашему сведению для тех, кто хочет запустить его в библиотеке классов, WebBrowrowser должен быть в одиночной резьбе, так что делайте что -то вроде этого:
var t = new Thread(InitAndDo); //InitAndDo would have your code creating the webbrowser object etc...
t.SetApartmentState(ApartmentState.STA);
t.Start();
Тогда Gotcha, после того, как вызов навигации будет выполнен, добавьте эту строку кода, чтобы вы получили завершенное навигационное событие:
web.Navigate(Url);
Application.Run();
Я создал пакет Nuget для этой целиhttps://github.com/dcumin39/renderhighcharts/wiki