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

源代碼: Lib/nntplib.py

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


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

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

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

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

此模塊本身定義了以下的類(lèi):

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

返回一個(gè)新的 NNTP 對象,代表一個(gè)對運行于主機 host,在端口 port 上監聽(tīng)的 NNTP 服務(wù)器的連接。 可以為套接字連接指定可選的 timeout。 如果提供了可選的 userpassword,或者如果在 /.netrc 中存在適合的憑證并且可選的旗標 usenetrc 為真值,則會(huì )使用 AUTHINFO USERAUTHINFO PASS 命令在服務(wù)器上標識和認證用戶(hù)。 如果可選的旗標 readermode 為真值,則會(huì )在執行認證之前發(fā)送 mode reader 命令。 在某些時(shí)候如果你是連接本地機器上的 NNTP 服務(wù)器并且想要調用讀取者專(zhuān)屬命令如 group 那么還必須使用讀取者模式。 如果你收到預料之外的 NNTPPermanentError,你可能需要設置 readermode。 NNTP 類(lèi)支持使用 with 語(yǔ)句來(lái)無(wú)條件地消費 OSError 異常并在結束時(shí)關(guān)閉 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ā)一個(gè) 審計事件 nntplib.connect,附帶參數 self, host, port。

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

在 3.2 版更改: usenetrc 現在默認為 False。

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

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

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

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

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

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

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

3.2 新版功能.

在 3.4 版更改: 本類(lèi)現在支持使用 ssl.SSLContext.check_hostname服務(wù)器名稱(chēng)指示 (參閱 ssl.HAS_SNI)進(jìn)行主機名檢查。

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

exception nntplib.NNTPError?

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

response?

可用的服務(wù)器響應,為一 str 對象。

exception nntplib.NNTPReplyError?

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

exception nntplib.NNTPTemporaryError?

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

exception nntplib.NNTPPermanentError?

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

exception nntplib.NNTPProtocolError?

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

exception nntplib.NNTPDataError?

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

NNTP 對象?

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

屬性?

NNTP.nntp_version?

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

3.2 新版功能.

NNTP.nntp_implementation?

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

3.2 新版功能.

方法?

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

以下方法中許多都接受一個(gè)可選的僅限關(guān)鍵字參數 file。 當提供了 file 參數時(shí),它必須為打開(kāi)用于二進(jìn)制寫(xiě)入的 file object,或要寫(xiě)入的磁盤(pán)文件名稱(chēng)。 此類(lèi)方法隨后將把服務(wù)器返回的任意數據(除了響應行和表示結束的點(diǎn)號)寫(xiě)入到文件中;此類(lèi)方法通常返回的任何行列表、元組或對象都將為空值。

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

NNTP.quit()?

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

NNTP.getwelcome()?

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

NNTP.getcapabilities()?

返回服務(wù)器所聲明的 RFC 3977 功能,其形式為將功能名稱(chēng)映射到(可能為空的)值列表的 dict 實(shí)例。 在不能識別 CAPABILITIES 命令的舊式服務(wù)器上,會(huì )返回一個(gè)空字典。

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

3.2 新版功能.

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

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

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

3.2 新版功能.

NNTP.starttls(context=None)?

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

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

3.2 新版功能.

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

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

發(fā)送 NEWGROUPS 命令。 date 參數應為 datetime.datedatetime.datetime 對象。 返回一個(gè) (response, groups) 對,其中 groups 是代表給定i date 以來(lái)所新建的新聞組。 但是如果提供了 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 是新聞組名稱(chēng)或為 '*',而 datenewgroups() 中的含義相同。 返回一個(gè) (response, articles) 對,其中 articles 為消息 ID 列表。

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

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

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

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

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

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

  • j: 來(lái)自組員的文章會(huì )被轉入垃圾分組。

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

  • =foo.bar: 文章會(huì )被轉入 foo.bar 分組。

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

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

在 3.2 版更改: 增加了 group_pattern。

NNTP.descriptions(grouppattern)?

發(fā)送 LIST NEWSGROUPS 命令,其中 grouppatternRFC 3977 中規定的 wildmat 字符串(它實(shí)際上與 DOS 或 UNIX shell 通配字符串相同)。 返回一個(gè) (response, descriptions) 對,其中 descriptions 是將新聞組名稱(chēng)映射到文本描述的字典。

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

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

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

NNTP.group(name)?

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

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

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

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

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

  • :bytes metadata: 整個(gè)原始文章數據的字節數(包括標頭和消息體)

  • :lines metadata: 文章消息體的行數

每個(gè)條目的值或者為字符串,或者在沒(méi)有值時(shí)為 None。

建議在標頭值可能包含非 ASCII 字符的時(shí)候對其使用 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?= <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 命令。 返回一個(gè) (response, list) 對,其中 list 為幫助字符串列表。

NNTP.stat(message_spec=None)?

發(fā)送 STAT 命令,其中 message_spec 為消息 ID (包裹在 '<''>' 中) 或者當前新聞組中的文章編號。 如果 message_spec 被省略或為 None,則會(huì )選擇當前新聞組中的當前文章。 反回一個(gè)三元組 (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() 類(lèi)似的結果。

NNTP.last()?

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

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

發(fā)送 ARTICLE 命令,其中 message_spec 的含義與 stat() 中的相同。 返回一個(gè)元組 (response, info),其中 info 是一個(gè) namedtuple,包含三個(gè)屬性 number, message_idlines (按此順序)。 number 是新聞組中的文章數量 (或者如果該信息不可用則為 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() 類(lèi)似,但會(huì )發(fā)送 HEAD 命令。 返回的 lines (或寫(xiě)入到 file) 將只包含消息標頭,不包含消息體。

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

article() 類(lèi)似,但會(huì )發(fā)送 BODY 命令。 返回的 lines (或寫(xiě)入到 file) 將只包含消息體,不包含標頭。

NNTP.post(data)?

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

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

NNTP.ihave(message_id, data)?

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

NNTP.date()?

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

NNTP.slave()?

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

NNTP.set_debuglevel(level)?

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

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

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

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

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

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

工具函數?

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

nntplib.decode_header(header_str)?

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

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