web-dev-qa-db-fra.com

Obtenir par programme une capture d'écran d'une page

J'écris un robot d'exploration et un analyseur spécialisé pour un usage interne, et j'ai besoin de pouvoir prendre une capture d'écran d'une page Web afin de vérifier quelles couleurs sont utilisées partout. Le programme prendra une dizaine d'adresses Web et les enregistrera sous forme d'image bitmap.

À partir de là, je prévois d'utiliser des LockBits afin de créer une liste des cinq couleurs les plus utilisées dans l'image. À ma connaissance, c'est le moyen le plus simple d'obtenir les couleurs utilisées dans une page Web, mais s'il existe un moyen plus simple de le faire, n'hésitez pas à faire part de vos suggestions.

Quoi qu'il en soit, j'allais utiliser ACA WebThumb ActiveX Control jusqu'à ce que je voie l'étiquette de prix. Je suis également assez nouveau sur C #, ne l'utilisant que depuis quelques mois. Existe-t-il une solution à mon problème de capture d'écran d'une page Web afin d'extraire le jeu de couleurs?

48
Mike B

https://screenshotlayer.com/documentation est le seul service gratuit que je puisse trouver récemment ...

Vous devrez utiliser HttpWebRequest pour télécharger le binaire de l'image. Voir l'URL ci-dessus pour plus de détails.

HttpWebRequest request = HttpWebRequest.Create("https://[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...
25
jjxtra

Un moyen rapide et sale serait d'utiliser le contrôle WinForms WebBrowser et de le dessiner sur un bitmap. Faire cela dans une application console autonome est légèrement délicat car vous devez être conscient des implications de l'hébergement d'un contrôle STAThread tout en utilisant un modèle de programmation fondamentalement asynchrone. Mais voici une preuve de concept qui capture une page Web dans un fichier 800x600 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();
        }
    }
}

Pour compiler cela, créez une nouvelle application console et assurez-vous d'ajouter des références d'assembly pour System.Drawing et System.Windows.Forms.

MISE À JOUR: J'ai réécrit le code pour éviter d'avoir à utiliser le modèle de sondage hacky WaitOne/DoEvents. Ce code devrait être plus proche des meilleures pratiques suivantes.

MISE À JOUR 2: Vous indiquez que vous souhaitez l'utiliser dans une application Windows Forms. Dans ce cas, oubliez de créer dynamiquement le contrôle WebBrowser. Ce que vous voulez, c'est créer une instance cachée (Visible = false) d'un WebBrowser sur votre formulaire et l'utiliser comme je le montre ci-dessus. Voici un autre exemple qui montre la partie code utilisateur d'un formulaire avec une zone de texte (webAddressTextBox), un bouton (generateScreenshotButton) et un navigateur masqué (webBrowser). Pendant que j'y travaillais, j'ai découvert une particularité que je n'avais pas gérée auparavant - l'événement DocumentCompleted peut en fait être déclenché plusieurs fois selon la nature de la page. Cet exemple devrait fonctionner en général, et vous pouvez l'étendre pour faire ce que vous voulez:

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);
            }
        }
    }
}
30
bobbymcr

Cette question est ancienne mais vous pouvez également utiliser le paquet nuget Freezer . Il est gratuit, utilise un navigateur Web Gecko récent (prend en charge HTML5 et CSS3) et ne se trouve que dans une seule DLL.

var screenshotJob = ScreenshotJobBuilder.Create("https://google.com")
              .SetBrowserSize(1366, 768)
              .SetCaptureZone(CaptureZone.FullPage) 
              .SetTrigger(new WindowLoadTrigger()); 

 System.Drawing.Image screenshot = screenshotJob.Freeze();
21
Perfect28

Il existe un excellent navigateur basé sur Webkit PhantomJS qui permet d'exécuter n'importe quel JavaScript à partir de la ligne de commande.

Installez-le depuis http://phantomjs.org/download.html et exécutez l'exemple de script suivant à partir de la ligne de commande:

./phantomjs ../examples/rasterize.js http://www.panoramio.com/photo/76188108 test.jpg

Il créera une capture d'écran d'une page donnée dans un fichier JPEG. L'avantage de cette approche est que vous ne comptez sur aucun fournisseur externe et pouvez facilement automatiser la capture d'écran en grande quantité.

17
Maksym Kozlenko

J'ai utilisé WebBrowser et cela ne fonctionne pas parfaitement pour moi, surtout lorsque vous devez attendre le rendu JavaScript. J'ai essayé quelques Api et j'ai trouvé Selenium , la chose la plus importante à propos de Selenium est qu'elle ne nécessite pas STAThread et pourrait fonctionner dans une application console simple ainsi que dans les services.

essaie :

class Program
{
    static void Main()
    {
        var driver = new FirefoxDriver();

        driver.Navigate()
            .GoToUrl("http://stackoverflow.com/");

        driver.GetScreenshot()
            .SaveAsFile("stackoverflow.jpg", ImageFormat.Jpeg);

        driver.Quit();
    }
}
3
Soren

vous pouvez également consulter QT jambi http://qt.nokia.com/doc/qtjambi-4.4/html/com/trolltech/qt/qtjambi-index.html

ils ont un Nice webkit basé sur Java implémentation pour un navigateur où vous pouvez faire une capture d'écran simplement en faisant qqch comme:

    QPixmap pixmap;
    pixmap = QPixmap.grabWidget(browser);

    pixmap.save(writeTo, "png");

Jetez un oeil aux exemples - ils ont une belle démo webbrowser.

1
Marc

Vérifiez this out. Cela semble faire ce que vous vouliez et techniquement, cela aborde le problème de manière très similaire grâce au contrôle du navigateur Web. Il semble avoir pris en charge une gamme de paramètres à transmettre et également une bonne gestion des erreurs intégrée. Le seul inconvénient est que c'est un processus externe (exe) que vous générez et qu'il crée un fichier physique que vous lirez plus tard. D'après votre description, vous considérez même les services Web, donc je ne pense pas que ce soit un problème.

Pour résoudre votre dernier commentaire sur la façon de traiter plusieurs d'entre eux simultanément, ce sera parfait. Vous pouvez générer un parallèle de 3, 4, 5 processus ou plus à tout moment ou faire analyser le bit de couleur en tant que thread pendant qu'un autre processus de capture est en cours.

Pour le traitement d'image, j'ai récemment rencontré Emg , je ne l'ai pas utilisé moi-même mais cela semble fascinant. Il prétend être rapide et avoir beaucoup de support pour l'analyse graphique, y compris la lecture de la couleur des pixels. Si j'ai un projet de traitement graphique sous la main, je vais essayer.

1
Fadrian Sudaman