48 votes

Par programmation obtenir une capture d'écran d'une page

Je suis en train d'écrire un spécialisé robot d'indexation et analyseur pour un usage interne, et j'ai besoin de la capacité de prendre une capture d'écran d'une page web afin de vérifier de quelles couleurs sont utilisées tout au long de. Le programme prendra en autour de dix adresses web et les enregistrer en tant qu'image bitmap.

À partir de là, j'ai l'intention d'utiliser LockBits afin de créer une liste des cinq plus les couleurs utilisées dans l'image. À ma connaissance, c'est la façon la plus simple pour obtenir les couleurs utilisées à l'intérieur d'une page web, mais si il ya un moyen plus facile de le faire s'il vous plaît carillon avec vos suggestions.

De toute façon, j'allais à l'utilisation de l'ACA WebThumb Contrôle ActiveX jusqu'à ce que j'ai vu l'étiquette de prix. Je suis également assez nouveau pour C#, le fait d'avoir utilisé pendant quelques mois. Est-il une solution à mon problème de prendre une capture d'écran d'une page web afin d'en extraire le schéma de couleur?

31voto

bobbymcr Points 14916

Une façon rapide et sale serait d'utiliser les WinForms WebBrowser de contrôle et de dessiner une image bitmap. Faire cela dans un standalone application console est un peu difficile parce que vous devez être conscient des conséquences de l'hébergement d'un STAThread de contrôle lors de l'utilisation d'un fondamentalement la programmation asynchrone modèle. Mais ici, c'est un travail de preuve de concept qui capture d'une page web à une résolution de 800x600 fichier 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("http://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 hacky interrogation WaitOne/DoEvents modèle. Ce code doit être au plus près en suivant les meilleures pratiques.

Mise à JOUR 2: vous indiquez que Vous voulez l'utiliser dans une application Windows Forms. Dans ce cas, oubliez la création dynamique de l' WebBrowser contrôle. Ce que vous voulez est de créer un caché (Visible=false) exemple d'un WebBrowser sur votre formulaire et utiliser de la même façon que je montre ci-dessus. Voici un autre exemple qui montre à l'utilisateur partie du code d'un formulaire avec une zone de texte (webAddressTextBox), un bouton (generateScreenshotButton), et une cachée du navigateur (webBrowser). Alors que je travaillais sur ce, j'ai découvert une particularité que je n'ai pas manipuler avant d' -- le DocumentCompleted événement peut effectivement être soulevée à plusieurs reprises en fonction de la nature de la page. Cet exemple devrait 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);
            }
        }
    }
}

30voto

PsychoDad Points 7582

Utilisez simplement Websnapr. Vous pouvez faire 100 000 images / mois. Il y a un tout petit peu en filigrane qui ne devrait pas influencer vos couleurs (si il le fait, il suffit de ne pas prendre le coin en bas à droite en compte). L'avantage, c'est qu'ils ont le plus populaire Url de mise en cache, de sorte que vous obtiendrez des temps de réponse très rapides.

Vous aurez besoin d'utiliser HttpWebRequest pour télécharger le binaire de l'image. Voici un exemple:

    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...

Je ne suis pas affilié avec l'ACA Systèmes.

19voto

Maksym Kozlenko Points 4557

Il y a un grand navigateur basé sur Webkit PhantomJS qui permet d'exécuter le code JavaScript à partir de la ligne de commande.

L'installer à partir de http://phantomjs.org/download.html et exécuter l'exemple de script suivant à partir de la ligne de commande:

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

Il va créer une capture d'écran de la page donnée en fichier JPEG. L'avantage de cette approche est que vous n'avez pas à compter sur aucun fournisseur externe et peut facilement automatiser la capture d'écran prise en grandes quantités.

2voto

user1474090 Points 607

À l'aide d'un contrôle WebBrowser peut être très peu fiable, j'avais un vrai problème en essayant de faire des captures d'écran yahoo.com!

Il est probablement préférable d'utiliser un service tiers pour cela, vous n'avez pas à vous soucier des problèmes d'infrastructure. GrabzIt offre une belle ASP.NET API pour vous permettre de faire cela. En C#, vous pouvez utiliser quelque chose le long de ces lignes:

GrabzItClient grabzIt = GrabzItClient.Create("APPLICATION KEY", "APPLICATION SECRET");
string id = grabzIt.TakePicture("http://www.google.com");
bool completed = false;
int attempts = 0;
while (!completed && attempts <= 10)
{
     Image image = grabzIt.GetPicture(id);
     if (image != null)
     {
          string filename = url.Substring(url.IndexOf("://") + 3) + ".jpg";
          image.Save(filename);
          completed = true;           
     }
     attempts++;
     Thread.Sleep(1000);
     Application.DoEvents();
}

1voto

Fadrian Sudaman Points 4659

Vérifiez ceci dehors. Ce qui semble faire ce que tu voulais et techniquement, il aborde le problème de manière très semblable au travers de contrôle de navigateur web. Il semble avoir pris en compte une série de paramètres à transmettre et également une bonne gestion des erreurs construit en elle. Le seul inconvénient est que c'est un processus externe (exe) que vous frayer, et c'est de créer un fichier physique que vous lirez plus tard. À partir de votre description, vous pouvez même envisager de webservices, donc je ne pense pas que c'est un problème.

Dans la résolution de votre dernier commentaire sur la façon dont le processus de plusieurs d'entre eux simultanément, ce sera parfait. Vous pouvez frayer dire un parallèle de 3, 4, 5 ou plusieurs processus en même temps ou avoir l'analyse de la couleur de bit fonctionnant comme fil tandis qu'un autre processus de capture qui se passe.

Pour le traitement de l'image, j'ai récemment rencontré Emgu, nai pas utilisé moi-même, mais il semble fascinant. Il prétend être rapide et avoir beaucoup de soutien pour les graphiques de l'analyse, y compris la lecture de la couleur des pixels. Si j'ai tout traitement graphique du projet sur la main droite maintenant, je vais donner à ceci un essai.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X