Программно получить скриншот страницы
Я пишу специализированный сканер и синтаксический анализатор для внутреннего использования, и мне требуется возможность сделать снимок экрана веб-страницы, чтобы проверить, какие цвета используются повсеместно. Программа займет около десяти веб-адресов и сохранит их в виде растрового изображения.
Оттуда я планирую использовать LockBits, чтобы создать список пяти наиболее используемых цветов в изображении. Насколько мне известно, это самый простой способ получить цвета, используемые на веб-странице, но если есть более простой способ сделать это, пожалуйста, поделитесь своими предложениями.
В любом случае, я собирался использовать ACA WebThumb ActiveX Control, пока не увидел ценник. Я также довольно новичок в C#, использовав его всего несколько месяцев. Есть ли решение моей проблемы сделать скриншот веб-страницы, чтобы извлечь цветовую схему?
7 ответов
https://www.url2png.com/docs - хороший вариант. У них есть свободный уровень.
Вам нужно будет использовать HttpWebRequest, чтобы загрузить двоичный файл изображения. Вот пример:
HttpWebRequest request = HttpWebRequest.Create("https://api.url2png.com/v6/[API_KEY]/[API_TOKEN]/png/?url=[URL]") 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...
Для генерации URL...
public static string url2png(string UrlToSite)
{
string url2pngAPIKey = "PXXX";
string url2pngPrivateKey = "SXXX";
string url = HttpUtility.UrlEncode(UrlToSite);
string getstring = "fullpage=true&url=" + url;
string SecurityHash_url2png = Md5HashPHPCompliant(url2pngPrivateKey + "+" + getstring).ToLower();
var url2pngLink = "http://api.url2png.com/v6/" + url2pngAPIKey + "/" + SecurityHash_url2png + "/" + "png/?" + getstring;
return url2pngLink;
}
public static string Md5HashPHPCompliant(string pass)
{
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] dataMd5 = md5.ComputeHash(Encoding.UTF8.GetBytes(pass));
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= dataMd5.Length - 1; i++)
{
sb.AppendFormat("{0:x2}", dataMd5[i]);
}
return sb.ToString();
}
Быстрый и грязный способ - использовать элемент управления WinForms WebBrowser и вывести его на растровое изображение. Делать это в автономном консольном приложении немного сложно, потому что вы должны знать о последствиях размещения элемента управления STAThread при использовании принципиально асинхронного шаблона программирования. Но вот рабочее доказательство концепции, которая записывает веб-страницу в файл BMP 800x600:
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://stackru.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();
}
}
}
Чтобы скомпилировать это, создайте новое консольное приложение и обязательно добавьте ссылки на сборки для System.Drawing
а также System.Windows.Forms
,
ОБНОВЛЕНИЕ: я переписал код, чтобы избежать необходимости использовать шаблон хакерского опроса WaitOne/DoEvents. Этот код должен быть ближе к следующим лучшим практикам.
ОБНОВЛЕНИЕ 2: Вы указываете, что хотите использовать это в приложении Windows Forms. В этом случае забудьте о динамическом создании WebBrowser
контроль. Вам нужно создать скрытый (Visible=false) экземпляр WebBrowser
и используйте его так же, как показано выше. Вот еще один пример, который показывает часть кода пользователя формы с текстовым полем (webAddressTextBox
), кнопка (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);
}
}
}
}
Этот вопрос старый, но, в качестве альтернативы, вы можете использовать пакет nuget Freezer. Это бесплатно, использует недавний веб-браузер Gecko (поддерживает 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();
Существует отличный браузер на основе Webkit PhantomJS, который позволяет выполнять любой JavaScript из командной строки.
Установите его с сайта http://phantomjs.org/download.html и выполните следующий пример сценария из командной строки:
./phantomjs ../examples/rasterize.js http://www.panoramio.com/photo/76188108 test.jpg
Это создаст скриншот данной страницы в файле JPEG. Плюсом этого подхода является то, что вы не полагаетесь на какого-либо внешнего поставщика и можете легко автоматизировать создание снимков экрана в больших количествах.
Я использовал WebBrowser, и он не работает идеально для меня, особенно когда нужно дождаться завершения рендеринга JavaScript. Я попробовал некоторые API-интерфейсы и обнаружил Selenium, самая важная вещь о Selenium - он не требует STAThread и может работать как в простом консольном приложении, так и в службах.
попробуй:
class Program
{
static void Main()
{
var driver = new FirefoxDriver();
driver.Navigate()
.GoToUrl("http://stackru.com/");
driver.GetScreenshot()
.SaveAsFile("stackru.jpg", ImageFormat.Jpeg);
driver.Quit();
}
}
Проверьте это. Это, кажется, делает то, что вы хотели, и технически это очень похоже на проблему через управление через веб-браузер. Кажется, он учитывает диапазон передаваемых параметров, а также встроенную в него хорошую обработку ошибок. Единственным недостатком является то, что это внешний процесс (exe), который вы порождаете, и он создает физический файл, который вы будете читать позже. Из вашего описания вы даже рассматриваете веб-сервисы, поэтому я не думаю, что это проблема.
В решении вашего последнего комментария о том, как обрабатывать несколько из них одновременно, это будет идеально. Вы можете вызвать параллель из 3, 4, 5 или более процессов одновременно или выполнить анализ цветового бита, выполняемого как нить, пока происходит другой процесс захвата.
Для обработки изображений я недавно натолкнулся на Эмгу, сам не использовал его, но это кажется захватывающим. Он претендует на скорость и имеет большую поддержку графического анализа, включая чтение цвета пикселей. Если у меня сейчас есть какой-нибудь проект по обработке графики, я попробую.
Вы также можете взглянуть на QT jambi http://qt.nokia.com/doc/qtjambi-4.4/html/com/trolltech/qt/qtjambi-index.html
у них есть хорошая реализация java на основе webkit для браузера, где вы можете сделать скриншот, просто выполнив sth:
QPixmap pixmap;
pixmap = QPixmap.grabWidget(browser);
pixmap.save(writeTo, "png");
Посмотрите на образцы - у них есть хорошая демонстрация веб-браузера.