【问题标题】:How do I find the elements in a dynamic webpage with Selenium in VBA?如何在 VBA 中使用 Selenium 在动态网页中查找元素?
【发布时间】:2021-05-12 10:04:21
【问题描述】:

我正在尝试使用 VBA 中的 Selenium 浏览此网页:https://www.familysearch.org/search/collection/1401638/。我使用 Chrome 作为浏览器并检查以查看页面中的元素。我不熟悉 javascript,但我是 VBA 专家。我可以浏览页面上看似静态的元素,例如单击右上角的登录按钮。但是我还没有弄清楚如何与具有标签 Search Collection 的中心的表单进行交互。

这是我目前的代码:

Sub WebScraper()
    Dim FSBrowser As New WebDriver
    Dim FSWebElements As WebElements

    FSBrowser.Start "chrome", "https://www.familysearch.org/search"
    FSBrowser.Get "/collection/1401638/"        ' United States Census, 1850
    
    FSBrowser.FindElementById("signInLink").Click
    
    'FSBrowser.FindElementById("userName").SendKeys ("xxxx")
    'FSBrowser.FindElementById("password").SendKeys ("xxxx")
    'FSBrowser.FindElementById("login").Click

    FSBrowser.Quit
End Sub

我想在出生地文本框中输入“弗吉尼亚”,然后点击搜索。

在 Inspect 中呈现的完整 HTML 代码真的很长,因为有相当多的表单元素。这是来自 javascript 和两个元素的表单信息:

<fs-search-form mobile-breakpoint="500">
<form id="form" method="get" class="search-form " action="/search/record/results">
<input type="text" class="fs-field-group__input" name="birthLikePlace" id="birthLikePlace">
<button type="submit" class="fs-button fs-button--recommended">Search</button>

这似乎是一项简单的任务,但我显然遗漏了一些东西。有人可以告诉我那是什么吗?看起来通过名称或birthLikePlace 的 Id 查找元素会起作用,但它不起作用。

编辑: 似乎 shadow-root 在这个问题上发挥了重要作用。它被标记为打开,但我怀疑还有更多我没有看到的内容。以下是birthLikePlace 的完整部分:

<sf-search-field-group field-list="[&quot;birthLikePlace&quot;, &quot;birthLikeDate&quot;]" trigger-id="birth">
   #shadow-root (open)
      <style> ... </style>
      <div class="field-section" visible="">
         <h2 class="section-header fs-h5">KEY: null (en)</h2>
         <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
         <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
         <div class="trigger-group shown active flexible-container" for="birth">
            <legend role="button" class="closer " for="birth" aria-label="Hide search fields for birth"> </legend>
            <slot></slot> </div> </div>
   <sf-search-field field-id="birthLikePlace" field-type="place">
      #shadow-root (open)
         <style> ... </style>
         <span class="field" visible="" field-id="birthLikePlace">
            <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
            <span class="event-place flex-item">
               <label for="birthLikePlace_place">Birthplace</label>
               <span class="fs-field-group">
                  <input type="text" class="fs-field-group__input" name="birthLikePlace" id="birthLikePlace">
                  <span class="fs-field-group__attachment fs-tooltip">
                     <span class="fs-tooltip__trigger">
                        <input type="checkbox" name="birthLikePlace.exact" id="birthLikePlaceexact">
                        <label aria-label="Match birthplace exactly" for="birthLikePlaceexact"></label> </span>
                     <span class="fs-tooltip__body" role="tooltip">::before Match birthplace exactly ::after</span> </span> </span> </span>
               <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
               <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
               <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
               <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
               <dom-if style="display: none;"><template is="dom-if"></template></dom-if>
               <dom-if style="display: none;"><template is="dom-if"></template></dom-if> 
         </span>
   </sf-search-field>
   <sf-search-field field-id="birthLikeDate" field-type="year"> ... </sf-search-field>
</sf-search-field-group>

【问题讨论】:

  • 乍一看,您似乎可以使用发出 post 请求的 xmlhttp requests 方法登录到该站点。你试过了吗?
  • 我想先尝试使用 Selenium,因为我想使用 Chrome 作为浏览器而不是 Internet Explorer。 xmlhttp 会是完成这项任务的更好方法吗?
  • Selenium 绝对是比 IE 更好的选择。 Xmlhttp requests 方法始终是最好的方法,如果你能以正确的方式处理它并且你希望抓取的内容不是高度动态的意味着 javascript 加密。
  • 这里的请求只是开始的地方,所以我可以理解我在哪里遗漏了一些东西。一旦我弄清楚了基础知识,我就会计划更多。该网站基本上都是用 javascript 编写的并且是完全动态的。
  • 如果您想在登录后在出生地文本框中输入文本,您想为脚本定义一个显式超时以等待该框可用,例如Set obirthPlace = FSBrowser.FindElementById("birthLikePlace", timeout:=10000): obirthPlace.SendKeys "virginia"

标签: excel vba selenium web-scraping


【解决方案1】:

假设 HTML 与您显示的一样,然后 SendKeys 使用出生地的 id 输入,然后按类定位相邻按钮

FSBrowser.FindElementById("birthLikePlace").SendKeys "Virginia"
FSBrowser.FindElementByCss("#birthLikePlace + fs-button").Click

如果 HTML 在您提供的示例中显示的方式不平坦,您可能需要使用更独特的类,例如

FSBrowser.FindElementByCss(".fs-button--recommended").Click

或者也许是一个属性

FSBrowser.FindElementByCss("[type=submit]").Click

真正取决于第一个匹配项的位置是必需的。无法从小的 html 示例中看出这就是为什么我最初使用锚定到 id 的选择器(希望是唯一的 id)。

【讨论】:

  • 这两行都不起作用。我确实直接从检查窗口中复制了元素。但我猜有些东西我不知道要包括在内。
  • 请描述什么不起作用?错误信息?是否有父 iframe/frame 可以协商?更长的等待时间有帮助吗?
  • 对于文本框建议的所有内容,我收到错误 NoSuchElementError, Element not found for Id =birthLikePlace。除了最后一个建议外,按钮基本上是相同的错误。 FSBrowser.FindElementByCss("[type=submit]").Click 得到一个错误,指出 ElementNotVisibleError,元素不可交互。似乎 css 找到了一些东西,但可能不是我要查找的元素,因为我需要的搜索框是可见的。
  • 这些元素是否在父 iframe/frame 中?
  • 我认为没有 iframe 或框架。我已经更新了问题,为一个部分提供了完整的代码集。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-25
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
相关资源
最近更新 更多