如何通过 Ruby 使用 Selenium 从复杂的网页中提取信息

How to extract information from a complex web page using Selenium via Ruby

提问人:Grant Sayer 提问时间:5/30/2023 更新时间:5/31/2023 访问量:60

问:

作为一个实验,我想测试如何使用 Ruby、Selenium 和 Web 驱动程序来访问一个复杂的网站。对于这个测试,我想我可以花 flights.google.com 时间,看看如何在页面上找到一些东西,快速浏览一下视觉上看起来很简单但生成的视图是复杂的动态性质。

似乎很容易。例如,站点 flights.google.com,输入两个目标点,比如 SFO 到 LAX,URL 将 https://www.google.com/travel/flights/search?tfs=CBwQAhogEgoyMDIzLTA2LTE0KABqBwgBEgNTRk9yBwgBEgNMQVgaIBIKMjAyMy0wNi0xOCgAagcIARIDTEFYcgcIARIDU0ZPQAFIAXABggELCP___________wGYAQE

现在,当页面生成时,您会得到一些漂亮的航班列表,如果我想找到一个结果,它不是一组可读的命名项目。

<div class="yR1fYc" jsaction="click:O1htCb;gP4E0b:O1htCb;DIjhEc:YmNhJf" jsname="BXUrOb">
<div class="mxvQLc ceis6c uj4xv uVdL1c A8qKrc" jsname="HSrbLb">…</div>
</div>

通常使用 Webdriver 和 Selenium,我会使用

require 'selenium-webdriver'
require 'capybara'

driver = Selenium::WebDriver.for :chrome
driver.get 'https://www.google.com/flights/'

然后将 Find Element 方法与一些命名元素一起使用

flights = driver.find_elements_by_class_name('flight')

在这种情况下,它是一个更神秘的名称,所以如果我假设类的名称可能是动态生成的,那么不确定如何解决这个问题。

有什么建议或方法吗?

Ruby Selenium-Web Web驱动程序

评论


答:

1赞 Amadan 5/30/2023 #1

您仍然可以依赖结构,因为结构不是随机的;像这样的 CSS 选择器应该能够为您提供结果的列表元素,而无需依赖类名:

body > c-wiz:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(2) >
c-wiz:nth-of-type(1) > div:nth-of-type(1) >
c-wiz:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(2) > div:nth-of-type(3) >
ul:nth-of-type(1) > li

评论

0赞 Greg 5/30/2023
我要补充一点,是的,DOM 结构不是随机的,但就像看起来随机的 CSS 类一样(用于使网络爬虫的生活变得困难)——DOM 结构也有望发生变化。这是一场猫捉老鼠的游戏。OP 应该准备好维护它(追逐更改),如果他计划抓取数据的时间比一次性实验更长。
1赞 Amadan 5/31/2023
@Greg 这绝对是一场猫捉老鼠的游戏。但是类 ID 在每次编译中都可能发生变化,即使修改了代码中完全不相关的部分;但只有当影响相关结构的代码逻辑发生变化时,结构才会发生变化。两者没有可比性,尽管两者都是黑客。
2赞 Todd A. Jacobs 5/31/2023 #2

TL的;博士

如果混淆是故意的并且不断发展,您可能无法永久解决您的问题。但是,对于不故意违反标准的网站,您可以遵循一些最佳实践。您可能只需要重新构建您的解决方案,使其在面对动态内容时不那么脆弱,并找出页面上没有更改的内容。

分析与建议

如果要处理动态生成的内容,则需要以下一项或多项:

  1. 一个驱动程序,可以为依赖 JavaScript 的网站呈现 JavaScript,但并非所有网站都这样做。
    • 您的 Chrome 驱动程序可以,但呈现方式可能与其他 JavaScript 驱动程序不同;可能值得尝试其他一些。
    • 如果 Google 故意使用 Chrome 的功能对网页进行混淆处理,那么使用其他 JavaScript 驱动程序或引擎可能会有所帮助。YMMV 与这个。
  2. 某种父子元素、 n 个元素或基于容器的搜索,以在不能依赖给定的类或 ID 名称时找到所需的内容。
  3. 如果您知道有可靠的前缀、后缀或其他基于字符串的逻辑来识别所需数据或 HTML 元素附近的文本,请愿意将您的方法更改为整页正则表达式或固定字符串搜索。
  4. 考虑针对仅 HTML 版本的网站(如果可用)进行测试。
    • 你可以用 felinks 或类似的东西进行测试,看看没有 JavaScript 的渲染效果。
    • 您可以在其屏幕阅读器或启用辅助功能的页面中搜索您尝试查找的内容。
    • 您可以查看它们是否支持 Web Accessibility Initiative、Accessible Rich Internet Applications、WAI-ARIA 或您可以正确解析的类似正常降级接口。
  5. 请考虑 API 访问。
    • 有时,当有 RESTful 或 GraphQL 选项可用时,网络抓取是解决数据检索问题的错误方法。
    • 例如,谷歌曾经提供谷歌航班搜索(GFS),但似乎已经停止了。我没有找到替代方案,但我只花了大约 30 秒试图找到一个。

例如,如果可以依赖给定容器中某个位置的“名字”之类的内容,则可以使用 XPath 表达式来查找父容器,然后从那里进行更结构化或更宽松的搜索。div

水豚非常强大,但有时你必须自己解析。如果发生这种情况,请查看 Nokogiri 提供的内容,看看即使您必须执行多个提取/搜索步骤才能完成它,您仍然可以做您想做的事。

并非所有东西都有单行作为解决方案。我想,那些旨在破坏标准工具(如机械化或基于CSS的解析器)的动态站点通常这样做是有原因的,尽管它经常破坏与标准的兼容性。假设他们没有故意破坏 ALT 文本或其他辅助功能属性等辅助功能,您可能会考虑利用这些或类似的辅助功能,因为商业网站通常需要满足 ADA 或第 508 节标准,无论它们滥用 DOM 的程度如何。