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.

RMalke
  • 4,048
  • 29
  • 42
  • 1
    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 https://googledotnet.codeplex.com/ – Karnivaurus Jan 08 '15 at 17:50
  • Thank you Karnivaurus. I will check it. –  Jan 08 '15 at 17:52
  • I could just see that bringing up some ... ummm ... "interesting" results, I wouldn't put it into a business application. :-P – Ads Nov 09 '17 at 22:45

2 Answers2

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);
}
Icemanind
  • 47,519
  • 50
  • 171
  • 296
  • 2
    @mafu - I agree! Haha – Icemanind Sep 01 '15 at 05:34
  • 1
    This is pretty cool. It would be better if could download the full quality image that you get when you click the thumbnail. – Julien Feb 16 '16 at 20:59
  • Is there a way to do it with full quality images? The small ones are so small that are hardly visible. – MadBoy Apr 26 '16 at 17:52
  • @Julien - I edited my answer to provide that functionality. – Icemanind Apr 26 '16 at 22:49
  • @MadBoy - I edited my answer to provide that functionality. – Icemanind Apr 26 '16 at 22:49
  • @Icemanind now that looks pretty :D Thank you. Sorry for late answer! – MadBoy May 02 '16 at 18:02
  • @Icemanind 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? – MadBoy May 03 '16 at 13:07
  • @MadBoy - Can you tell me the specific error message you are receiving? And, if possible, which topics you chose? – Icemanind May 03 '16 at 16:43
  • @Icemanind 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? – Just A Minnion Feb 23 '20 at 21:05
  • 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. – Fredy Nov 23 '22 at 09:03
  • 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); – Fredy Nov 23 '22 at 09:29
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;
            }
Jbjstam
  • 874
  • 6
  • 13