nntplib --- NNTP 協(xié)議客戶端?

源代碼: Lib/nntplib.py

3.11 版后已移除: The nntplib module is deprecated (see PEP 594 for details).


此模塊定義了 NNTP 類來實現(xiàn)網(wǎng)絡新聞傳輸協(xié)議的客戶端。 它可被用于實現(xiàn)一個新聞閱讀或發(fā)布器,或是新聞自動處理程序。 它兼容了 RFC 3977 以及較舊的 RFC 977RFC 2980。

下面是此模塊的兩個簡單用法示例。 列出某個新聞組的一些統(tǒng)計數(shù)據(jù)并打印最近 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!'

要基于一個二進制文件發(fā)布文章 (假定文章包含有效的標頭,并且你有在特定新聞組上發(fā)布內(nèi)容的權限):

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

此模塊本身定義了以下的類:

class nntplib.NNTP(host, port=119, user=None, password=None, readermode=None, usenetrc=False[, timeout])?

返回一個新的 NNTP 對象,代表一個對運行于主機 host,在端口 port 上監(jiān)聽的 NNTP 服務器的連接。 可以為套接字連接指定可選的 timeout。 如果提供了可選的 userpassword,或者如果在 /.netrc 中存在適合的憑證并且可選的旗標 usenetrc 為真值,則會使用 AUTHINFO USERAUTHINFO PASS 命令在服務器上標識和認證用戶。 如果可選的旗標 readermode 為真值,則會在執(zhí)行認證之前發(fā)送 mode reader 命令。 在某些時候如果你是連接本地機器上的 NNTP 服務器并且想要調(diào)用讀取者專屬命令如 group 那么還必須使用讀取者模式。 如果你收到預料之外的 NNTPPermanentError,你可能需要設置 readermode。 NNTP 類支持使用 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')
>>>

引發(fā)一個 審計事件 nntplib.connect,附帶參數(shù) self, host, port。

引發(fā)一個 審計事件 nntplib.putline,附帶參數(shù) self, line。

在 3.2 版更改: usenetrc 現(xiàn)在默認為 False。

在 3.3 版更改: 添加了對 with 語句的支持。

在 3.9 版更改: 如果 timeout 參數(shù)設置為 0,創(chuàng)建非阻塞套接字時,它將引發(fā) ValueError 來阻止該操作。

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

返回一個新的 NNTP_SSL 對象,代表一個對運行于主機 host,在端口 port 上監(jiān)聽的 NNTP 服務器的連接。 NNTP_SSL 對象具有與 NNTP 對象相同的方法。 如果 port 被省略,則會使用端口 563 (NNTPS)。 ssl_context 也是可選的,且為一個 SSLContext 對象。 請閱讀 安全考量 來了解最佳實踐。 所有其他形參的行為都與 NNTP 的相同。

請注意 RFC 4642 不再推薦使用 563 端口的 SSL,建議改用下文描述的 STARTTLS。 但是,某些服務器只支持前者。

引發(fā)一個 審計事件 nntplib.connect,附帶參數(shù) self, host, port。

引發(fā)一個 審計事件 nntplib.putline,附帶參數(shù) self, line。

3.2 新版功能.

在 3.4 版更改: 本類現(xiàn)在支持使用 ssl.SSLContext.check_hostname服務器名稱指示 (參閱 ssl.HAS_SNI)進行主機名檢查。

在 3.9 版更改: 如果 timeout 參數(shù)設置為 0,創(chuàng)建非阻塞套接字時,它將引發(fā) ValueError 來阻止該操作。

exception nntplib.NNTPError?

派生自標準異常 Exception,這是 nntplib 模塊中引發(fā)的所有異常的基類。 該類的實例具有以下屬性:

response?

可用的服務器響應,為一 str 對象。

exception nntplib.NNTPReplyError?

從服務器收到意外答復時,將引發(fā)本異常。

exception nntplib.NNTPTemporaryError?

收到 400--499 范圍內(nèi)的響應代碼時所引發(fā)的異常。

exception nntplib.NNTPPermanentError?

收到 500--599 范圍內(nèi)的響應代碼時所引發(fā)的異常。

exception nntplib.NNTPProtocolError?

當從服務器收到不是以數(shù)字 1--5 開頭的答復時所引發(fā)的異常。

exception nntplib.NNTPDataError?

當響應數(shù)據(jù)中存在錯誤時所引發(fā)的異常。

NNTP 對象?

當連接時,NNTPNNTP_SSL 對象支持以下方法和屬性。

屬性?

NNTP.nntp_version?

代表服務器所支持的 NNTP 協(xié)議版本的整數(shù)。 在實踐中,這對聲明遵循 RFC 3977 的服務器應為 2 而對其他服務器則為 1。

3.2 新版功能.

NNTP.nntp_implementation?

描述 NNTP 服務器軟件名稱和版本的字符串,如果服務器未聲明此信息則為 None。

3.2 新版功能.

方法?

作為幾乎全部方法所返回元組的第一項返回的 response 是服務器的響應:以三位數(shù)字代碼打頭的字符串。 如果服務器的響應是提示錯誤,則方法將引發(fā)上述異常之一。

以下方法中許多都接受一個可選的僅限關鍵字參數(shù) file。 當提供了 file 參數(shù)時,它必須為打開用于二進制寫入的 file object,或要寫入的磁盤文件名稱。 此類方法隨后將把服務器返回的任意數(shù)據(jù)(除了響應行和表示結束的點號)寫入到文件中;此類方法通常返回的任何行列表、元組或?qū)ο蠖紝榭罩怠?/p>

在 3.2 版更改: 以下方法中許多都已被重寫和修正,這使得它們不再與 3.1 中的同名方法相兼容。

NNTP.quit()?

發(fā)送 QUIT 命令并關閉連接。 一旦此方法被調(diào)用,NNTP 對象的其他方法都不應再被調(diào)用。

NNTP.getwelcome()?

返回服務器發(fā)送的歡迎消息,作為連接開始的回復。(該消息有時包含與用戶有關的免責聲明或幫助信息。)

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)?

發(fā)送 AUTHINFO 命令并附帶用戶名和密碼。 如果 userpasswordNoneusenetrc 為真值,則會在可能的情況下使用來自 ~/.netrc 的憑證。

除非被有意延遲,登錄操作通常會在 NNTP 對象初始化期間被執(zhí)行因而沒有必要單獨調(diào)用此函數(shù)。 要強制延遲驗證,你在創(chuàng)建該對象時不能設置 userpassword,并必須將 usenetrc 設為 False。

3.2 新版功能.

NNTP.starttls(context=None)?

發(fā)送 STARTTLS 命令。 這將在 NNTP 連接上啟用加密。 context 參數(shù)是可選的且應為 ssl.SSLContext 對象。 請閱讀 安全考量 了解最佳實踐。

請注意此操作可能不會在傳輸驗證信息之后立即完成,只要有可能驗證默認會在 NNTP 對象初始化期間發(fā)生。 請參閱 NNTP.login() 了解有關如何屏蔽此行為的信息。

3.2 新版功能.

在 3.4 版更改: 此方法現(xiàn)在支持使用 ssl.SSLContext.check_hostname服務器名稱指示 (參見 ssl.HAS_SNI) 進行主機名檢查。

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

發(fā)送 NEWGROUPS 命令。 date 參數(shù)應為 datetime.datedatetime.datetime 對象。 返回一個 (response, groups) 對,其中 groups 是代表給定i 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)?

發(fā)送 NEWNEWS 命令。 這里,group 是新聞組名稱或為 '*',而 datenewgroups() 中的含義相同。 返回一個 (response, articles) 對,其中 articles 為消息 ID 列表。

此命令經(jīng)常會被 NNTP 服務器管理員禁用。

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

發(fā)送 LISTLIST ACTIVE 命令。 返回一個 (response, list) 對,其中 list 是代表此 NNTP 服務器上所有可用新聞組的元組列表,并可選擇匹配模式字符串 group_pattern。 每個元組的形式為 (group, last, first, flag),其中 group 為新聞組名稱,lastfirst 是最后一個和第一個文章的編號,而 flag 通常為下列值之一:

  • y: 允許來自組員的本地發(fā)帖和文章。

  • m: 新聞組受到管制因而所有發(fā)帖必須經(jīng)過審核。

  • n: 不允許本地發(fā)帖,只允許來自組員的文章。

  • j: 來自組員的文章會被轉(zhuǎn)入垃圾分組。

  • x: 不允許本地發(fā)帖,而來自組員的文章會被忽略。

  • =foo.bar: 文章會被轉(zhuǎn)入 foo.bar 分組。

如果 flag 具有其他值,則新聞組的狀態(tài)應當被視為未知。

此命令可能返回非常龐大的結果,特別是當未指明 group_pattern 的時候。 最好是離線緩存其結果,除非你確實需要刷新它們。

在 3.2 版更改: 增加了 group_pattern

NNTP.descriptions(grouppattern)?

發(fā)送 LIST NEWSGROUPS 命令,其中 grouppatternRFC 3977 中規(guī)定的 wildmat 字符串(它實際上與 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)?

獲取單個新聞組 group 的描述。 如果匹配到一個以上的新聞組(如果 'group' 是一個真實的 wildmat 字符串),則返回第一個匹配結果。 如果未匹配到任何新聞組,則返回空字符串。

此方法略去了來自服務器的響應代碼。 如果需要響應代碼,請使用 descriptions()。

NNTP.group(name)?

發(fā)送 GROUP 命令,其中 name 為新聞組名稱。 該新聞組如果存在,則會被選定為當前新聞組。 返回一個元組 (response, count, first, last, name),其中 count 是該新聞組中(估計的)文章數(shù)量,first 是新聞組中第一篇文章的編號,last 是新聞組中最后一篇文章的編號,而 name 是新聞組名稱。

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

發(fā)送 OVER 命令,或是舊式服務器上的 XOVER 命令。 message_spec 可以是表示消息 ID 的字符串,或是指明當前新聞組內(nèi)文章范圍的數(shù)字元組 (first, last),或是指明當前新聞組內(nèi)從 (first, None) first 到最后一篇文章的元組,或者為 None 表示選定當前新聞組內(nèi)的當前文章。

返回一個 (response, overviews) 對。 其中 overviews 是一個包含 (article_number, overview) 元組的列表,每個元組對應 message_spec 所選定的一篇文章。 每個 overview 則是包含同樣數(shù)量條目的字典,但具體數(shù)量取決于服務器。 這些條目或是為消息標頭(對應鍵為小寫的標頭名稱)或是為 metadata 項(對應鍵為以 ":" 打頭的 metadata 名稱)。 以下條目會由 NNTP 規(guī)范描述來確保提供:

  • subject, from, date, message-idreferences 標頭

  • :bytes metadata: 整個原始文章數(shù)據(jù)的字節(jié)數(shù)(包括標頭和消息體)

  • :lines metadata: 文章消息體的行數(shù)

每個條目的值或者為字符串,或者在沒有值時為 None。

建議在標頭值可能包含非 ASCII 字符的時候?qū)ζ涫褂?decode_header() 函數(shù):

>>>
>>> _, _, 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?= <martin@v.loewis.de>'
>>> nntplib.decode_header(over['from'])
'"Martin v. L?wis" <martin@v.loewis.de>'

3.2 新版功能.

NNTP.help(*, file=None)?

發(fā)送 HELP 命令。 返回一個 (response, list) 對,其中 list 為幫助字符串列表。

NNTP.stat(message_spec=None)?

發(fā)送 STAT 命令,其中 message_spec 為消息 ID (包裹在 '<''>' 中) 或者當前新聞組中的文章編號。 如果 message_spec 被省略或為 None,則會選擇當前新聞組中的當前文章。 反回一個三元組 (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, '<20030112190404.GE29873@epoch.metaslash.com>')
NNTP.next()?

發(fā)送 NEXT 命令。 返回與 stat() 類似的結果。

NNTP.last()?

發(fā)送 LAST 命令。 返回與 stat() 類似的結果。

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

發(fā)送 ARTICLE 命令,其中 message_spec 的含義與 stat() 中的相同。 返回一個元組 (response, info),其中 info 是一個 namedtuple,包含三個屬性 number, message_idlines (按此順序)。 number 是新聞組中的文章數(shù)量 (或者如果該信息不可用則為 0),message_id 為字符串形式的消息 ID,而 lines 為由包括標頭和消息體的原始消息的行組成的列表 (不帶末尾換行符)。

>>>
>>> resp, info = s.article('<20030112190404.GE29873@epoch.metaslash.com>')
>>> info.number
0
>>> info.message_id
'<20030112190404.GE29873@epoch.metaslash.com>'
>>> len(info.lines)
65
>>> info.lines[0]
b'Path: main.gmane.org!not-for-mail'
>>> info.lines[1]
b'From: Neal Norwitz <neal@metaslash.com>'
>>> 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() 類似,但會發(fā)送 HEAD 命令。 返回的 lines (或?qū)懭氲?file) 將只包含消息標頭,不包含消息體。

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

article() 類似,但會發(fā)送 BODY 命令。 返回的 lines (或?qū)懭氲?file) 將只包含消息體,不包含標頭。

NNTP.post(data)?

使用 POST 命令發(fā)布文章。 data 參數(shù)是以二進制讀取模式打開的 file object,或是任意包含字節(jié)串對象的可迭代對象 (表示要發(fā)布的文章的原始行數(shù)據(jù))。 它應當代表一篇適當格式的新聞組文章,包含所需的標頭。 post() 方法會自動對以 . 打頭的行數(shù)據(jù)進行轉(zhuǎn)義并添加結束行。

如果此方法執(zhí)行成功,將返回服務器的響應。 如果服務器拒絕響應,則會引發(fā) NNTPReplyError。

NNTP.ihave(message_id, data)?

發(fā)送 IHAVE 命令。 message_id 為要發(fā)給服務器的消息 ID (包裹在 '<''>' 中)。 data 形參和返回值與 post() 的一致。

NNTP.date()?

返回一個 (response, date) 對。 date 是包含服務器當前日期與時間的 datetime 對象。

NNTP.slave()?

發(fā)送 SLAVE 命令。 返回服務器的 響應

NNTP.set_debuglevel(level)?

設置實例的調(diào)試級別。 它控制著打印調(diào)試輸出信息的數(shù)量。 默認值 0 不產(chǎn)生調(diào)試輸出。 值 1 產(chǎn)生中等數(shù)量的調(diào)試輸出,通常每個請求或響應各產(chǎn)生一行。 大于等于 2 的值產(chǎn)生最多的調(diào)試輸出,在連接上發(fā)送和接收的每一行信息都會被記錄下來(包括消息文本)。

以下是在 RFC 2980 中定義的可選 NNTP 擴展。 其中一些已被 RFC 3977 中的新命令所取代。

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

發(fā)送 XHDR 命令。 hdr 參數(shù)是標頭關鍵字,例如 'subject'。 str 參數(shù)的形式應為 'first-last',其中 firstlast 是要搜索的首篇和末篇文章編號。 返回一個 (response, list) 對,其中 list(id, text) 對的列表,其中 id 是文章編號(字符串類型)而 text 是該文章的請求標頭。 如果提供了 file 形參,則 XHDR 命令的輸出會保存到文件中。 如果 file 為字符串,則此方法將打開指定名稱的文件,向其寫入內(nèi)容并將其關閉。 如果 filefile object,則將在該文件對象上調(diào)用 write() 方法來保存命令所輸出的行信息。 如果提供了 file,則返回的 list 將為空列表。

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

發(fā)送 XOVER 命令。 startend 是限制所選取文章范圍的文章編號。 返回值與 over() 的相同。 推薦改用 over(),因為它將在可能的情況下自動使用更新的 OVER 命令。

工具函數(shù)?

這個模塊還定義了下列工具函數(shù):

nntplib.decode_header(header_str)?

解碼標頭值,恢復任何被轉(zhuǎn)義的非 ASCII 字符。 header_str 必須為 str 對象。 將返回被恢復的值。 推薦使用此函數(shù)來以人類可讀的形式顯示某些標頭:

>>>
>>> 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'