Select and Download random image from Google
Asked Answered
G

2

9

Is there any example how I can search and download a random image from google? Using a random search string?

I want to use this image as steganography image and I want it to be a random one.

I am using C# with Visual Studio 2012.

Glennaglennie answered 8/1, 2015 at 17:44 Comment(3)
Do you really want a random search string? e.g. HE8IHN96HV3? This would most likely return no matches from Google images. Instead, you could choose a random word from a dictionary, search for that, and then choose a random image from all the results. In order to actually achieve this in C#, have a look at the Google search API documentation at googledotnet.codeplex.comTaam
Thank you Karnivaurus. I will check it.Glennaglennie
I could just see that bringing up some ... ummm ... "interesting" results, I wouldn't put it into a business application. :-PVespid
S
40

You probably don't want a random search string. You probably want random topics. Here is some code to help you out. First, create a list of topics:

private readonly List<string> _topics = new List<string> {"dog", "car", "truck", "cat", "florida"};

Of course, you are free to change, add and remove as many topics as you wish. Next, we will create a function to retrieve the HTML code from a Google image search, randomly selecting one of our topics to search from:

private string GetHtmlCode()
{
    var rnd = new Random();

    int topic = rnd.Next(0, _topics.Count - 1);

    string url = "https://www.google.com/search?q=" + _topics[topic] + "&tbm=isch";
    string data = "";

    var request = (HttpWebRequest)WebRequest.Create(url);
    var response = (HttpWebResponse)request.GetResponse();

    using (Stream dataStream = response.GetResponseStream())
    {
        if (dataStream == null)
            return "";
        using (var sr = new StreamReader(dataStream))
        {
            data = sr.ReadToEnd();
        }
    }
    return data;
}

Once we have the HTML code, we need to parse out the img tags located underneath the images_table table and store the URL's of the images in a list:

private List<string> GetUrls(string html)
{
    var urls = new List<string>();
    int ndx = html.IndexOf("class=\"images_table\"", StringComparison.Ordinal);
    ndx = html.IndexOf("<img", ndx, StringComparison.Ordinal);

    while (ndx >= 0)
    {
        ndx = html.IndexOf("src=\"", ndx, StringComparison.Ordinal);
        ndx = ndx + 5;
        int ndx2 = html.IndexOf("\"", ndx, StringComparison.Ordinal);
        string url = html.Substring(ndx, ndx2 - ndx);
        urls.Add(url);
        ndx = html.IndexOf("<img", ndx, StringComparison.Ordinal);
    }
    return urls;
}

Our last function we need is to take an URL and have it download the image bytes into a byte array:

private byte[] GetImage(string url)
{
    var request = (HttpWebRequest)WebRequest.Create(url);
    var response = (HttpWebResponse)request.GetResponse();

    using (Stream dataStream = response.GetResponseStream())
    {
        if (dataStream == null)
            return null;
        using (var sr = new BinaryReader(dataStream))
        {
            byte[] bytes = sr.ReadBytes(100000);

            return bytes;
        }
    }

    return null;
}

Finally, we just need to tie it all together:

string html = GetHtmlCode();
List<string> urls = GetUrls(html);
var rnd = new Random();

int randomUrl = rnd.Next(0, urls.Count - 1);

string luckyUrl = urls[randomUrl];

byte[] image = GetImage(luckyUrl);
using (var ms = new MemoryStream(image))
{
    pictureBox1.Image = Image.FromStream(ms);
}

UPDATE

I've gotten a few requests about this answer asking that I modify it so it loads the actual full size image rather than the thumbnail. I have modified my original code so that it loads the full size images now instead of the thumbnails.

First, like before, create a list of topics:

private readonly List<string> _topics = new List<string> { "dog", "car", "truck", "cat", "florida" };

Of course you are free to change, add and remove as many topics as you wish. Next we will create a function to retrieve the HTML code from a Google image search, randomly selecting one of our topics to search from. GetHtmlCode() here is different from the GetHtmlCode() in the thumbnail version in that we must add an Accept and a UserAgent to the request or else Google won't give us the full size image URLs:

private string GetHtmlCode()
{
    var rnd = new Random();

    int topic = rnd.Next(0, _topics.Count - 1);

    string url = "https://www.google.com/search?q=" + _topics[topic] + "&tbm=isch";
    string data = "";

    var request = (HttpWebRequest)WebRequest.Create(url);
    request.Accept = "text/html, application/xhtml+xml, */*";
    request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";

    var response = (HttpWebResponse)request.GetResponse();

    using (Stream dataStream = response.GetResponseStream())
    {
        if (dataStream == null)
            return "";
        using (var sr = new StreamReader(dataStream))
        {
            data = sr.ReadToEnd();
        }
    }
    return data;
}

The GetUrls() method was also rewritten because the HTML code we get back now is different from the HTML code we got back in our "thumbnail" version. It still parses out the URLs from the HTML code:

private List<string> GetUrls(string html)
{
    var urls = new List<string>();

    int ndx = html.IndexOf("\"ou\"", StringComparison.Ordinal);

    while (ndx >= 0)
    {
        ndx = html.IndexOf("\"", ndx + 4, StringComparison.Ordinal);
        ndx++;
        int ndx2 = html.IndexOf("\"", ndx, StringComparison.Ordinal);
        string url = html.Substring(ndx, ndx2 - ndx);
        urls.Add(url);
        ndx = html.IndexOf("\"ou\"", ndx2, StringComparison.Ordinal);
    }
    return urls;
}

Our last function we need is to take an URL and have it download the image bytes into a byte array. There is only one minor change in this function that's different from the "thumbnail" version. We had to change the number in ReadBytes() since our images will be larger now:

private byte[] GetImage(string url)
{
    var request = (HttpWebRequest)WebRequest.Create(url);
    var response = (HttpWebResponse)request.GetResponse();

    using (Stream dataStream = response.GetResponseStream())
    {
        if (dataStream == null)
            return null;
        using (var sr = new BinaryReader(dataStream))
        {
            byte[] bytes = sr.ReadBytes(100000000);

            return bytes;
        }
    }

    return null;
}

Finally, we just need to tie it all together, like before:

string html = GetHtmlCode();
List<string> urls = GetUrls(html);
var rnd = new Random();

int randomUrl = rnd.Next(0, urls.Count - 1);

string luckyUrl = urls[randomUrl];

byte[] image = GetImage(luckyUrl);
using (var ms = new MemoryStream(image))
{
    pictureBox1.Image = Image.FromStream(ms);
}
Supernormal answered 8/1, 2015 at 18:41 Comment(11)
@mafu - I agree! HahaSupernormal
This is pretty cool. It would be better if could download the full quality image that you get when you click the thumbnail.Statolith
Is there a way to do it with full quality images? The small ones are so small that are hardly visible.Rumpf
@Statolith - I edited my answer to provide that functionality.Supernormal
@Rumpf - I edited my answer to provide that functionality.Supernormal
@Supernormal now that looks pretty :D Thank you. Sorry for late answer!Rumpf
@Supernormal I've tested it a bit and it sometimes crashes with GDI resources, and sometimes doesn't load the image. Do you know what could be the issue and how to make sure whole app doesn't crashes because of that?Rumpf
@Rumpf - Can you tell me the specific error message you are receiving? And, if possible, which topics you chose?Supernormal
@Supernormal Hello, HTML parsing is not my forte... About a month ago GetUrls method stopped working and I'm at a loss how to fix it. If you have the time, could you update the method? Or give some hints at what to look for?Girder
I couldn't make this work as is, the result page may have changed since. So, I replaced "class=\"images_table\"" of the first version by "table class=" and it works fine.Plenipotent
Also, nobody pointed out this bug: int topic = rnd.Next(0, _topics.Count - 1); will avoid the last element of the list because Random.Next(a,b) includes a and excludes b. Thus it would be: int topic = rnd.Next(0, _topics.Count);Plenipotent
A
1

Icemanind's answer mostly worked for me, though I had to rewrite Geturls:

    private List<string> GetUrls(string html)
    {
        var urls = new List<string>();

        string search = @",""ou"":""(.*?)"",";
        MatchCollection matches = Regex.Matches(html, search);

        foreach (Match match in matches)
        {
            urls.Add(match.Groups[1].Value);
        }

        return urls;
    }

I also had to find a WPF alternative to Image.FromStream (source):

            byte[] image = GetImage(luckyUrl);

            using (var stream = new MemoryStream(image))
            {
                var bitmap = new BitmapImage();
                bitmap.BeginInit();
                bitmap.StreamSource = stream;
                bitmap.CacheOption = BitmapCacheOption.OnLoad;
                bitmap.EndInit();
                bitmap.Freeze();

                this.img.Source = bitmap;
            }
Antiphon answered 30/9, 2015 at 7:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.