如何使用VBA查找给定search词的图像结果数量

我一直在从Excel中搞乱HTML,尝试近似不同分辨率的图像。 我希望得到一些dynamic的东西 – 用户input一个search词,代码循环一系列预定义的图像分辨率,对指定分辨率之间的search词的常见图像进行排名。

第一步是获得一个可靠(快速)的方式来返回特定分辨率的图像数量。 我写了这个代码:

Sub GoogleWithURL() 'requires Microsoft HTML Object Library Dim url As String, searchTerm As String Dim objIE As InternetExplorer 'special object variable representing the IE browser Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("sheet1") Dim currPage As HTMLDocument Dim xRes As Integer, yRes As Integer With ws xRes = .Range("XRes") yRes = .Range("YRes") searchTerm = .Range("search") End With 'create URL to page with these image criteria url = WorksheetFunction.Concat("https://www.google.com/search?q=", searchTerm, _ "&tbm=isch&source=lnt&tbs=isz:ex,iszw:", xRes, "iszh:", yRes) 'initiating a new instance of Internet Explorer and asigning it to objIE Set objIE = New InternetExplorer 'objIE.Visible = True 'for debugging purposes 'Google images search objIE.navigate url Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop Set currPage = objIE.document 'Count image results Set valueResult = currPage.getElementById("rg_s").getElementsByTagName("IMG") MsgBox WorksheetFunction.Concat("'", searchTerm, "' returns ", valueResult.Length _ , " images @ ", xRes, "x", yRes, "px.") 'returns number of loaded images on page 'close the browser On Error Resume Next 'required when the browser is visible and I close it manually half way objIE.Quit End Sub 

它导航一个Internet Explorer对象到一个特定的分辨率谷歌图片search,统计图像的数量在rg_s ID(这些图像结果而不是横幅图像等)。 然后它将这个计数作为消息框返回。 (当我最终实现这个时,我会返回表格中一列的值,循环30个不同的分辨率)

问题

这个代码的主要问题是:

  • 它没有给出一个非常有用的数字。 分辨率很低,因为它只计算已加载的图像 – 这意味着像1920×1080或1366×768这样的常见分辨率下的大多数search项会返回最多100个图像。

  • 这很慢。 对我来说,浏览页面,计数图像标签,这似乎很像在VBA中select。 这就像手动方法,人会做什么,因此效率低下。

解决scheme

我可以想一些办法来解决这些问题

  1. 解决数据/获得更有用的数量

    • 向下滚动。 如果我可以加载更多的图像,我可能会有更好的区分。 我发现,尽可能地滚动(可达“加载更多结果”button)的上限为400而不是100 – 如果给定的分辨率至less有很多图像,那么我很高兴,我会给它最高的排名。 虽然没有帮助问题2。 不过, 我该怎么做呢?

    • 缩小结果。 如果返回100,则可以更改我发送的URL中的filetype:如附加filetype:png ,可能会减less返回的图像数量,从而使我在0-100范围内传播更好。 不理想,因为我不得不迭代通过多个文件types的一些解决scheme,放慢代码,即使如此,不一定给我我想要的。

    • 使用谷歌(或其他search引擎)自己的价值观。 我已经在各种网站上以各种forms提出了这个问题, 有没有关于图像计数的任何数据可以直接从谷歌 – 即没有返回(和缓慢加载)图像本身。 就像普通searchabout 1,300,500 results in 0.03 secondsabout 1,300,500 results in 0.03 seconds一样,只能用于图像? 如果我每次使用一个预先计算的值来比100个结果更大的数组,我可能会得到更详细的图片。

  2. 缓慢

    • 尝试一种不同types的HTTP请求。 现在我打开一个Internet Explorer的实例,并导航到一个页面。 这听起来很人性化 ,我更喜欢电脑风格的要求。 我的意思是,不是用我的笔记本电脑一个接一个地浏览图片,而是让Google的超级计算机只做点数,而不是用图像本身来对付图像。 不知道如何做到这一点。 我知道另外两种方法可以在Excel中search网页; 网页查询和CreateObject("MSXML2.serverXMLHTTP") 。 不知道这些,但如果你认为他们会是一个更好的方式,那么我会更密切地关注他们。

概要

希望有很多事情可以继续下去,我认为我的思路应该是相当清楚的。 关于如何向下滚动/加载更多图像/让Google返回一个计数而不是图像本身的实际答案是最好的,关于什么追求的build议也是有用的。

你的瓶颈不在for循环中。 这是在打开一个浏览器,并将其指向一个位置。 如果您担心时间,那么您应该抓取一个已经打开的浏览器,而不是closures它,直到您运行了所有的search。 每次search应至less保存2秒。 我跑了下面的代码,得到这些时间:

打开并设置资源pipe理器的时间:2.41秒。

计时100张照片(1):0.1秒。

计时100张照片(2):0.11秒。

我们的方法之间的差异是1/100秒。

而且,Google图片要求用户下页以调用下一个100张图片。 如果你可以findajax或javascript语句来实现这一点,那么你将能够认为它有页面。 这就是为什么你只能得到100张图片。

或者你可以打开一个浏览器,键入你的search词,然后翻页,直到屏幕上有299个图像,当你find一个显示“显示更多图像”的button。 然后抓住打开的网页。

如果您正在运行几个search条件,而不是在打开和closures浏览器的时间瓶颈,而不是计算图像。

 Sub GoogleWithURL() 'requires Microsoft HTML Object Library ' https://www.google.com/search?q=St+Mary&source=lnms&tbm=isch&sa=X&ved=0ahUKEwj99ay14aPSAhWDMSYKHadiCjkQ_AUICSgC&biw=1600&bih=840 Dim url As String Dim objIE As InternetExplorer 'special object variable representing the IE browser Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("Sheet1") Dim currPage As HTMLDocument Dim StartTime As Double, SecondsElapsed As Double '**************************************** ' Hard code url to search images of St Mary url = "https://www.google.com/search?q=St+Mary&source=lnms&tbm=" & _ "isch&sa=X&ved=0ahUKEwj99ay14aPSAhWDMSYKHadiCjkQ_AUICSgC&biw=1600&bih=840" StartTime = Timer Set objIE = New InternetExplorer objIE.Visible = True objIE.navigate url Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop Set currPage = objIE.document SecondsElapsed = Round(Timer - StartTime, 2) Debug.Print "Time to open and set Explorer: " & SecondsElapsed & " seconds." StartTime = Timer Set valueResult = currPage.getElementById("rg_s").getElementsByTagName("IMG") For Each pic In valueResult counter = counter + 1 Next pic SecondsElapsed = Round(Timer - StartTime, 2) Debug.Print "Time to Count " & counter & " Photos(1): " & SecondsElapsed & " seconds." counter = 0 StartTime = Timer Set valueResult = currPage.getElementsByTagName("IMG") For Each pic In valueResult If InStr(1, pic.className, "rg") > 0 Then counter = counter + 1 End If Next pic SecondsElapsed = Round(Timer - StartTime, 2) Debug.Print "Time to Count " & counter & " Photos(2): " & SecondsElapsed & " seconds." On Error Resume Next 'required when the browser is visible and I close it manually half way objIE.Quit End Sub 

再过几个问题,现在感觉有点明智了,我为此做了一个UDF:

 Public Function GOOGLE_COUNT(searchTerm As String, xRes As Long, yRes As Long, Optional timeout As Long = 10) As Long Dim url As String Dim objIE As InternetExplorer Dim currPage As HTMLDocument Dim stTimer As Double, tElapsed As Single Dim valueResult As IHTMLElementCollection 'create URL to page with these image criteria url = "https://www.google.com/search?q=" & searchTerm & _ "&tbm=isch&source=lnt&tbs=isz:ex,iszw:" & xRes & ",iszh:" & yRes 'initiating a new instance of Internet Explorer and asigning it to objIE Set objIE = New InternetExplorer 'Google images search objIE.navigate url Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop Set currPage = objIE.document Dim myDiv As HTMLDivElement: Set myDiv = currPage.getElementById("fbar") Dim elemRect As IHTMLRect: Set elemRect = myDiv.getBoundingClientRect stTimer = Timer 'Scroll until bottom of page is in view Do Until elemRect.bottom > 0 Or tElapsed > timeout 'timeout after n seconds currPage.parentWindow.scrollBy 0, 10000 Set elemRect = myDiv.getBoundingClientRect tElapsed = Timer - stTimer Loop myDiv.ScrollIntoView 'Count the images Set valueResult = currPage.getElementById("rg_s").getElementsByTagName("IMG") GOOGLE_COUNT = valueResult.Length objIE.Quit End Function 

就这样工作:然后以1366:768的图片尺寸search“圣玛丽”

 =GOOGLE_COUNT("St. Mary", 1366, 768) 

或者10秒超时(如果经过了10秒,search停止滚动,只计算加载的图像)

 =GOOGLE_COUNT("St. Mary", 1366, 768, 10) 

我在另一个问题中解释了滚动工作如何,现在是混乱的,但function。

重要:

正如@John Muggins所指出的,重要的时间是在装载,不计算。 特别是打开和closuresInternetExplorer 。 所以要避免巨大的重新计算时间; 如果(像我一样)你想检查多个术语/决议, 把这个代码放在一个macros ,而不是一个函数(如果你认为我应该发布这个评论)。 这个UDF只用于一次性search

希望它是有用的,我想我应该重新访问这个问题,张贴我所得到的答案。

最后注意:

  1. 你的电脑(可能)没有崩溃,function只是计算。

  2. 对于search字词,input您要在Googlesearch栏中input的任何内容 – 例如“Jaguar -car”会返回动物的图片,而不是汽车公司

  3. 结果是0-400; 0-399是实际计数的图像数量(只要您设置超时时间足够大 – 自动为10秒)。 400是最大的,所以在这个分辨率下可能会有超过400个图像可用。