nntplib — NNTP 协议客户端

源代码: Lib/nntplib.py

自 3.11 版起已弃用: nntplib 模块已弃用(有关详细信息,请参见 PEP 594)。


此模块定义了 NNTP 类,该类实现了网络新闻传输协议的客户端。它可用于实现新闻阅读器或发布者,或自动新闻处理器。它与 RFC 3977 以及较早的 RFC 977RFC 2980 兼容。

可用性:不适用于 Emscripten,不适用于 WASI。

此模块在 WebAssembly 平台 wasm32-emscriptenwasm32-wasi 上不起作用或不可用。有关更多信息,请参见 WebAssembly 平台

以下是如何使用它的两个小示例。列出有关新闻组的一些统计信息,并打印最近 10 篇文章的主题

>>> s = nntplib.NNTP('news.gmane.io')
>>> resp, count, first, last, name = s.group('gmane.comp.python.committers')
>>> print('Group', name, 'has', count, 'articles, range', first, 'to', last)
Group gmane.comp.python.committers has 1096 articles, range 1 to 1096
>>> resp, overviews = s.over((last - 9, last))
>>> for id, over in overviews:
...     print(id, nntplib.decode_header(over['subject']))
...
1087 Re: Commit privileges for Łukasz Langa
1088 Re: 3.2 alpha 2 freeze
1089 Re: 3.2 alpha 2 freeze
1090 Re: Commit privileges for Łukasz Langa
1091 Re: Commit privileges for Łukasz Langa
1092 Updated ssh key
1093 Re: Updated ssh key
1094 Re: Updated ssh key
1095 Hello fellow committers!
1096 Re: Hello fellow committers!
>>> s.quit()
'205 Bye!'

从二进制文件发布一篇文章(这假定该文章具有有效的标题,并且您有权在特定新闻组上发布文章)

>>> s = nntplib.NNTP('news.gmane.io')
>>> f = open('article.txt', 'rb')
>>> s.post(f)
'240 Article posted successfully.'
>>> s.quit()
'205 Bye!'

模块本身定义了以下类

nntplib.NNTP(主机, 端口=119, 用户=无, 密码=无, 阅读器模式=无, usenetrc=False[, 超时])

返回一个新的 NNTP 对象,表示与运行在主机 host 上、监听端口 port 的 NNTP 服务器的连接。可以为套接字连接指定一个可选的 timeout。如果提供了可选的 userpassword,或者在 /.netrc 中存在合适的凭据且可选标志 usenetrc 为真,则 AUTHINFO USERAUTHINFO PASS 命令用于识别和向服务器验证用户。如果可选标志 readermode 为真,则在执行验证之前会发送一个 mode reader 命令。如果您连接到本地计算机上的 NNTP 服务器并打算调用特定于阅读器的命令(例如 group),则有时需要阅读器模式。如果您收到意外的 NNTPPermanentError,您可能需要设置 readermodeNNTP 类支持 with 语句来无条件使用 OSError 异常,并在完成后关闭 NNTP 连接,例如:

>>> from nntplib import NNTP
>>> with NNTP('news.gmane.io') as n:
...     n.group('gmane.comp.python.committers')
... 
('211 1755 1 1755 gmane.comp.python.committers', 1755, 1, 1755, 'gmane.comp.python.committers')
>>>

引发 审计事件 nntplib.connect,其参数为 selfhostport

所有命令都将引发 审计事件 nntplib.putline,其参数为 selfline,其中 line 是即将发送到远程主机的字节。

3.2 版中已更改: usenetrc 现在默认情况下为 False

3.3 版中已更改: 添加了对 with 语句的支持。

3.9 版中已更改: 如果将 timeout 参数设置为零,它将引发 ValueError 以防止创建非阻塞套接字。

class nntplib.NNTP_SSL(host, port=563, user=None, password=None, ssl_context=None, readermode=None, usenetrc=False[, timeout])

返回一个新的 NNTP_SSL 对象,表示与在主机 host 上运行的 NNTP 服务器的加密连接,在端口 port 上进行侦听。 NNTP_SSL 对象具有与 NNTP 对象相同的方法。如果省略 port,则使用端口 563 (NNTPS)。ssl_context 也是可选的,并且是一个 SSLContext 对象。请阅读 安全注意事项 以了解最佳做法。所有其他参数的行为与 NNTP 的行为相同。

请注意,根据 RFC 4642,不鼓励在 563 端口上使用 SSL,而应使用 STARTTLS(如下所述)。但是,某些服务器仅支持前者。

引发 审计事件 nntplib.connect,其参数为 selfhostport

所有命令都将引发 审计事件 nntplib.putline,其参数为 selfline,其中 line 是即将发送到远程主机的字节。

3.2 版中添加。

3.4 版中已更改:该类现在支持使用 ssl.SSLContext.check_hostname服务器名称指示(请参阅 ssl.HAS_SNI)进行主机名检查。

3.9 版中已更改: 如果将 timeout 参数设置为零,它将引发 ValueError 以防止创建非阻塞套接字。

exception nntplib.NNTPError

派生自标准异常 Exception,这是 nntplib 模块引发的所有异常的基本类。此类的实例具有以下属性

response

服务器的响应(如果可用),作为 str 对象。

exception nntplib.NNTPReplyError

当从服务器收到意外答复时引发的异常。

exception nntplib.NNTPTemporaryError

当收到 400-499 范围内的响应代码时引发的异常。

exception nntplib.NNTPPermanentError

当收到 500-599 范围内的响应代码时引发的异常。

exception nntplib.NNTPProtocolError

当从服务器收到不以 1-5 范围内的数字开头的答复时引发的异常。

exception nntplib.NNTPDataError

当响应数据中出现某些错误时引发的异常。

NNTP 对象

连接后,NNTPNNTP_SSL 对象支持以下方法和属性。

属性

NNTP.nntp_version

表示服务器支持的 NNTP 协议版本的整数。在实践中,对于宣告符合 RFC 3977 的服务器,此值应为 2,对于其他服务器,此值应为 1

3.2 版中添加。

NNTP.nntp_implementation

描述 NNTP 服务器的软件名称和版本的字符串,如果服务器未宣告,则为 None

3.2 版中添加。

方法

几乎所有方法的返回元组中作为第一个项目返回的响应是服务器的响应:以三位数字代码开头的字符串。如果服务器的响应表示错误,则该方法会引发上述异常之一。

以下许多方法采用可选的仅关键字参数file。当提供file 参数时,它必须是已打开用于二进制写入的 文件对象,或者要写入的磁盘文件名称。然后,该方法会将服务器返回的任何数据(响应行和终止点除外)写入文件;该方法通常返回的任何行、元组或对象的列表都将为空。

在 3.2 版中更改:以下许多方法已得到重新设计和修复,这使得它们与其 3.1 对应版本不兼容。

NNTP.quit()

发送 QUIT 命令并关闭连接。调用此方法后,不应再调用 NNTP 对象的任何其他方法。

NNTP.getwelcome()

返回服务器在初始连接时发送的欢迎消息。(此消息有时包含可能与用户相关的免责声明或帮助信息。)

NNTP.getcapabilities()

返回服务器通告的 RFC 3977 功能,作为 dict 实例,将功能名称映射到(可能为空的)值列表。对于不理解 CAPABILITIES 命令的旧服务器,将返回一个空字典。

>>> s = NNTP('news.gmane.io')
>>> 'POST' in s.getcapabilities()
True

3.2 版中添加。

NNTP.login(user=None, password=None, usenetrc=True)

使用用户名和密码发送 AUTHINFO 命令。如果 userpasswordNoneusenetrc 为 true,则尽可能使用 ~/.netrc 中的凭据。

除非有意延迟,否则通常在 NNTP 对象初始化期间执行登录,单独调用此函数是不必要的。要强制延迟身份验证,在创建对象时不得设置 userpassword,并且必须将 usenetrc 设置为 False。

3.2 版中添加。

NNTP.starttls(context=None)

发送 STARTTLS 命令。这将在 NNTP 连接上启用加密。context 参数是可选的,应为 ssl.SSLContext 对象。请阅读 安全注意事项 以了解最佳做法。

请注意,在传输身份验证信息后可能无法执行此操作,并且在 NNTP 对象初始化期间,如果可能,默认情况下会进行身份验证。有关抑制此行为的信息,请参阅 NNTP.login()

3.2 版中添加。

版本 3.4 中已更改:此方法现在支持使用 ssl.SSLContext.check_hostname服务器名称指示(请参阅 ssl.HAS_SNI)进行主机名检查。

NNTP.newgroups(date, *, file=None)

发送 NEWGROUPS 命令。date 参数应为 datetime.datedatetime.datetime 对象。返回一个对 (response, groups),其中 groups 是一个表示自给定 date 以来新出现的组的列表。不过,如果提供了 file,那么 groups 将为空。

>>> from datetime import date, timedelta
>>> resp, groups = s.newgroups(date.today() - timedelta(days=3))
>>> len(groups) 
85
>>> groups[0] 
GroupInfo(group='gmane.network.tor.devel', last='4', first='1', flag='m')
NNTP.newnews(group, date, *, file=None)

发送 NEWNEWS 命令。此处,group 是一个组名或 '*',而 date 的含义与 newgroups() 中的含义相同。返回一个对 (response, articles),其中 articles 是一个消息 ID 列表。

此命令经常被 NNTP 服务器管理员禁用。

NNTP.list(group_pattern=None, *, file=None)

发送 LISTLIST ACTIVE 命令。返回一个对 (response, list),其中 list 是一个元组列表,表示此 NNTP 服务器中可用的所有组,可以选择匹配模式字符串 group_pattern。每个元组的格式为 (group, last, first, flag),其中 group 是一个组名,lastfirst 是最后一篇文章编号和第一篇文章编号,而 flag 通常采用以下值之一

  • y:允许本地张贴和来自对等方的文章。

  • m:此组已审核,所有张贴都必须经过批准。

  • n:不允许本地张贴,仅允许来自对等方的文章。

  • j:来自对等方的文章被归档在垃圾组中。

  • x:没有本地张贴,并且忽略来自对等方的文章。

  • =foo.bar:文章被归档在 foo.bar 组中。

如果标记有其他值,则应将新闻组的状态视为未知。

此命令可以返回非常大的结果,尤其是在未指定组模式的情况下。除非您确实需要刷新结果,否则最好将结果脱机缓存。

3.2 版中已更改: 添加了组模式

NNTP.descriptions(grouppattern)

发送 LIST NEWSGROUPS 命令,其中grouppatternRFC 3977 中指定的通配符字符串(它本质上与 DOS 或 UNIX shell 通配符字符串相同)。返回一个对 (response, descriptions),其中descriptions 是一个字典,将组名映射到文本描述。

>>> resp, descs = s.descriptions('gmane.comp.python.*')
>>> len(descs) 
295
>>> descs.popitem() 
('gmane.comp.python.bio.general', 'BioPython discussion list (Moderated)')
NNTP.description(group)

获取单个组的描述。如果有多个组匹配(如果“组”是真实的通配符字符串),则返回第一个匹配项。如果没有组匹配,则返回一个空字符串。

这会从服务器中删除响应代码。如果需要响应代码,请使用 descriptions()

NNTP.group(name)

发送 GROUP 命令,其中name 是组名。如果该组存在,则将其选为当前组。返回一个元组 (response, count, first, last, name),其中count 是组中的文章(估计)数,first 是组中的第一个文章编号,last 是组中的最后一个文章编号,name 是组名。

NNTP.over(message_spec, *, file=None)

发送 OVER 命令,或在旧服务器上发送 XOVER 命令。message_spec 可以是表示消息 ID 的字符串,或表示当前组中文章范围的数字 (first, last) 元组,或表示从 first 开始到当前组中最后一篇文章的范围的 (first, None) 元组,或 None,以选择当前组中的当前文章。

返回一个对 (response, overviews)overviews(article_number, overview) 元组的列表,对于由 message_spec 选择的每篇文章都有一个元组。每个 overview 是一个包含相同数量项目的字典,但此数量取决于服务器。这些项目是消息头(键是小写头名称)或元数据项目(键是元数据名称,前面加上 ":")。NNTP 规范保证存在以下项目

  • subjectfromdatemessage-idreferences

  • :bytes 元数据:整个原始文章(包括头和正文)中的字节数

  • :lines 元数据:文章正文中的行数

每个项目的价值要么是字符串,要么是 None(如果不存在)。

建议在头值可能包含非 ASCII 字符时对头值使用 decode_header() 函数

>>> _, _, first, last, _ = s.group('gmane.comp.python.devel')
>>> resp, overviews = s.over((last, last))
>>> art_num, over = overviews[0]
>>> art_num
117216
>>> list(over.keys())
['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']
>>> over['from']
'=?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?= <[email protected]>'
>>> nntplib.decode_header(over['from'])
'"Martin v. Löwis" <[email protected]>'

3.2 版中添加。

NNTP.help(*, file=None)

发送 HELP 命令。返回一个对 (response, list),其中 list 是帮助字符串的列表。

NNTP.stat(message_spec=None)

发送 STAT 命令,其中 message_spec 是消息 ID(用 '<''>' 括起来)或当前组中的文章编号。如果省略 message_specNone,则考虑当前组中的当前文章。返回一个三元组 (response, number, id),其中 number 是文章编号,id 是消息 ID。

>>> _, _, first, last, _ = s.group('gmane.comp.python.devel')
>>> resp, number, message_id = s.stat(first)
>>> number, message_id
(9099, '<[email protected]>')
NNTP.next()

发送 NEXT 命令。返回 stat() 的内容。

NNTP.last()

发送 LAST 命令。返回 stat() 的内容。

NNTP.article(message_spec=None, *, file=None)

发送 ARTICLE 命令,其中 message_spec 的含义与 stat() 中的含义相同。返回一个元组 (response, info),其中 info 是一个 namedtuple,具有三个属性 numbermessage_idlines(按此顺序)。number 是组中的文章编号(如果信息不可用,则为 0),message_id 是作为字符串的消息 ID,lines 是包含原始消息(包括标题和正文)的行的列表(不含终止换行符)。

>>> resp, info = s.article('<[email protected]>')
>>> info.number
0
>>> info.message_id
'<[email protected]>'
>>> len(info.lines)
65
>>> info.lines[0]
b'Path: main.gmane.org!not-for-mail'
>>> info.lines[1]
b'From: Neal Norwitz <[email protected]>'
>>> info.lines[-3:]
[b'There is a patch for 2.3 as well as 2.2.', b'', b'Neal']
NNTP.head(message_spec=None, *, file=None)

article() 相同,但发送 HEAD 命令。返回(或写入 file)的 lines 将仅包含消息标题,而不包含正文。

NNTP.body(message_spec=None, *, file=None)

article() 相同,但发送 BODY 命令。返回(或写入 file)的 lines 将仅包含消息正文,不包含标题。

NNTP.post(data)

使用 POST 命令发布一篇文章。data 参数可以是打开用于二进制读取的 文件对象,也可以是字节对象的任何可迭代对象(表示要发布的文章的原始行)。它应该表示一个格式良好的新闻文章,包括必需的标题。 post() 方法会自动转义以 . 开头的行,并追加终止行。

如果方法成功,则返回服务器的响应。如果服务器拒绝发布,则会引发 NNTPReplyError

NNTP.ihave(message_id, data)

发送 IHAVE 命令。message_id 是要发送到服务器的消息 ID(用 '<''>' 括起来)。data 参数和返回值与 post() 相同。

NNTP.date()

返回一个元组 (response, date)date 是一个 datetime 对象,其中包含服务器的当前日期和时间。

NNTP.slave()

发送 SLAVE 命令。返回服务器的响应

NNTP.set_debuglevel(level)

设置实例的调试级别。这控制打印的调试输出量。默认值 0 不产生调试输出。值 1 产生适量调试输出,通常每个请求或响应一行。值 2 或更高产生最大调试输出量,记录连接上发送和接收的每一行(包括消息文本)。

以下是 RFC 2980 中定义的可选 NNTP 扩展。其中一些已被 RFC 3977 中较新的命令取代。

NNTP.xhdr(hdr, str, *, file=None)

发送 XHDR 命令。hdr 参数是一个头关键字,例如 'subject'str 参数应具有 'first-last' 形式,其中 firstlast 是要搜索的第一个和最后一个文章编号。返回一个对 (response, list),其中 list 是对 (id, text) 的列表,其中 id 是文章编号(作为字符串),text 是该文章请求头的文本。如果提供了 file 参数,则 XHDR 命令的输出将存储在文件中。如果 file 是一个字符串,则该方法将打开一个具有该名称的文件,写入它,然后关闭它。如果 file 是一个 文件对象,则它将开始调用 write() 来存储命令输出的行。如果提供了 file,则返回的 list 是一个空列表。

NNTP.xover(start, end, *, file=None)

发送 XOVER 命令。startend 是用于限定要选择的文章范围的文章编号。返回值与 over() 的相同。建议改用 over(),因为它在可用时会自动使用较新的 OVER 命令。

实用程序函数

此模块还定义了以下实用程序函数

nntplib.decode_header(header_str)

解码标头值,取消转义所有转义的非 ASCII 字符。header_str 必须是 str 对象。返回取消转义的值。建议使用此函数以人类可读的形式显示一些标头

>>> decode_header("Some subject")
'Some subject'
>>> decode_header("=?ISO-8859-15?Q?D=E9buter_en_Python?=")
'Débuter en Python'
>>> decode_header("Re: =?UTF-8?B?cHJvYmzDqG1lIGRlIG1hdHJpY2U=?=")
'Re: problème de matrice'