python核心编程笔记——因特网客户端编程(二)

本文介绍Usenet新闻系统及网络新闻传输协议NNTP的基本原理,探讨Python中nntplib库的应用,演示如何使用NNTP类进行新闻组的交互,并提供示例代码展示如何在实际项目中下载和解析新闻组内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值