网页内容如何检查是否已更改?

10

基本上,我正在尝试运行一些代码(Python 2.7),如果网站上的内容发生更改,就运行它,否则等待一会儿并稍后再检查。

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

那么...你会怎么做呢?您会查看HTML的Kb大小吗?您会查看字符串长度,并检查例如长度是否增加了5%,内容已经“更改”?还是有某种哈希算法,如果仅更改了字符串/内容的一小部分,则哈希值保持不变?

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


相关链接:http://stackoverflow.com/q/4618530 - Basilevs
你确定需要比较整个页面源代码而不是你期望更新的特定部分吗? - alecxe
我想要比较整个页面。 - Savad KP
不确定您的页面结构有多复杂。如果您关心要忽略某些文本,例如日期,那么在进行哈希之前,如何添加一些HTML标记,例如<div class="ignore_compare"></div>,然后将其删除,以便您可以获得更好的数据进行比较。 - thep
6个回答

4

没有通用解决方案。

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

2
如果您想制作一个可以应用于任意网站的工具,那么您仍然可以从为几个特定网站获取工具开始 - 反复下载它们并确定您想要忽略的确切差异,尝试以合理通用的方式处理问题而不忽略有意义的差异。这样的快速亲身体验应该会让您对面临的挑战有更具体的想法。无论您尝试什么解决方案,都要针对越来越多的网站进行测试,并在进行调整。

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

那非常粗糙,如果可能的话我会避免使用它。但是,您确实需要权衡错误地认为页面未更改与错误地认为页面已更改的成本。

还是有一种哈希算法,其中哈希值只有在字符串/内容的小部分发生更改时才保持不变?

可以创建这样的“哈希”,但很难调整灵敏度以检测文档中的有意义的更改。 无论如何,例如:您可以按文档中的字节值在256个可能的字节值中进行排序,并将其视为2k哈希:稍后可以执行“差异”以查看该字节值排序在后续下载中发生了多少变化。(为了节省内存,您可能只需要处理可打印的ASCII值,甚至只需标准化大写字母后的字母。)

另一种选择是为文档的不同部分生成一组哈希值:例如将其分成标题与正文,正文根据标题级别和段落划分,直到获得所需的粒度为止(例如30个切片)。然后,您可以说如果30个中只有2个切片发生了更改,则认为文档相同。

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

您还可以在自上次处理页面以来的时间增加时降低对更改的容忍度,这可能会减轻或限制错误地认为它未更改的“成本”。


2

最安全的解决方案:

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

优点:不依赖任何服务器头信息,可以检测到任何修改。
缺点:带宽使用太多。每次都需要下载所有内容。

使用Head

使用HEAD谓词请求页面并检查标头标记:

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

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

使用GET

使用GET谓词请求页面并使用条件标头标记: * If-Modified-Since:服务器将检查自从以下时间以来是否修改了资源,并返回内容或返回304 Not Modified

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

最后,也许将上述解决方案混合使用是实现此操作的最佳方法。


1
使用具有出色报告功能的git,它能够很好地报告两个文件状态之间发生了什么变化;此外,由于git管理增量,因此不会占用磁盘空间。

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

实际上,这归结为解析git diff -b --numstat HEAD HEAD^的输出;大致相当于“找到所有文件中已更改的内容(忽略任何空格更改),在当前状态和上一个状态之间”,将产生以下输出:

2       37      en/index.html

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

接下来,您需要进行一些实验,以找到您认为变化显著的“阈值”,以便进一步处理文件;这需要时间,因为您必须训练系统(您也可以自动化此部分,但那是另一个完全不同的主题)。

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


1
我希望这能有所帮助。
存储HTML文件 -- 两个版本..
一个是在一小时之前获取的HTML -- first.html
第二个是现在获取的HTML -- second.html
运行以下命令:
$ diff first.html second.html > diffs.txt

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

我认为这不是一个好主意。将大型HTML文件保存到我们的数据库中成本非常高昂。这就是为什么我在考虑哈希的原因。 - Savad KP
你能压缩文件并将文件路径存储在数据库中吗?这样做有帮助吗? - SuperNova
保存整个HTML文件(无论是否压缩)都比哈希值要大得多。我们可以非常容易地将文件转换为哈希。此外,我们可以轻松地存储和比较从哈希获得的十六进制值。 - Savad KP
你可以安全地假设现代网站上的HTML总是会变化,而最古老的网站则保留了If-modified-since。换句话说,在这里没有什么可以改进的。 - Basilevs
顺便说一下,你甚至不需要外部工具来完成这个任务。Python自带difflib库:https://docs.python.org/2.7/library/difflib.html - Martin Valgur
“将大型HTML文件保存到我们的数据库” <-- 这就是你的问题所在。除非你正在运行某种NLP类型的工作,否则你永远不想这样做 - 如果是这样,你会使用专为此类工作设计的数据库(例如couch或mongo)。由于你只关心更改,上述选项是一个不错的选择。 - Burhan Khalid

0

你应该执行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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接