def use_NNTP(): for server in NNTP_server_list: print server server = raw_input('Which NNTP_server do you want to go?\n') while True: if server not in NNTP_server_list: print 'invalid srever name,try again!' server = raw_input() else: break s = NNTP(server) print "s = NNTP('news.newsfan.net') is OK!" (resp, lst) = s.list() while True: for i, elem in enumerate(lst): print i, elem[0].decode('gbk') num = raw_input('Which group do you want to go?\n') try: rsp, ct, first, last, grp = s.group(lst[int(num)][0]) print "Article's range is:%s to %s." % (first, last) (resp, subs) = s.xhdr('subject', (str(first) + '-' + str(last))) except: print format_exc() print 'invalid input!try again!!!' sleep(3) continue for subject in subs: try: print subject[0], subject[1].decode('gbk') except: print subject[0], subject[1] while True: try: number = raw_input('Which article do you want to read?\n') if number == 'q': break f = open("NNTPfile", 'w') (reply, num, id, list) = s.body(str(number), f) f = open("NNTPfile", 'r') for eachLine in f: try: print eachLine.decode('gbk'), except: print eachLine f.close() print 'Press any to continue...(Press q to return...)' if raw_input() == 'q': break except: print format_exc() print 'invalid input!try again!!!' sleep(3) s.quit() return
def main(): s = NNTP(settings.nntp_hostname, settings.nntp_port) resp, groups = s.list() # check all of the groups, just in case for group_name, last, first, flag in groups: resp, count, first, last, name = s.group(group_name) print "\nGroup", group_name, 'has', count, 'articles, range', first, 'to', last resp, subs = s.xhdr('subject', first + '-' + last) for id, sub in subs[-10:]: print id, sub s.quit()
def download_group(name): if not os.path.exists(name): os.mkdir(name) s = NNTP('news.gmane.org') resp, count, first, last, name = s.group(name) print 'Group', name, 'has', count, 'articles, range', first, 'to', last resp, subs = s.xhdr('subject', first + '-' + last) for id, sub in subs: print id with open(os.path.join(name, str(id)), 'wb') as fp: pprint.pprint(s.article(id), stream=fp)
def getItems(self): server = NNTP(self.servername) (resp, count, first, last, name) = server.group(self.group) (resp, subs) = server.xhdr('subject', (str(first) + '-' + str(last))) for subject in subs[-10:]: title = subject[1] (reply, (num, id, list)) = server.body(subject[0]) # list是一个列表,但是是bytes编码的,需要把每一个元素都解码成string body = [] #print(list) for l in list: body.append(l.decode('gbk')) # 注意,这里用utf-8解码会出现解码错误 #print(body) body = ''.join(body) yield NewsItem(title, body) server.quit()
def getItems(self): server = NNTP(self.servername) (resp, count, frist, last, name) = server.group(self.group) (resp, subs) = server.xhdr('subject', (str(frist) + '-' + (last))) for subject in subs[-10:]: title = subject[1] (reply, num, id, list) = server.body(subject[0]) body = ''.join(list) #print(num) #186919 #print(title) #Re: Find out which module a class came from #print(''.join(list))#prano wrote:> But for merely ordinary obfuscation caused by poor... yield NewsItem(title, body) server.quit()
def getItems(self): server = NNTP(self.servername) _, count, first, last, name = server.group(self.group) _, subs = server.xhdr( 'subject', (str(first) + '-' + str(last))) for sub in subs[:10]: # default last ten id = sub[0] lines = server.article(id)[3] message = message_from_string('\n'.join(lines)) title = message['subject'] body = message.get_payload() if message.is_multipart(): body = body[0] yield NewsItem(title, body) server.quit()
def getItems(self): """ 书中原例getItems()方法 返回 nntplib.NNTPTemporaryError: 480 NEWNEWS command disabled by administrator #480管理员禁用NEWNEWS命令 def getItems(self): start = localtime(time() - self.window*day) date = strftime('%y%m%d', start) hour = strftime('%H%M%S', start) server = NNTP(self.servername) ids = server.newnews(self.group, date, hour)[1] for id in ids: lines = serverarticle(id)[3] message = message_from_string('\n'.join(lines)) title = message['subject'] body = message.get_payload() if message.is_multipat(): body = body[0] yield NewsItem(title, body) server.quit() """ server = NNTP(self.servername) (resp, count, frist, last, name) = server.group(self.group) (resp, subs) = server.xhdr('subject', (str(frist) + '-' + (last))) for subject in subs[-10:]: title = subject[1] (reply, num, id, list) = server.body(subject[0]) body = ''.join(list) #print(num) #186919 #print(title) #Re: Find out which module a class came from #print(''.join(list))#prano wrote:> But for merely ordinary obfuscation caused by poor... yield NewsItem(title, body) server.quit()
class NewsGrep: def __init__(self,server,username,password): self.server = NNTP(server, 119,username,password) def __del__(self): pass def __str__(self): pass def list(self): resp, groups = self.server.list() for group, last, first, flag in groups: print group def ls(self,group_name): resp, count, first, last, name = self.server.group(group_name) print 'Group', name, 'has', count, 'articles, range', first, 'to', last resp, subs = self.server.xhdr('subject', first + '-' + last) for id, sub in subs[-10:]: print id, sub
class NewsGrep: def __init__(self, server, username, password): self.server = NNTP(server, 119, username, password) def __del__(self): pass def __str__(self): pass def list(self): resp, groups = self.server.list() for group, last, first, flag in groups: print group def ls(self, group_name): resp, count, first, last, name = self.server.group(group_name) print 'Group', name, 'has', count, 'articles, range', first, 'to', last resp, subs = self.server.xhdr('subject', first + '-' + last) for id, sub in subs[-10:]: print id, sub
showcount = int(showcount) except: servername = 'news.gmane.org' groupname = 'gmane.comp.python.general' # cmd line args or defaults showcount = 10 # show last showcount posts # connect to nntp server print 'Connecting to', servername, 'for', groupname from nntplib import NNTP connection = NNTP(servername) (reply, count, first, last, name) = connection.group(groupname) print '%s has %s articles: %s-%s' % (name, count, first, last) # get request headers only fetchfrom = str(int(last) - (showcount-1)) (reply, subjects) = connection.xhdr('subject', (fetchfrom + '-' + last)) # show headers, get message hdr+body for (id, subj) in subjects: # [-showcount:] if fetch all hdrs print 'Article %s [%s]' % (id, subj) if not listonly and raw_input('=> Display?') in ['y', 'Y']: reply, num, tid, list = connection.head(id) for line in list: for prefix in showhdrs: if line[:len(prefix)] == prefix: print line[:80]; break if raw_input('=> Show body?') in ['y', 'Y']: reply, num, tid, list = connection.body(id) for line in list: print line[:80] print
class DownloadSpots(object): def __init__(self): try: self.news = NNTP(NEWS_SERVER, NNTP_PORT, NNTP_USERNAME, NNTP_PASSWORD) except NNTPTemporaryError as e: raise SpotError('NNTP', e) except socket.error as e: raise SpotError('Connection', e) self.conn = sqlite3.connect(NEWS_SERVER + '.db') self.conn.row_factory = sqlite3.Row self.cur = self.conn.cursor() self.cur.executescript('''\ PRAGMA synchronous = OFF; PRAGMA journal_mode = MEMORY; PRAGMA temp_store = MEMORY; PRAGMA count_changes = OFF; ''') def __del__(self): print 'quit!' if hasattr(self, 'news'): self.news.quit() if hasattr(self, 'cur'): self.cur.close() if hasattr(self, 'conn'): self.conn.close() def make_table(self): sql = '''\ CREATE TABLE IF NOT EXISTS spots ( id int PRIMARY KEY, full_id str, cat int, title str, poster str, date int, size int, erotiek int, subcats str, modulus int, keyid int, c_count int ); CREATE TABLE IF NOT EXISTS comments ( id int PRIMARY KEY, full_id str, spot_full_id str ); CREATE INDEX IF NOT EXISTS spots_full_id_index on spots(full_id); ''' self.cur.executescript(sql) self.conn.commit() def download_detail(self, id): '''Get information about a spot. Args: id (int/string): the nntp id of the spot. Can be: - a short id: 123456 - a long id: '*****@*****.**' Returns: a dict with the following keys: - nzb: a list of nntp id's of the nzb file - image: the location of the image file: url or nntp id - website: url of the website - desc: a description of the spot - title2: the title of the spot (is called title2 to avoid a conflict) ''' id = str(id) self.news.group('free.pt') print id head = self.news.head(id)[-1] xmltext = ''.join(item[7:] for item in head if item.startswith('X-XML:')) xml = etree.XML(xmltext) xmldict = defaultdict(list) xmldict['nzb'] = [i.text for i in xml.find('.//NZB').iter('Segment')] imgfind = xml.find('.//Image') if imgfind is not None: if imgfind.find('.//Segment') is not None: xmldict['image'] = imgfind.find('.//Segment').text else: xmldict['image'] = imgfind.text else: xmldict['image'] = None webfind = xml.find('.//Website') if webfind is not None: xmldict['website'] = webfind.text else: xmldict['website'] = None xmldict['desc'] = bb2html('\n'.join(self.news.body(id)[-1])) xmldict['title2'] = xml.find('.//Title').text print xmldict return xmldict def download_image(self, article, imgnr): '''Download and save an image file. Args: article: Location of the file, can be: - None - an url: 'http://url.to.image.ext' - a nntp id: '*****@*****.**' imgnr: filename of the saved image ''' print imgnr file = 'temp/%s.picture' % imgnr if article is None: shutil.copy('none.png', file) elif article.startswith('http'): if 'imgchili.com' in article: article = re.sub(r't([0-9]\.imgchili)', r'i\1', article) try: print urllib.urlretrieve(article, file) except: print 'Image download error' shutil.copy('none.png', file) elif '@' in article: article = '<%s>' % article print article try: self.news.group('alt.binaries.ftd') data = ''.join(self.news.body(article)[-1]) except NNTPTemporaryError as e: shutil.copy('none.png', file) raise SpotError('NNTP', e) else: data = data.replace('=A', '\x00').replace('=B', '\r') \ .replace('=C', '\n').replace('=D', '=') with open(file, 'wb') as f: f.write(data) else: shutil.copy('none.png', file) def download_nzb(self, articles, title): '''Download and save a nzb file. Args: articles: a list of nntp id's: ['*****@*****.**'] title (string): the filename of the saved nzb file (must be already escaped) ''' print 'download_nzb' file = 'temp/%s.nzb' % title self.news.group('alt.binaries.ftd') print articles data = ''.join(''.join(self.news.body('<%s>' % article)[-1]) for article in articles) data = data.replace('=A', '\x00').replace('=B', '\r') \ .replace('=C', '\n').replace('=D', '=') data = zlib.decompress(data, -zlib.MAX_WBITS) with open(file, 'wb') as f: f.write(data) def update_spots(self): '''Download new spots and save them to the database. Yields: total: total amount of spots to be downloaded subtotal: amount of spots already done ''' print 'Opening database...', self.make_table() self.cur.execute('SELECT count(id) FROM spots') oude_lengte = self.cur.fetchone()[0] print 'Done' print oude_lengte, 'spots in database' print 'Connecting...', last = int(self.news.group('free.pt')[3]) print 'Done' if oude_lengte: self.cur.execute('SELECT max(id) FROM spots') current = self.cur.fetchone()[0] else: current = last - (NR_OF_SPOTS * 100) delta = 2000 total = last - current print 'Current:', current print 'Last:', last print total, 'spots op te halen' yield total if current >= last: print 'Geen nieuwe spots!' yield 'end' return print 'Getting new spots...', self.cur.execute('DROP INDEX IF EXISTS spots_full_id_index') self.conn.commit() for i in xrange(0, total, delta): for (id, subject), (id, fromline), (id, full_id) in \ zip(*(self.news.xhdr(header, '%s-%s' % (current + 1 + i, current + delta + i))[-1] for header in ('subject', 'from', 'Message-ID'))): subject = re.sub('^[\t]', '', subject).split('\t')[0] if subject[:7] == 'DISPOSE': continue subject = subject.decode('latin-1') fromline = fromline.decode('latin-1') subject = re.sub('\s\|\s\w+$', '', subject) poster = re.sub('(\t[^\t]+\t)?([^\s]+)\s<.+$', r'\2', fromline) try: info = re.findall(r'<[^>]+>', fromline)[0].split('@') modulus = info[0] info = info[1].split('.')[:4] date = info[3] except IndexError: continue if info[0][1] == '7': modulus = modulus.split('.')[0][1:] else: modulus = 0 subcats = '|'.join(info[0][2:][x:x + 3] for x in xrange(0, len(info[0][2:]), 3)) erotiek = 0 if info[0][0] == '1': for genre in re.findall('d[0-9]{2}', subcats): if ((23 <= int(genre[1:]) <= 26) or (72 <= int(genre[1:]) <= 89)): erotiek = 1 break sql = ('INSERT INTO spots (id, full_id, cat, title, poster, date, ' 'size, erotiek, subcats, modulus, keyid, c_count) ' 'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)') self.cur.execute(sql, (id, full_id, info[0][0], subject, poster, date, info[1], erotiek, subcats, modulus, info[0][1])) self.conn.commit() yield int(id) - current # subtotal self.cur.execute('CREATE INDEX spots_full_id_index on spots(full_id)') self.conn.commit() print 'Spots klaar!' self.cur.execute('SELECT count(id) FROM spots') lengte = self.cur.fetchone()[0] print lengte - oude_lengte, 'nieuwe spots!' self.news.quit() yield 'end' def update_comments(self): '''Download new comments and save them to the database. Yields: total: total amount of comments to be downloaded subtotal: amount of comments already done ''' print 'comments' print 'Opening database...', self.make_table() self.cur.execute('SELECT count(id) FROM comments') oude_lengte = self.cur.fetchone()[0] print 'Done' print oude_lengte, 'comments in database' print 'Connecting...', last = int(self.news.group('free.usenet')[3]) print 'Done' if oude_lengte: self.cur.execute('SELECT max(id) FROM comments') current = self.cur.fetchone()[0] print current else: current = last - (NR_OF_SPOTS * 500) delta = 2000 total = last - current print 'Current:', current print 'Last:', last print total, 'comments op te halen' yield total if current >= last: print 'Geen nieuwe comments!' yield 'end' return print 'begin reacties', time.time() for i in xrange(0, total, delta): for (id, ref), (id, msgid) in \ zip(*(self.news.xhdr(header, '%s-%s' % (current + 1 + i, current + delta + i))[-1] for header in ('References', 'Message-ID'))): self.cur.execute('INSERT INTO comments VALUES (?, ?, ?)', (id, msgid, ref)) self.cur.execute('UPDATE spots SET c_count = c_count + 1 WHERE full_id = ?', (ref,)) yield int(id) - current # subtotal self.conn.commit() print 'Reacties klaar' self.cur.execute('SELECT count(id) FROM comments') lengte = self.cur.fetchone()[0] print lengte - oude_lengte, 'nieuwe comments!' self.news.quit() yield 'end' def show(self, search_col, op, search, search_rest='', limit=NR_OF_SPOTS, columns='*'): '''Perform a sql query. Args: search_col: the column to use in the where clause op: the operator to use in the where clause search: the search value to use in the where clause search_rest: additional conditions for the where clause limit: the number of rows to select columns: the columns to select Returns: a list of tuples with the results of the sql query ''' self.make_table() sql = '''\ SELECT %s FROM spots WHERE %s %s :search %s ORDER BY id DESC LIMIT %s ''' % (columns, search_col, op, search_rest, limit) results = map(Spot, self.cur.execute(sql, (search,))) print len(results) return results
''' '''-----------------------------------------------------------------------------------------------------------''' # 原文连接 http://www.ynpxrz.com/n1039057c2023.aspx http://www.jb51.net/article/65708.htm from nntplib import NNTP server = NNTP('web.aioe.org') #server = NNTP('news.gmane.org') (resp, count, frist, last, name) = server.group('comp.lang.python') #3211 3691 182837 186527 comp.lang.python -- 3691 --82837 --186527-- 3691 (resp,subs) = server.xhdr('subject', (str(frist) + '-' + str(last))) #print(resp, '----', subs) # NNTP.xhdr(hdr,str,*,file = None )xhdr命令 hdr是标题关键字例如主题 # str是文章编号的的起始和终点位置编号 格式'first-last' 返回响应元组 Return a pair (response, list) #其中list是对(id,text)的列表,其中id是文章编号,文本是该文章所请求的标题的文本 # 221 Header or metadata information for subject follows (from overview) #---- [('182841', 'Re: compile error when using override'), .... ##输出后十个文章ID和文章标题 for subject in subs[-10:]: print(subject) number = input('Which article do you want to read?') (reply, num, id, lists) = server.body(str(number)) #python3 会出现 错误#ValueError: not enough values to unpack (expected 4, got 2)
#!/usr/local/bin/python3 from nntplib import NNTP server = NNTP('news.aioe.org') resp, count, first, last, name = server.group('sci.logic') print('Group', name, 'has', count, 'articles, range', first, 'to', last) resp, subs = server.xhdr('subject', str(first) + '-' + str(last)) for id, text in subs[-10:]: print(id, text) server.quit()
showcount = int(showcount) except: servername = 'news.rmi.net' groupname = 'comp.lang.python' # cmd line args or defaults showcount = 10 # show last showcount posts # connect to nntp server print 'Connecting to', servername, 'for', groupname from nntplib import NNTP connection = NNTP(servername) (reply, count, first, last, name) = connection.group(groupname) print '%s has %s articles: %s-%s' % (name, count, first, last) # get request headers only fetchfrom = str(int(last) - (showcount-1)) (reply, subjects) = connection.xhdr('subject', (fetchfrom + '-' + last)) # show headers, get message hdr+body for (id, subj) in subjects: # [-showcount:] if fetch all hdrs print 'Article %s [%s]' % (id, subj) if not listonly and raw_input('=> Display?') in ['y', 'Y']: reply, num, tid, list = connection.head(id) for line in list: for prefix in showhdrs: if line[:len(prefix)] == prefix: print line[:80]; break if raw_input('=> Show body?') in ['y', 'Y']: reply, num, tid, list = connection.body(id) for line in list: print line[:80] print
import nntplib from nntplib import NNTP s = NNTP('news.gmane.org') resp, count, first, last, name = s.group('gmane.comp.python.committers') print ('Group', name, 'has', count, 'articles, range', first, 'to', last) resp, subs = s.xhdr('subject',first) for id, sub in subs[-10:]: print (id, sub) try : for id, sub in subs[-10:]: print (id, sub) except TypeError as e: print(e) print(s.quit()) # NNTP.
class Client(Context): def __init__(self, log, hostname, port=None, username=None, password=None, *, debuglevel=None, **timeout): self.log = log self.hostname = hostname self.port = port self.username = username self.password = password self.debuglevel = debuglevel self.timeout = timeout Context.__init__(self) self.connect() def connect(self): address = net.format_addr((self.hostname, self.port)) self.log.write("Connecting to {}\n".format(address)) if self.port is None: port = () else: port = (self.port,) self.connect_time = time.monotonic() self.nntp = NNTP(self.hostname, *port, **self.timeout) with ExitStack() as cleanup: cleanup.push(self) if self.debuglevel is not None: self.nntp.set_debuglevel(self.debuglevel) self.log.write("{}\n".format(self.nntp.getwelcome())) if self.username is not None: self.log.write("Logging in as {}\n".format(self.username)) with self.handle_abort(): self.nntp.login(self.username, self.password) self.log.write("Logged in\n") cleanup.pop_all() def body(self, id, *pos, **kw): id = "<{}>".format(id) retry = 0 while True: try: with self.handle_abort(): self.nntp.body(id, *pos, **kw) break except failure_responses as err: [code, *msg] = err.response.split(maxsplit=1) if code == "400": [msg] = msg or (None,) if not msg: msg = "Server shut down connection" elif code[1] == "0" and not retry: msg = err.response else: raise self.log.write(msg + "\n") self.log_time() if retry >= 60: raise TimeoutError() self.close() time.sleep(retry) if not retry: start = time.monotonic() self.connect() if retry: retry *= 2 else: retry = time.monotonic() - start if retry <= 0: retry = 0.5 def group(self, *pos, **kw): with self.handle_abort(): return self.nntp.group(*pos, **kw) def over(self, *pos, **kw): with self.handle_abort(): return self.nntp.over(*pos, **kw) def hdr(self, *pos, **kw): with self.handle_abort(): return self.nntp.xhdr(*pos, **kw) @contextmanager def handle_abort(self): try: yield except failure_responses: raise # NNTP connection still intact except: # Protocol is disrupted so abort the connection straight away self.close() raise def close(self): if not self.nntp: return # Ignore failure of inappropriate QUIT command with suppress(NNTPError), self.nntp: pass self.nntp = None def log_time(self): # TODO: time duration formatter self.log.write("Connection lasted {:.0f}m\n".format((time.monotonic() - self.connect_time)/60))
# ids = server.newnews(group, date,hour)[1] # 该方法有问题 # for id in ids: # print(id) # head = server.head(id)[3] # for line in head: # if line.lower().startswith('subject:'): # subjucet = line[9:] # break # body = server.body(id)[3] # # print(subjucet) # print('-' * len(subjucet)) # print('\n'.join(body)) servername = 'web.aioe.org' group = 'comp.lang.python.announce' server = NNTP(servername) (resp, count, first, last, name) = server.group(group) (resp, subs) = server.xhdr('subject', (str(first) + '-' + (last))) for subject in subs[-10:]: title = subject[1] (reply, num, id, list) = server.body(subject[0]) body = ''.join(list) print(num) #186919 print(title) #Re: Find out which module a class came from print( ''.join(list) ) #prano wrote:> But for merely ordinary obfuscation caused by poor... server.quit()
from nntplib import NNTP s = NNTP('web.aioe.org') (resp, count, first, last, name) = s.group('comp.lang.python') (resp, subs) = s.xhdr('subject', (str(first) + '-' + str(last))) for subject in subs[-10:]: print subject number = input('Which article do you want to read? ') (reply, num, id, list) = s.body(str(number)) for line in list: print line
class Client(Context): def __init__(self, log, hostname, port=None, username=None, password=None, *, debuglevel=None, **timeout): self.log = log self.hostname = hostname self.port = port self.username = username self.password = password self.debuglevel = debuglevel self.timeout = timeout Context.__init__(self) self.connect() def connect(self): address = net.format_addr((self.hostname, self.port)) self.log.write("Connecting to {}\n".format(address)) if self.port is None: port = () else: port = (self.port, ) self.connect_time = time.monotonic() self.nntp = NNTP(self.hostname, *port, **self.timeout) with ExitStack() as cleanup: cleanup.push(self) if self.debuglevel is not None: self.nntp.set_debuglevel(self.debuglevel) self.log.write("{}\n".format(self.nntp.getwelcome())) if self.username is not None: self.log.write("Logging in as {}\n".format(self.username)) with self.handle_abort(): self.nntp.login(self.username, self.password) self.log.write("Logged in\n") cleanup.pop_all() def body(self, id, *pos, **kw): id = "<{}>".format(id) retry = 0 while True: try: with self.handle_abort(): self.nntp.body(id, *pos, **kw) break except failure_responses as err: [code, *msg] = err.response.split(maxsplit=1) if code == "400": [msg] = msg or (None, ) if not msg: msg = "Server shut down connection" elif code[1] == "0" and not retry: msg = err.response else: raise self.log.write(msg + "\n") self.log_time() if retry >= 60: raise TimeoutError() self.close() time.sleep(retry) if not retry: start = time.monotonic() self.connect() if retry: retry *= 2 else: retry = time.monotonic() - start if retry <= 0: retry = 0.5 def group(self, *pos, **kw): with self.handle_abort(): return self.nntp.group(*pos, **kw) def over(self, *pos, **kw): with self.handle_abort(): return self.nntp.over(*pos, **kw) def hdr(self, *pos, **kw): with self.handle_abort(): return self.nntp.xhdr(*pos, **kw) @contextmanager def handle_abort(self): try: yield except failure_responses: raise # NNTP connection still intact except: # Protocol is disrupted so abort the connection straight away self.close() raise def close(self): if not self.nntp: return # Ignore failure of inappropriate QUIT command with suppress(NNTPError), self.nntp: pass self.nntp = None def log_time(self): # TODO: time duration formatter self.log.write("Connection lasted {:.0f}m\n".format( (time.monotonic() - self.connect_time) / 60))
#!/usr/bin/env python # Copyright (c) 2004 Joao Prado Maia. See the LICENSE file for more information. # $Id: check_health.py,v 1.1 2004-01-25 06:10:33 jpm Exp $ import settings from nntplib import NNTP s = NNTP(settings.nntp_hostname, settings.nntp_port) resp, groups = s.list() # check all of the groups, just in case for group_name, last, first, flag in groups: resp, count, first, last, name = s.group(group_name) print "\nGroup", group_name, 'has', count, 'articles, range', first, 'to', last resp, subs = s.xhdr('subject', first + '-' + last) for id, sub in subs[-10:]: print id, sub s.quit()