这个练习项目来自《Python基础教程(第2版)》,案例原名为“新闻聚合”。
项目分为两个阶段:
- 第一阶段:通过与NNTP服务器进行交互获取新闻源。
- 第二阶段:获取不同的新闻源编译为新闻报告并输出不同格式的目标。
这一篇教程,我们先完成第一阶段的目标。
NNTP是“Network News Transfer Protocol”的简称,中文名为“网络新闻传输协议”。
通过这种协议不是很常见,通过它可以传输网络新闻邮件。
NNTP服务器上,往往会存在多个新闻组(或者叫讨论组)。
我们需要从NNTP服务器获取到24小时内,某一个新闻组的新闻邮件,并进行解析,获取到新闻标题以及对应的内容。
这里我们访问的NNTP服务器地址为:http://web.aioe.org,新闻组名称为:comp.lang.python。
为了实现第一阶段目标,我们先进行一次试验。
通过Python内置的nntplib模块与NNTP服务器进行交互,访问目标新闻组。
示例代码:
from nntplib import NNTP
server = NNTP('web.aioe.org') # 实例化NNTP服务器连接对象
result = server.group('comp.lang.python') # 连接服务器中的新闻组
print(result) # 显示输出连接信息
server.quit() # 关闭连接
运行上方代码,如果正确连接到了指定的新闻组,会显示输出以“211”开头的返回信息。
例如:(‘211 8977 192702 201741 comp.lang.python’, 8977, 192702, 201741, ‘comp.lang.python’)
否则,会给出异常提示。
在完成了这个试验,确定能够正常连接新闻组之后,我们进一步完成项目目标。
1、导入需要使用的模块
除了nntplib模块之外,因为我们要获取近24小时的新闻源,所以还需要datetime模块,帮助我们处理获取新闻的时间。
示例代码:
from nntplib import NNTP
from datetime import date, timedelta
2、创建服务器连接对象、新闻组名称以及新闻时间
示例代码:
server = NNTP('web.aioe.org') # 实例化NNTP服务器连接对象
yesterday = date.today() - timedelta(days=1) # 当前时间减去时间间隔
group = 'comp.lang.python' # 新闻组名称
3、创建生成新闻id的生成器
创建新闻id的生成器是为了能够只获取一个新闻标题与内容。
因为获取内容过多的话,会耗费太多时间。
def get_id(): # 创建新闻id生成器
ids = server.newnews(group, yesterday)[1] # 获取近24小时新闻内容中的所有新闻id
for id in ids: # 遍历所有新闻id
yield id # 生成1个新闻id
在上方代码中,通过newnews()方法能够获取最新一段时间内的所有新闻的数量和id,它是一个元组,类似:(数量描述,[id1,id2,…])。
所以,我们需要获取到返回值中id列表部分,并进行循环遍历,从而生成每一个新闻id。
4、获取一个新闻内容并显示输出
大家可以通过下方代码的注释,理解整个实现过程。
示例代码:
ids = get_id() # 创建新闻id生成器对象
id = next(ids) # 获取第1个新闻id
head_data = server.head(id)[1][2] # 获取新闻的头部内容
body_data = server.body(id)[1][2] # 获取新闻的主体内容
title = '' # 创建标题
body = '' # 创建主体
for line in head_data: # 遍历头部内容
if line.decode().lower().startswith('subject:'): # 如果发现标题特征(“subject:”开头)
title = line[9:].decode() # 去除特征文字保存标题内容
for line in body_data: # 遍历主体内容
if line.decode().endswith('='): # 如果行内容以“=”结尾
line = line[:-1] # 去除“=”
if line.decode().endswith('=20'): # 如果行内容以“=20”结尾
line = line[:-3] + b'\n' # 去除“=20”后添加换行符
body += line.decode() # 将每行内容组织为新的主体内容
print(title) # 显示输出标题内容
print('-' * len(title)) # 显示输出和标题字符数量同等的“-”符号
print(body) # 显示输出主题内容
server.quit() # 退出与服务器的连接
注意,因为获取到的新闻内容中,字符串都是bytes类型,所以需要进行解码,才能够进行字符串的相关操作。
通过以上步骤,我们就实现了第一阶段的目标。