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

源代碼: Lib/nntplib.py

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


此模塊定義了 NNTP 類來實現(xiàn)網(wǎng)絡(luò)新聞傳輸協(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!'

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

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

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

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

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

在 3.9 版更改: 如果 timeout 參數(shù)設(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 服務(wù)器的連接。 NNTP_SSL 對象具有與 NNTP 對象相同的方法。 如果 port 被省略,則會使用端口 563 (NNTPS)。 ssl_context 也是可選的,且為一個 SSLContext 對象。 請閱讀 安全考量 來了解最佳實踐。 所有其他形參的行為都與 NNTP 的相同。

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

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

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

3.2 新版功能.

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

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

exception nntplib.NNTPError?

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

response?

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

exception nntplib.NNTPReplyError?

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

exception nntplib.NNTPTemporaryError?

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

exception nntplib.NNTPPermanentError?

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

exception nntplib.NNTPProtocolError?

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

exception nntplib.NNTPDataError?

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

NNTP 對象?

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

屬性?

NNTP.nntp_version?

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

3.2 新版功能.

NNTP.nntp_implementation?

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

3.2 新版功能.

方法?

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

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

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

NNTP.quit()?

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

NNTP.getwelcome()?

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

NNTP.getcapabilities()?

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

>>>
>>> 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)建該對象時不能設(shè)置 userpassword,并必須將 usenetrc 設(shè)為 False。

3.2 新版功能.

NNTP.starttls(context=None)?

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

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

3.2 新版功能.

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

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

發(fā)送 NEWGROUPS 命令。 date 參數(shù)應(yīng)為 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 服務(wù)器管理員禁用。

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

發(fā)送 LISTLIST ACTIVE 命令。 返回一個 (response, list) 對,其中 list 是代表此 NNTP 服務(wù)器上所有可用新聞組的元組列表,并可選擇匹配模式字符串 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)應(yīng)當(dāng)被視為未知。

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

在 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 字符串),則返回第一個匹配結(jié)果。 如果未匹配到任何新聞組,則返回空字符串。

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

NNTP.group(name)?

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

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

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

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

  • subject, from, date, message-idreferences 標(biāo)頭

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

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

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

建議在標(biāo)頭值可能包含非 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 (包裹在 '<''>' 中) 或者當(dāng)前新聞組中的文章編號。 如果 message_spec 被省略或為 None,則會選擇當(dāng)前新聞組中的當(dāng)前文章。 反回一個三元組 (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() 類似的結(jié)果。

NNTP.last()?

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

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 為由包括標(biāo)頭和消息體的原始消息的行組成的列表 (不帶末尾換行符)。

>>>
>>> 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) 將只包含消息標(biāo)頭,不包含消息體。

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

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

NNTP.post(data)?

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

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

NNTP.ihave(message_id, data)?

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

NNTP.date()?

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

NNTP.slave()?

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

NNTP.set_debuglevel(level)?

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

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

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

發(fā)送 XHDR 命令。 hdr 參數(shù)是標(biāo)頭關(guān)鍵字,例如 'subject'str 參數(shù)的形式應(yīng)為 'first-last',其中 firstlast 是要搜索的首篇和末篇文章編號。 返回一個 (response, list) 對,其中 list(id, text) 對的列表,其中 id 是文章編號(字符串類型)而 text 是該文章的請求標(biāo)頭。 如果提供了 file 形參,則 XHDR 命令的輸出會保存到文件中。 如果 file 為字符串,則此方法將打開指定名稱的文件,向其寫入內(nèi)容并將其關(guān)閉。 如果 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)?

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

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