ps:我的python環境爲3.6.2
網絡新聞
usenet和新聞組
. usenet新聞系統是一個由大量計算機組成的龐大的全球網絡,計算機之間共享 Usenet 上的帖子。如果某個用戶發了一個帖子到本地的 Usenet 計算機上,這個帖子會被傳播到其他相連的計算機上,再由這些計算機傳到與它們相連的計算機上,直到這個帖子傳播到了全世界,每個人都收到這個帖子爲止。帖子在 Usenet 上的存活時間是有限的,這個時間可以由 Usenet系統管理員來指定,也可以爲帖子指定一個過期的日期/時間。
每個系統都有一個已“訂閱”的新聞組列表,系統只接收感興趣的新聞組裏的帖子,而不是接收服務器上所有新聞組的帖子。Usenet 新聞組的內容由提供者安排,很多服務都是公開的。但也有一些服務只允許特定用戶使用,例如付費用戶等。
網絡新聞傳輸協議
. 用戶使用網絡新聞傳輸協議(NNTP)在新聞組中下載或發表帖子。NNTP 與 FTP 的操作方式相似,但更簡單。在FTP 中,登錄、傳輸數據和控制需要使用不同的端口,而 NNTP 只使用一個標準端口 119 來通信。用戶向服務器發送一個請求,服務器就做出相應的響應。
Python與NNTP
. 有了FTP的經驗,可以猜出有一個nntplib庫和一個需要實例化的nntplib.NNTP類,其流程與FTP也非常相似:
1.連接到服務器;
2.登錄(根據需要);
3.發出服務器請求;
4.退出。
下面是一段python的僞代碼:
from nntplib import NNTP
n = NNTP('your.nntp.server')
r,c,f,l,g = n.group('comp.lang.python')
...
n.quit()
. 一般來說登錄後需要調用一個group方法來選擇感興趣的新聞組。該方法返回服務器的回覆、文章的數量、第一篇和最後一篇文章的ID、新聞組的名稱。
nntplib.NNTP 類方法
. 下表中列出了常用的一些關於NNTP類的方法:
方法 | 描述 |
---|---|
group(name) | 選擇一個組的名字,返回一個元組(rsp,ct,fst,lst,group),分別表示服務器響應信息、文章數量、第一個和最後一個文章的編號、組名,所有數據都是字符串。(返回的 group 與傳進去的 name 應該是相同的) |
xhdr(hdr, artrg[, ofile]) | 返回文章範圍 artrg(“頭 -尾”的格式)內文章 hdr 頭的列表,或把數據輸出到文件 ofile 中 |
body(id=None, *, file=None) | 根據 id 獲取文章正文,id 可以是消息的 ID(放在尖括號裏),也可以是文章編號(以字符串形式表示),返回一個元組(response, info),分別表示服務器響應信息和一個名爲info的元祖,info包括了number-文章編號(以字符串形式表示)、message_id-消息 ID(放在尖括號裏)、lines-文章所有行的列表(只有正文),或把數據輸出到文件 ofile 中 |
head(id=None, *, file=None) | 與 body()類似,返回相同的元組,只是返回的行列表中只包括文章標題 |
article(id=None, *, file=None) | 同樣與 body()類似,返回相同的元組,只是返回的行列表中同時包括文章標題和正文 |
stat(id) | 讓文章的“指針”指向 id(即前面的消息 ID 或文章編號)。返回一個與 body()相似的元組(rsp, anum,mid),但不包含文章的數據 |
next() | 用法和 stat()類似,把文章指針移到下一篇文章,返回與 stat()相似的元組 |
last() | 用法和 stat()類似,把文章指針移到最後一篇文章,返回與 stat()相似的元組 |
post(ufile) | 上傳 ufile 文件對象裏的內容(使用 ufile.readline()),併發布到當前新聞組中 |
quit() | 關閉連接並退出 |
交互式NNTP示例
. 可以在python的IDLE中直接連接NNTP服務器,長時間不操作貌似會斷掉,還有就是我實在不知道怎麼去看一個NNTP服務器上的組名,即使在瀏覽器上登錄了服務器也不知道咋看,我嘗試通過newgroups函數將一部分組信息列舉出來,但並不知道其名字和瀏覽器界面上的有什麼關係:
>>> from nntplib import NNTP
>>> from datetime import date,timedelta
>>> n = NNTP('web.aioe.org')
>>> resp,groups = n.newgroups(date.today() - timedelta(days = 300))
>>> len(groups)
234
>>> groups[0]
GroupInfo(group='a2i.ba.jobs.offered.hivol', last='37', first='26', flag='y')
>>> rsp,ct,fst,lst,grp = n.group('a2i.ba.jobs.offered.hivol')
>>> rsp,info = n.article('27')
>>> for eachLine in info.lines:
print(eachLine)
. 調用newgroups()那行代碼表示這300天來新添加的組,形式爲:
newgroups(date, *, file=None) ;
其參數應該是date或datetime對象,結果可以用循環打印出來看看(確實不知道啥意思)。
客戶端程序NNTP示例
. 在下面的示例中做了更復雜的工作,在之前的服務器中下載內容並且顯示有效的前20行:
import nntplib
import socket
Host = 'web.aioe.org'
Grnm = 'comp.lang.python'
def main():
try:
n = nntplib.NNTP(Host)
except socket.gaierror as e:
print('無法連接 "%s"' % Host)
print(' ("%s")' % eval(str(e))[1])
return
except nntplib.NNTPPermanentError as e:
print('服務器拒絕訪問')
print(' ("%s")' % str(e))
return
print('連接成功')
try:
rsp,ct,fst,lst,grp = n.group(Grnm)
except nntplib.NNTPTemporaryError as ee:
print('找不到組名 "%s"' % Grnm)
print(' ("%s")' % str(e))
n.quit()
return
print('找到新聞組')
rng = '%s-%s' % (lst-1,lst-1)
rsp,frm = n.xhdr('from',rng)
rsp,sub = n.xhdr('subject',rng)
rsp,dat = n.xhdr('date',rng)
print('''找到最新的文章 (#%s):
From: %s
subject: %s
Date: %s
''' % (lst,frm[0][1],sub[0][1],dat[0][1]))
rsp,info = n.body(lst)
displayFirst20(info.lines)
n.quit()
def displayFirst20(data):
print('前20行:\n')
count = 0
lines = (line.rstrip() for line in data)
lastBlank = True
for line in lines:
if line:
lower = line.lower().decode('utf-8')
if(lower.startswith('>') and not \
lower.startswith('>>>')) or \
lower.startswith('|') or \
lower.startswith('in article') or \
lower.endswith('writes:') or \
lower.endswith('wrote:'):
continue
if not lastBlank or (lastBlank and line):
print(' %s' % line.decode('utf-8'))
if line:
count += 1
lastBlank = False
else:
lastBlank = True
if count == 20:
break
if __name__ == '__main__':
main()