新闻汇总(1):初次实现

2019-07-26 16:57:15 浏览数 (1)

网上充斥着形式多样的新闻源,包括报纸、视频频道、博客、播客等。有些新闻院还提供诸如RSS和Atom feed等服务,让你使用相对简单的代码就能获取最新的新闻,而无需对网页进行解析。在这个项目中,我们将探索一种比Web更早面世的机制:网络新闻传输协议(Network News Transfer Protocol,NNTP)。我们将首先创建一个没有任何抽象(没有函数、没有类)的原型,在创建一个包含重要抽象的通用系统。为此,我们将使用能够让你与NNTP服务器交互的nntplib库,但添加其他协议和机制应该很简单。

NNTP是一种标准网络协议,用于管理在Usenet讨论组中发布的消息。NNTP服务器组成了一个统一管理新闻组的全局网络,通过NNTP客户端(也称为新闻阅读器)可发布和阅读消息。NNTP服务器组成的主网络称为Usenet,创建于1980年(但NNTP协议到1985年才开始使用)。相比于最新的Web潮流,这算是一种很古老的技术了,但从某种程度上说,互联网的很大一部分都基于这样的古老技术,而且尝试这些低级技术没什么不好。另外,随时都可将项目使用的NNTP替换为你自己开发的新闻收集模块,如可能转而使用Facebook或Twitter等社交网站提供的Web API。

1.问题描述

现在要编写的程序是一个信息收集代理,能够替你收集信息(具体地说是新闻)并生成新闻汇总。基于你对网络功能的了解,这好像不太难——确实不难,但在这个项目中,需要做的并非仅仅使用urllib下载文件,你将使用另一个网络库,即nntplib,它使用起来要难些。另外,你还需重构程序以支持不同的新闻源和目的地,进而在中间层使用主引擎将前端和后端分开。

最终的程序要实现的主要目标如下。

  • 能够从众多不同的新闻源收集新闻。
  • 可轻松地添加新闻源(乃至不同类型的新闻源)。
  • 能够以众多不同的格式将生成的新闻汇编分发到众多不同的目的地。
  • 能够轻松地添加新的目的地(乃至不同类型的目的地)。

2.有用的工具

在这个项目中,你无需安装额外的软件,但要用到一些标准库模块,其中包括你以前没有见过的nntplib,它负责与NNTP服务器交互。这里不详细介绍这个模块的方方面面,而是通过建立原型来研究它。

3.准备工作

要使用nntplib,你必须能够访问NNTP服务器。如果不确定能否这样做,可向ISP或系统管理员咨询。在这个项目中,我使用的是新闻组gmane.comp.python.committers,因此必须确保你的新闻(NNTP)服务器有这个新闻组,或者寻找你要使用的其他新闻组。如果你无法访问NNTP服务器,有几个开放的服务器可供任何人使用。只要在网上搜索“免费NNTP服务器”就能找到这样的服务器,你可以从中选择一个(nntplib官方文档中代码示例使用的NNTP服务器为news.gmane.org)。假设你使用的新闻服务器为news.gmane.org,可以像下面这样测试NNTP服务器:


注意 连接到有些服务器时,可能需要提供其他用于身份验证的参数。有关构造函数nntp的可选参数的详情,请参阅“Python库参考手册”(http://docs.python.org/library/nntplib.html)。


最后一行代码的运行结果是一个字符串,这个字符串以'211'(意味着该服务器上有你请求的新闻组)或'411'(意味着服务器没有这样的新闻组)打头,如下所示:

如果返回的字符串以'411'打头,就应使用新闻阅读器来查找可供使用的其他新闻组(还可能出现异常和相应的错误信息)。如果出现异常,可能是你输入的服务器名称不对。另一种可能性是,从创建服务器对象到调用方法group的时间超过了限定的时间,因为服务器可能只允许你连接很短的时间,如10秒钟。如果你无法快速输入这些代码,可将它们放在脚本中,再执行这个脚本(但需要添加print语句),也可将创建服务器和调用方法放在一行内(并用分号分隔它们)。

4.初次实现

秉承原型设计的理念,我们直接来解决问题。首先要做的是从NNTP服务器上的新闻组下载最新的消息。为简单起见,使用print直接将结果打印到标准输出即可。这个程序的逻辑不太复杂,难点主要是nntplib的用法。我们将使用单个NNTP对象,正如你在前一节看到的,实例化这个类时,只需指定NNTP服务器的名称。你需要对NNTP实例调用3个方法。

  • group:将指定新闻组设置为当前新闻组,并返回一些有关该新闻组的信息,其中包括最后一条消息的编号。
  • over:返回通过编号指定的一组消息的摘要。
  • body:返回指定消息的正文。

使用前面的服务器名称,可以像下面这样来完成设置工作:

其中变量howmany指定要获取多少篇文章。现在可以选择新闻组了。

返回的值为通用的服务器响应、新闻组包含的消息数、第一条和最后一条消息的编号,以及新闻组的名称,。我们感兴趣的主要是last,将使用它来创建要获取的文章的编号区间,该区间的起点为start = last-howmany 1,终点为last。我们将这两个数字作为参数传递给方法over,这将返回一系列表示消息的(id, overview)。然后,我们从overview中提取主题,并使用ID从服务器获取消息正文。

消息正文行是以字节形式返回的。如果使用默认编码UTF-8进行解码,可能得到非法的字节序列。理想的做法是提取编码信息,但为简单起见,我们直接使用编码Latin-1,它适用于ASCII字节,且遇到非ASCII字节时不会报错。打印所有文章后,我们调用server.quit()。就这么简单。

这个简单的新闻收集代里源代码如图所示。

在bash等UNIX shell中,可像下面这样运行这个程序:

python newagent1.py | less

通过使用less可每次只阅读一篇文章。如果没有这样的分页程序可用,可修改程序的print部分,将生成的文本存储到文件中——再次实现时就会这样做。

0 人点赞