nntplib
--- NNTP 協(xié)議客戶(hù)端?
源代碼: Lib/nntplib.py
此模塊定義了 NNTP
類(lèi)來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)新聞傳輸協(xié)議的客戶(hù)端。 它可被用于實(shí)現(xiàn)一個(gè)新聞閱讀或發(fā)布器,或是新聞自動(dòng)處理程序。 它兼容了 RFC 3977 以及較舊的 RFC 977 和 RFC 2980。
下面是此模塊的兩個(gè)簡(jiǎn)單用法示例。 列出某個(gè)新聞組的一些統(tǒng)計(jì)數(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!'
要基于一個(gè)二進(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!'
此模塊本身定義了以下的類(lèi):
- class nntplib.NNTP(host, port=119, user=None, password=None, readermode=None, usenetrc=False[, timeout])?
返回一個(gè)新的
NNTP
對(duì)象,代表一個(gè)對(duì)運(yùn)行于主機(jī) host,在端口 port 上監(jiān)聽(tīng)的 NNTP 服務(wù)器的連接。 可以為套接字連接指定可選的 timeout。 如果提供了可選的 user 和 password,或者如果在/.netrc
中存在適合的憑證并且可選的旗標(biāo) usenetrc 為真值,則會(huì)使用AUTHINFO USER
和AUTHINFO PASS
命令在服務(wù)器上標(biāo)識(shí)和認(rèn)證用戶(hù)。 如果可選的旗標(biāo) readermode 為真值,則會(huì)在執(zhí)行認(rèn)證之前發(fā)送mode reader
命令。 在某些時(shí)候如果你是連接本地機(jī)器上的 NNTP 服務(wù)器并且想要調(diào)用讀取者專(zhuān)屬命令如group
那么還必須使用讀取者模式。 如果你收到預(yù)料之外的NNTPPermanentError
,你可能需要設(shè)置 readermode。NNTP
類(lèi)支持使用with
語(yǔ)句來(lái)無(wú)條件地消費(fèi)OSError
異常并在結(jié)束時(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è) 審計(jì)事件
nntplib.connect
,附帶參數(shù)self
,host
,port
。引發(fā)一個(gè) 審計(jì)事件
nntplib.putline
,附帶參數(shù)self
,line
。在 3.2 版更改: usenetrc 現(xiàn)在默認(rèn)為
False
。在 3.3 版更改: 添加了對(duì)
with
語(yǔ)句的支持。在 3.9 版更改: 如果 timeout 參數(shù)設(shè)置為 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
對(duì)象,代表一個(gè)對(duì)運(yùn)行于主機(jī) host,在端口 port 上監(jiān)聽(tīng)的 NNTP 服務(wù)器的連接。NNTP_SSL
對(duì)象具有與NNTP
對(duì)象相同的方法。 如果 port 被省略,則會(huì)使用端口 563 (NNTPS)。 ssl_context 也是可選的,且為一個(gè)SSLContext
對(duì)象。 請(qǐng)閱讀 安全考量 來(lái)了解最佳實(shí)踐。 所有其他形參的行為都與NNTP
的相同。請(qǐng)注意 RFC 4642 不再推薦使用 563 端口的 SSL,建議改用下文描述的 STARTTLS。 但是,某些服務(wù)器只支持前者。
引發(fā)一個(gè) 審計(jì)事件
nntplib.connect
,附帶參數(shù)self
,host
,port
。引發(fā)一個(gè) 審計(jì)事件
nntplib.putline
,附帶參數(shù)self
,line
。3.2 新版功能.
在 3.4 版更改: 本類(lèi)現(xiàn)在支持使用
ssl.SSLContext.check_hostname
和 服務(wù)器名稱(chēng)指示 (參閱ssl.HAS_SNI
)進(jìn)行主機(jī)名檢查。在 3.9 版更改: 如果 timeout 參數(shù)設(shè)置為 0,創(chuàng)建非阻塞套接字時(shí),它將引發(fā)
ValueError
來(lái)阻止該操作。
- exception nntplib.NNTPError?
派生自標(biāo)準(zhǔn)異常
Exception
,這是nntplib
模塊中引發(fā)的所有異常的基類(lèi)。 該類(lèi)的實(shí)例具有以下屬性:
- exception nntplib.NNTPReplyError?
從服務(wù)器收到意外答復(fù)時(shí),將引發(fā)本異常。
- exception nntplib.NNTPTemporaryError?
收到 400--499 范圍內(nèi)的響應(yīng)代碼時(shí)所引發(fā)的異常。
- exception nntplib.NNTPPermanentError?
收到 500--599 范圍內(nèi)的響應(yīng)代碼時(shí)所引發(fā)的異常。
- exception nntplib.NNTPProtocolError?
當(dāng)從服務(wù)器收到不是以數(shù)字 1--5 開(kāi)頭的答復(fù)時(shí)所引發(fā)的異常。
- exception nntplib.NNTPDataError?
當(dāng)響應(yīng)數(shù)據(jù)中存在錯(cuò)誤時(shí)所引發(fā)的異常。
NNTP 對(duì)象?
當(dāng)連接時(shí),NNTP
和 NNTP_SSL
對(duì)象支持以下方法和屬性。
屬性?
方法?
作為幾乎全部方法所返回元組的第一項(xiàng)返回的 response 是服務(wù)器的響應(yīng):以三位數(shù)字代碼打頭的字符串。 如果服務(wù)器的響應(yīng)是提示錯(cuò)誤,則方法將引發(fā)上述異常之一。
以下方法中許多都接受一個(gè)可選的僅限關(guān)鍵字參數(shù) file。 當(dāng)提供了 file 參數(shù)時(shí),它必須為打開(kāi)用于二進(jìn)制寫(xiě)入的 file object,或要寫(xiě)入的磁盤(pán)文件名稱(chēng)。 此類(lèi)方法隨后將把服務(wù)器返回的任意數(shù)據(jù)(除了響應(yīng)行和表示結(jié)束的點(diǎn)號(hào))寫(xiě)入到文件中;此類(lèi)方法通常返回的任何行列表、元組或?qū)ο蠖紝榭罩怠?/p>
在 3.2 版更改: 以下方法中許多都已被重寫(xiě)和修正,這使得它們不再與 3.1 中的同名方法相兼容。
- NNTP.quit()?
發(fā)送
QUIT
命令并關(guān)閉連接。 一旦此方法被調(diào)用,NNTP 對(duì)象的其他方法都不應(yīng)再被調(diào)用。
- NNTP.getwelcome()?
返回服務(wù)器發(fā)送的歡迎消息,作為連接開(kāi)始的回復(fù)。(該消息有時(shí)包含與用戶(hù)有關(guān)的免責(zé)聲明或幫助信息。)
- NNTP.getcapabilities()?
返回服務(wù)器所聲明的 RFC 3977 功能,其形式為將功能名稱(chēng)映射到(可能為空的)值列表的
dict
實(shí)例。 在不能識(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ù)名和密碼。 如果 user 和 password 為None
且 usenetrc 為真值,則會(huì)在可能的情況下使用來(lái)自~/.netrc
的憑證。除非被有意延遲,登錄操作通常會(huì)在
NNTP
對(duì)象初始化期間被執(zhí)行因而沒(méi)有必要單獨(dú)調(diào)用此函數(shù)。 要強(qiáng)制延遲驗(yàn)證,你在創(chuàng)建該對(duì)象時(shí)不能設(shè)置 user 或 password,并必須將 usenetrc 設(shè)為 False。3.2 新版功能.
- NNTP.starttls(context=None)?
發(fā)送
STARTTLS
命令。 這將在 NNTP 連接上啟用加密。 context 參數(shù)是可選的且應(yīng)為ssl.SSLContext
對(duì)象。 請(qǐng)閱讀 安全考量 了解最佳實(shí)踐。請(qǐng)注意此操作可能不會(huì)在傳輸驗(yàn)證信息之后立即完成,只要有可能驗(yàn)證默認(rèn)會(huì)在
NNTP
對(duì)象初始化期間發(fā)生。 請(qǐng)參閱NNTP.login()
了解有關(guān)如何屏蔽此行為的信息。3.2 新版功能.
在 3.4 版更改: 此方法現(xiàn)在支持使用
ssl.SSLContext.check_hostname
和 服務(wù)器名稱(chēng)指示 (參見(jiàn)ssl.HAS_SNI
) 進(jìn)行主機(jī)名檢查。
- NNTP.newgroups(date, *, file=None)?
發(fā)送
NEWGROUPS
命令。 date 參數(shù)應(yīng)為datetime.date
或datetime.datetime
對(duì)象。 返回一個(gè)(response, groups)
對(duì),其中 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)或?yàn)?'*'
,而 date 與newgroups()
中的含義相同。 返回一個(gè)(response, articles)
對(duì),其中 articles 為消息 ID 列表。此命令經(jīng)常會(huì)被 NNTP 服務(wù)器管理員禁用。
- NNTP.list(group_pattern=None, *, file=None)?
發(fā)送
LIST
或LIST ACTIVE
命令。 返回一個(gè)(response, list)
對(duì),其中 list 是代表此 NNTP 服務(wù)器上所有可用新聞組的元組列表,并可選擇匹配模式字符串 group_pattern。 每個(gè)元組的形式為(group, last, first, flag)
,其中 group 為新聞組名稱(chēng),last 和 first 是最后一個(gè)和第一個(gè)文章的編號(hào),而 flag 通常為下列值之一:y
: 允許來(lái)自組員的本地發(fā)帖和文章。m
: 新聞組受到管制因而所有發(fā)帖必須經(jīng)過(guò)審核。n
: 不允許本地發(fā)帖,只允許來(lái)自組員的文章。j
: 來(lái)自組員的文章會(huì)被轉(zhuǎn)入垃圾分組。x
: 不允許本地發(fā)帖,而來(lái)自組員的文章會(huì)被忽略。=foo.bar
: 文章會(huì)被轉(zhuǎn)入foo.bar
分組。
如果 flag 具有其他值,則新聞組的狀態(tài)應(yīng)當(dāng)被視為未知。
此命令可能返回非常龐大的結(jié)果,特別是當(dāng)未指明 group_pattern 的時(shí)候。 最好是離線(xiàn)緩存其結(jié)果,除非你確實(shí)需要刷新它們。
在 3.2 版更改: 增加了 group_pattern。
- NNTP.descriptions(grouppattern)?
發(fā)送
LIST NEWSGROUPS
命令,其中 grouppattern 為 RFC 3977 中規(guī)定的 wildmat 字符串(它實(shí)際上與 DOS 或 UNIX shell 通配字符串相同)。 返回一個(gè)(response, descriptions)
對(duì),其中 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è)匹配結(jié)果。 如果未匹配到任何新聞組,則返回空字符串。
此方法略去了來(lái)自服務(wù)器的響應(yīng)代碼。 如果需要響應(yīng)代碼,請(qǐng)使用
descriptions()
。
- NNTP.group(name)?
發(fā)送
GROUP
命令,其中 name 為新聞組名稱(chēng)。 該新聞組如果存在,則會(huì)被選定為當(dāng)前新聞組。 返回一個(gè)元組(response, count, first, last, name)
,其中 count 是該新聞組中(估計(jì)的)文章數(shù)量,first 是新聞組中第一篇文章的編號(hào),last 是新聞組中最后一篇文章的編號(hào),而 name 是新聞組名稱(chēng)。
- 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)前文章。返回一個(gè)
(response, overviews)
對(duì)。 其中 overviews 是一個(gè)包含(article_number, overview)
元組的列表,每個(gè)元組對(duì)應(yīng) message_spec 所選定的一篇文章。 每個(gè) overview 則是包含同樣數(shù)量條目的字典,但具體數(shù)量取決于服務(wù)器。 這些條目或是為消息標(biāo)頭(對(duì)應(yīng)鍵為小寫(xiě)的標(biāo)頭名稱(chēng))或是為 metadata 項(xiàng)(對(duì)應(yīng)鍵為以":"
打頭的 metadata 名稱(chēng))。 以下條目會(huì)由 NNTP 規(guī)范描述來(lái)確保提供:subject
,from
,date
,message-id
和references
標(biāo)頭:bytes
metadata: 整個(gè)原始文章數(shù)據(jù)的字節(jié)數(shù)(包括標(biāo)頭和消息體):lines
metadata: 文章消息體的行數(shù)
每個(gè)條目的值或者為字符串,或者在沒(méi)有值時(shí)為
None
。建議在標(biāo)頭值可能包含非 ASCII 字符的時(shí)候?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
命令。 返回一個(gè)(response, list)
對(duì),其中 list 為幫助字符串列表。
- NNTP.stat(message_spec=None)?
發(fā)送
STAT
命令,其中 message_spec 為消息 ID (包裹在'<'
和'>'
中) 或者當(dāng)前新聞組中的文章編號(hào)。 如果 message_spec 被省略或?yàn)?None
,則會(huì)選擇當(dāng)前新聞組中的當(dāng)前文章。 反回一個(gè)三元組(response, number, id)
,其中 number 為文章編號(hào)而 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.article(message_spec=None, *, file=None)?
發(fā)送
ARTICLE
命令,其中 message_spec 的含義與stat()
中的相同。 返回一個(gè)元組(response, info)
,其中 info 是一個(gè)namedtuple
,包含三個(gè)屬性 number, message_id 和 lines (按此順序)。 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()
類(lèi)似,但會(huì)發(fā)送HEAD
命令。 返回的 lines (或?qū)懭氲?file) 將只包含消息標(biāo)頭,不包含消息體。
- NNTP.body(message_spec=None, *, file=None)?
與
article()
類(lèi)似,但會(huì)發(fā)送BODY
命令。 返回的 lines (或?qū)懭氲?file) 將只包含消息體,不包含標(biāo)頭。
- NNTP.post(data)?
使用
POST
命令發(fā)布文章。 data 參數(shù)是以二進(jìn)制讀取模式打開(kāi)的 file object,或是任意包含字節(jié)串對(duì)象的可迭代對(duì)象 (表示要發(fā)布的文章的原始行數(shù)據(jù))。 它應(yīng)當(dāng)代表一篇適當(dāng)格式的新聞組文章,包含所需的標(biāo)頭。post()
方法會(huì)自動(dòng)對(duì)以.
打頭的行數(shù)據(jù)進(jìn)行轉(zhuǎn)義并添加結(jié)束行。如果此方法執(zhí)行成功,將返回服務(wù)器的響應(yīng)。 如果服務(wù)器拒絕響應(yīng),則會(huì)引發(fā)
NNTPReplyError
。
- NNTP.ihave(message_id, data)?
發(fā)送
IHAVE
命令。 message_id 為要發(fā)給服務(wù)器的消息 ID (包裹在'<'
和'>'
中)。 data 形參和返回值與post()
的一致。
- NNTP.slave()?
發(fā)送
SLAVE
命令。 返回服務(wù)器的 響應(yīng)。
- NNTP.set_debuglevel(level)?
設(shè)置實(shí)例的調(diào)試級(jí)別。 它控制著打印調(diào)試輸出信息的數(shù)量。 默認(rèn)值
0
不產(chǎn)生調(diào)試輸出。 值1
產(chǎn)生中等數(shù)量的調(diào)試輸出,通常每個(gè)請(qǐng)求或響應(yīng)各產(chǎn)生一行。 大于等于2
的值產(chǎn)生最多的調(diào)試輸出,在連接上發(fā)送和接收的每一行信息都會(huì)被記錄下來(lái)(包括消息文本)。
以下是在 RFC 2980 中定義的可選 NNTP 擴(kuò)展。 其中一些已被 RFC 3977 中的新命令所取代。
- NNTP.xhdr(hdr, str, *, file=None)?
發(fā)送
XHDR
命令。 hdr 參數(shù)是標(biāo)頭關(guān)鍵字,例如'subject'
。 str 參數(shù)的形式應(yīng)為'first-last'
,其中 first 和 last 是要搜索的首篇和末篇文章編號(hào)。 返回一個(gè)(response, list)
對(duì),其中 list 是(id, text)
對(duì)的列表,其中 id 是文章編號(hào)(字符串類(lèi)型)而 text 是該文章的請(qǐng)求標(biāo)頭。 如果提供了 file 形參,則XHDR
命令的輸出會(huì)保存到文件中。 如果 file 為字符串,則此方法將打開(kāi)指定名稱(chēng)的文件,向其寫(xiě)入內(nèi)容并將其關(guān)閉。 如果 file 為 file object,則將在該文件對(duì)象上調(diào)用write()
方法來(lái)保存命令所輸出的行信息。 如果提供了 file,則返回的 list 將為空列表。
工具函數(shù)?
這個(gè)模塊還定義了下列工具函數(shù):
- nntplib.decode_header(header_str)?
解碼標(biāo)頭值,恢復(fù)任何被轉(zhuǎn)義的非 ASCII 字符。 header_str 必須為
str
對(duì)象。 將返回被恢復(fù)的值。 推薦使用此函數(shù)來(lái)以人類(lèi)可讀的形式顯示某些標(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'