【问题标题】:How to check if content of webpage has been changed?如何检查网页内容是否已更改?
【发布时间】:2023-04-10 05:13:02
【问题描述】:

基本上,如果网站上的内容发生变化,我会尝试运行一些代码(Python 2.7),否则请稍等片刻,稍后再检查。

我正在考虑比较哈希,问题是如果页面更改了单个字节或字符,哈希会有所不同。例如,如果页面在页面上显示当前日期,则每次哈希都会不同,并告诉我内容已更新。

那么...你会怎么做呢?您会查看 HTML 的 Kb 大小吗?您是否会查看字符串长度并检查例如长度是否已更改超过 5%,内容是否已“更改”?或者是否存在某种散列算法,如果仅更改了字符串/内容的一小部分,则散列保持不变?

关于last-modified - 不幸的是,并非所有服务器都正确返回此日期。我认为这不是可靠的解决方案。我认为更好的方法 - 结合哈希和内容长度解决方案。检查哈希,如果它改变了 - 检查字符串长度。

【问题讨论】:

  • 您确定需要比较完整的页面来源而不是您希望更新的特定部分吗?
  • 我想比较完整的页面。
  • 不确定您的页面结构有多复杂。如果您关心一些您想忽略的文本,例如日期,如果有一些像
    这样的 html 标签,然后在进行散列之前将其删除,这样您可能会有更多更好的数据比较。

标签: python-2.7 hash compare web-crawler


【解决方案1】:

最安全的解决方案:

下载内容并使用内容的SHA512 哈希创建哈希校验和,将其保存在数据库中并每次进行比较。

优点:您不依赖于任何服务器标头,并且会检测到任何修改。
缺点:过多的带宽使用。您每次都必须下载所有内容。

使用Head

使用HEAD动词请求页面并检查标题标签:

  • Last-Modified:服务器应提供上次生成或修改的页面。
  • ETag:由服务器定义的类似校验和的值,应在内容更改后立即更改。

优点: 更少的带宽使用和非常快速的更新。
缺点: 并非所有服务器都提供并遵守以下准则。如果您发现需要获取数据,则需要使用GET 请求获取真实资源

使用GET

使用GET 动词和条件标题标签请求页面: * If-Modified-Since:服务器将检查资源是否从以下时间修改并返回内容或返回304 Not Modified

优点: 仍然使用较少的带宽,单程接收数据。
缺点: 同样,并非所有资源都支持此标头。

最后,也许上述解决方案的混合是执行此类操作的最佳方式。

【讨论】:

    【解决方案2】:

    没有通用的解决方案。

    • 尽可能使用 If-modifed-since 或 HEAD(通常被动态页面忽略)
    • 尽可能使用 RSS。
    • 以特定于站点的方式提取最后修改标记(新闻网站有每篇文章的发布日期,可通过 XPATH 轻松提取)
    • 仅散列页面的有趣元素(构建特定于站点的模型),不包括易变部分
    • 散列整个内容(对动态页面无用)

    【讨论】:

      【解决方案3】:

      如果您正在尝试制作一个可以应用于任意网站的工具,那么您仍然可以先让它适用于一些特定的网站 - 反复下载它们并确定您想忽略的确切差异,尝试在不忽略有意义的差异的情况下合理地处理这些问题。如此快速的动手采样应该会让您对所面临的挑战有更具体的想法。无论您尝试何种解决方案,都要针对越来越多的网站对其进行测试,并随时进行调整。

      您会查看 HTML 的 Kb 大小吗?您是否会查看字符串长度并检查例如长度是否变化超过 5%,内容是否已“更改”?

      难以置信很粗糙,如果可能的话,我会避免这种情况。但是,您确实需要权衡误认为页面未更改与误认为页面更改的成本。

      或者是否存在某种散列算法,如果仅更改了字符串/内容的一小部分,则散列保持不变?

      可以进行这样的“散列”,但是很难调整对文档中有意义更改的敏感度。无论如何,作为一个例子:您可以按文档中的频率对 256 个可能的字节值进行排序,并考虑一个 2k 散列:您可以稍后执行“diff”以查看该字节值排序在以后的下载中发生了多少变化。 (为了节省内存,您可以只使用可打印的 ASCII 值,甚至在标准化大写后只使用字母)。

      另一种方法是为文档的不同切片生成一组哈希值:例如将其分为标题与正文,正文按标题级别然后段落,直到您至少获得所需的粒度级别(例如 30 个切片)。然后,您可以说,如果 30 中只有 2 个切片发生了变化,您将认为该文档是相同的。

      您也可以尝试在散列之前替换某些类型的内容 - 例如使用正则表达式匹配将时间替换为"<time>"

      您还可以做一些事情,例如随着您上次处理页面的时间增加而降低容差以进行更多更改,这可以减少或限制错误地认为它没有变化的“成本”。

      【讨论】:

        【解决方案4】:

        希望这会有所帮助。

        存储 html 文件 -- 两个版本..

        一个是一个小时前拍摄的html。 -- first.html

        second 是现在获取的 html -- second.html

        运行命令:

        $ diff first.html second.html > diffs.txt
        

        如果差异有一些文本,则文件已更改。

        【讨论】:

        • 我认为这不是一个好主意。将大型 html 文件保存到我们的数据库非常昂贵。这就是为什么我在考虑哈希
        • 你可以压缩文件然后将文件的路径存储在数据库中吗?这会有帮助吗?
        • 保存整个 html 文件(压缩或不压缩)远大于 hash 值。我们可以很容易地将文件转换为 hash。我们还可以轻松存储和比较从 hash 获得的十六进制值。
        • 您可以放心地假设 HTML 在现代网站上总是会发生变化,而最古老的网站会保留 If-modifed-since。换句话说,这里没有什么可以改进的。
        • 顺便说一句,您甚至不需要为此使用外部工具。 Python有difflib:docs.python.org/2.7/library/difflib.html
        【解决方案5】:

        使用git,它对文件的两种状态之间的变化具有出色的报告功能;另外,您不会因为 git 为您管理增量而占用磁盘空间。

        您甚至可以告诉 git 忽略“微不足道”的更改,例如添加和删除空白字符以进一步优化搜索。

        实际上这归结为解析git diff -b --numstat HEAD HEAD^ 的输出;大致翻译为“找出所有文件中发生的变化,忽略当前状态和先前状态之间的任何空白变化”;这将导致如下输出:

        2       37      en/index.html
        

        en/index.html进行了2次插入,37次删除

        接下来,您必须进行一些实验以找到一个“阈值”,在该阈值上您会认为更改很重要,以便进一步处理文件;这需要时间,因为您必须训练系统(您也可以自动化这部分,但这是另一个主题)。

        除非您有充分的理由这样做,否则不要将传统的关系数据库用作文件系统。让操作系统处理文件,这是它非常擅长的(关系数据库不是为了管理而设计的)。

        【讨论】:

          【解决方案6】:

          您应该发出 HTTP HEAD 请求(这样您就不会下载文件)并查看响应中的“Last-modified”标头。

          import requests
          
          response = requests.head(url)
          datetime_str = response.headers["last-modified"]
          

          并继续检查该字段是否在 while 循环中更改并比较日期时间差异。

          我在 Python 上做了一个小程序来做到这一点:

          https://github.com/javierdechile/check_updates_http

          【讨论】:

            猜你喜欢
            • 2012-05-04
            • 1970-01-01
            • 1970-01-01
            • 2013-02-22
            • 2019-05-11
            • 2011-04-08
            • 2011-10-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多