文章目录
常用内建函数(续)
itertools操作迭代对象
import itertools
#无限打印自然数
natuals = itertools.count(1)
for n in natuals:
print(n)
#无限打印输入序列
cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
for c in cs:
print(c)
#指定打印三次
ns = itertools.repeat('A', 3)
for n in ns:
print(n)
#使用takewhile来限定范围
natuals = itertools.count(1)
ns = itertools.takewhile(lambda x: x <= 10, natuals)
list(ns)
一些常用迭代操作函数
chain()串联作用
chain()可以把一组迭代对象串联起来,形成一个更大的迭代器
groupby()
groupby()把迭代器中相邻的重复元素挑出来放在一起,可以消除重复元素。
for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):
print(key, list(group))
...
A ['A', 'a', 'a']
B ['B', 'B', 'b']
C ['c', 'C']
A ['A', 'A', 'a']
作业:计算π
def pi(N):
' 计算pi的值 '
# step 1: 创建一个奇数序列: 1, 3, 5, 7, 9, ...
qi = itertools.count(1,2)
# step 2: 取该序列的前N项: 1, 3, 5, 7, 9, ..., 2*N-1.
qu = itertools.takewhile(lambda x:x<=2*N-1,qi)
# step 3: 添加正负符号并用4除: 4/1, -4/3, 4/5, -4/7, 4/9, ...
qu_list = [4/x*(-1)**(idx%2) for idx,x in enumerate(list(qu))]
#step3第二种
qu_list = [4/x*(-1)**((x+1)/2-1) for x in qu]
# step 4: 求和:
return sum(qu_list)
contextlib操作文件资源
主要是通过with作为一个上下文管理器。
@contextmanager
def transaction(db):
db.begin()
try:
yield
except:
db.rollback()
raise
else:
db.commit()
with transaction(mydb):
mydb.cursor.execute(sql)
mydb.cursor.execute(sql)
mydb.cursor.execute(sql)
mydb.cursor.execute(sql)
with执行过程:
执行 context_expression,生成上下文管理器 context_manager
调用上下文管理器的__enter__() 方法;如果使用了 as 子句,则将__enter__() 方法的返回值赋值给 as 子句中的 target(s)
执行语句体 with-body
不管是否执行过程中是否发生了异常,执行上下文管理器的__exit__() 方法__exit__() 方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句 break/continue/return,则以 None 作为参数调用__exit__(None, None, None) ;如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用__exit__(exc_type, exc_value, exc_traceback)
出现异常时,如果__exit__(type, value, traceback) 返回 False,则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理
https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/index.html?mhsrc=ibmsearch_a&mhq=%E4%B8%8A%E4%B8%8B%E6%96%87%20Python
本体http://www.cnblogs.com/nnnkkk/p/4309275.html
urllib操纵url
urllib提供的功能就是利用程序去执行各种HTTP请求。
如果要模拟浏览器完成特定功能,需要把请求伪装成浏览器。
伪装的方法是先监控浏览器发出的请求,再根据浏览器的请求头来伪装,User-Agent头就是用来标识浏览器的。
from urllib import request
req = request.Request('http://www.douban.com/')
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', f.read().decode('utf-8'))
更复杂的可以通过post和handle去访问。
作业:解析url json并转换
from urllib import request
import json
def fetch_data(url):
with request.urlopen(str(url)) as f:
return json.loads(f.read().decode('utf-8'))
return None
XML类似json
操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件。
champhy_hu大佬的实例
from xml.parsers.expat import ParserCreate
#利用SAX解析XML文档牵涉到两个部分: 解析器和事件处理器
#解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件。
#而事件处理器则负责对事件作出响应,对传递的XML数据进行处理
class DefualtSaxHandler(object):
def start_element(self,name,attrs):
print('sax:start_elment: %s,attrs: %s'%(name,str(attrs)))
#name表示节点名称,attrs表示节点属性(字典)
def end_element(self,name):
print('sax:end_element: %s'%name)
def char_data(self,text):
print('sax:char_data: %s'%text)
#text表示节点数据
xml=r'''<?xml version="1.0"?>
<ol>
<li><a href="/python">Python</a></li>
<li><a href="/ruby">Ruby</a></li>
</ol>
'''
#处理器实例
handler=DefualtSaxHandler()
#解析器实例
parser=ParserCreate()
#下面3为解析器设置自定义的回调函数
#回调函数的概念,请搜索知乎,见1.9K赞的答案
parser.StartElementHandler=handler.start_element
parser.EndElementHandler=handler.end_element
parser.CharacterDataHandler=handler.char_data
#开始解析XML
parser.Parse(xml)
#然后就是等待expat解析,
#一旦expat解析器遇到xml的 元素开始,元素结束,元素值 事件时
#会回分别调用start_element, end_element, char_data函数
#关于XMLParser Objects的方法介绍下
#详见python文档:xml.parsers.expat
#xmlparser.StartElementHandler(name, attributes)
#遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典
#xmlparser.EndElementHandler(name)
#遇到XML结束标签时调用。
#xmlparser.CharacterDataHandler(data)
#调用时机:
#从行开始,遇到标签之前,存在字符,content 的值为这些字符串。
#从一个标签,遇到下一个标签之前, 存在字符,content 的值为这些字符串。
#从一个标签,遇到行结束符之前,存在字符,content 的值为这些字符串。
#标签可以是开始标签,也可以是结束标签。
#为了方便理解,我已经在下面还原来解析过程,
#标出何时调用,分别用S:表示开始;E:表示结束;D:表示data
如果看不明白,请配合脚本输出结果一起看
S<ol>C
C S<li>S<a href="/python">CPython</a>E</li>EC
C S<li>S<a href="/ruby">CRuby</a>E</li>EC
S</ol>E
作业:写一个可以输出天气的api
'''练习:
请利用SAX编写程序解析XML格式的天气预报,获取天气预报:
功能:获取北京市所有地区的当天天气预报信息——(地区名:{当日天气状态:’‘,最高温度:’‘,最低温度})
'''
# -*- coding:utf-8 -*-
from xml.parsers.expat import ParserCreate # 引入xml解析模块
from urllib import request # 引入URL请求模块
class WeatherSaxHandler(object): # 定义一个天气事件处理器
weather ={'city':1,'cityname':[], 'forecast':[]} # 初始化城市city和预报信息forecast
def start_element(self, name, attrs): # 定义开始标签处理事件
if name=='beijing':
self.weather['city']='北京'
if name == 'city': # 获取location信息
self.weather['cityname'].append(attrs['cityname']) #获取地区名
# 获取forecast信息
self.weather['forecast'].append({
'state':attrs['stateDetailed'],
'high':attrs['tem2'],
'low':attrs['tem1']
})
def parseXml(xml_str): # 定义xml解析器
handler = WeatherSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.Parse(xml_str) # 解析xml文本
print('City'+handler.weather['city'])
for (x,y) in zip(handler.weather['cityname'],handler.weather['forecast']): # 打印天气信息
print('Region:'+x)
print(y)
return handler.weather
# 测试:
URL = 'http://flash.weather.com.cn/wmaps/xml/beijing.xml'
with request.urlopen(URL, timeout=4) as f:
data = f.read()
result = parseXml(data.decode('utf-8'))
'''结果
City北京
Region:延庆
{'state': '晴', 'high': '7', 'low': '-7'}
Region:密云
{'state': '晴', 'high': '9', 'low': '-6'}
Region:怀柔
{'state': '晴', 'high': '10', 'low': '-6'}
Region:昌平
{'state': '晴', 'high': '9', 'low': '-1'}
Region:平谷
{'state': '晴', 'high': '8', 'low': '-5'}
Region:顺义
{'state': '晴', 'high': '10', 'low': '0'}
Region:门头沟
{'state': '晴', 'high': '10', 'low': '-2'}
Region:海淀
{'state': '晴', 'high': '11', 'low': '-2'}
Region:朝阳
{'state': '晴', 'high': '10', 'low': '-1'}
Region:石景山
{'state': '晴', 'high': '11', 'low': '-2'}
Region:市中心
{'state': '晴', 'high': '9', 'low': '-2'}
Region:丰台
{'state': '晴', 'high': '10', 'low': '-2'}
Region:房山
{'state': '晴', 'high': '9', 'low': '-4'}
Region:大兴
{'state': '晴', 'high': '9', 'low': '-4'}
Region:通州
{'state': '晴', 'high': '9', 'low': '-2'}
'''
HTMLParser
如果我们要编写一个搜索引擎,第一步是用爬虫把目标网站的页面抓下来,第二步就是解析该HTML页面,看看里面的内容到底是新闻、图片还是视频。
解析HTML就要用到HTMLParser
# -*-coding:UTF-8-*-
from html.parser import HTMLParser
from urllib.request import Request,urlopen
import re
def get_data(url):
'''
GET请求到指定的页面
:return: HTTP响应
'''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36'
}
req = Request(url, headers=headers)
with urlopen(req, timeout=25) as f:
data = f.read()
print(f'Status: {f.status} {f.reason}')
print()
return data.decode("utf-8")
class MyHTMLParser(HTMLParser):
def __init__(self):
super().__init__()
self.__parsedata='' # 设置一个空的标志位
self.info = []
def handle_starttag(self, tag, attrs):
if ('class', 'event-title') in attrs:
self.__parsedata = 'name' # 通过属性判断如果该标签是我们要找的标签,设置标志位
if tag == 'time':
self.__parsedata = 'time'
if ('class', 'say-no-more') in attrs:
self.__parsedata = 'year'
if ('class', 'event-location') in attrs:
self.__parsedata = 'location'
def handle_endtag(self, tag):
self.__parsedata = ''# 在HTML 标签结束时,把标志位清空
def handle_data(self, data):
if self.__parsedata == 'name':
# 通过标志位判断,输出打印标签内容
self.info.append(f'会议名称:{data}')
if self.__parsedata == 'time':
self.info.append(f'会议时间:{data}')
if self.__parsedata == 'year':
if re.match(r'\s\d{4}', data): # 因为后面还有两组 say-no-more 后面的data却不是年份信息,所以用正则检测一下
self.info.append(f'会议年份:{data.strip()}')
if self.__parsedata == 'location':
self.info.append(f'会议地点:{data} \n')
def main():
parser = MyHTMLParser()
URL = 'https://www.python.org/events/python-events/'
data = get_data(URL)
parser.feed(data)
for s in parser.info:
print(s)
if __name__ == '__main__':
main()
#第二种
from html.parser import HTMLParser
from urllib import request
class MyHTMLParser(HTMLParser):
def __init__(self):
super().__init__()
self.flag = 0 # 状态 1:目标标签 0:不是目标标签
def handle_starttag(self, tag, attrs):
if tag == 'h3' and ('class', 'event-title') in attrs: # 筛选会议名称
self.flag = 1
elif tag == 'time' and 'datetime' in attrs[0]: # 筛选会议时间
self.flag = 1
elif tag == 'span' and ('class', 'event-location') in attrs: # 筛选会议地点
self.flag = 1
def handle_data(self, data):
if self.flag:
print(data)
self.flag = 0 # 还原状态
with request.urlopen('https://www.python.org/events/python-events/') as f:
data = f.read().decode('utf-8')
parser = MyHTMLParser()
parser.feed(data)
本文深入探讨Python的内建函数,包括itertools的chain()与groupby(),contextlib上下文管理器在文件资源操作中的应用,urllib如何操纵URL以及XML与JSON的关联,最后介绍了HTMLParser解析HTML的基本用法。通过实例解析和作业,帮助读者更好地理解和掌握这些工具。
1万+

被折叠的 条评论
为什么被折叠?



