pythonrequest请求下载csv文件保存_通过 python下载csv文件并保存成csv文件

直接上代码:

importrequestsimportcsvfrom contextlib importclosing#保存csv文件

defsave_csv(f_name, data):#1. 创建文件对象

f = open(f_name, ‘w‘, encoding=‘utf-8‘, newline=‘‘)#2. 基于文件对象构建 csv写入对象

csv_writer =csv.writer(f)#4. 写入csv文件内容

for row indata:

csv_writer.writerow(row)#5. 关闭文件

f.close()#下载csv文件

defget_pag():

url= ‘********‘

#读取数据

with closing(requests.get(url, stream=True)) as r:

f= (line.decode(‘utf-8‘) for line inr.iter_lines())

reader= csv.reader(f, delimiter=‘,‘, quotechar=‘"‘)

save_csv(f_name, reader)if __name__ == ‘__main__‘:

f_name= ‘123.csv‘reader= get_pag()

亮点来了:

contextlib.closing 这个库,学习了.

1、之前的我,只知道with会用来关闭文件,数据库资源,这很好。

只要实现了__enter__() 和 __exit__()这两个方法的类都可以轻松创建上下文管理器,就能使用with。

2、我打开两个数据库的时候,都是

with xxx as conn1:

with yyy as conn2:

code

真是蠢如老狗呀,其实可以:

with xxx as conn1, yyy as conn2:

code

3、总感觉离开了with block,语句体的资源(文件啊,数据库连接啊,网络请求呀)就会自动关闭。

可是有一天我看到contextlib.closing()。 一脸懵逼,有了with还要这个干嘛,这是我内心真实OS。。

from contextlib importclosingfrom urllib2 importurlopen

with closing(urlopen(‘http://www.python.org‘;)) as page:for line inpage:print(line)

先来否定我的想法,凡用with就万事大吉,自动帮我关闭。

classDoor(object):defopen(self):print ‘Door is opened‘

defclose(self):print ‘Door is closed‘with Door() as d:

d.open()

结果:

#报错:

Traceback (most recent call last):

File"1.py", line 38, in with Door() as d:

AttributeError:__exit__

果然呢,因为with语句体执行之前运行__enter__方法,在with语句体执行完后运行__exit__方法。

如果一个类如Door连这两个方法都没有,是没资格使用with的。

有些类,并没有上述的两个方法,但是有close(),能不能在不加代码的情况下,使用with呢?

可以:

classDoor(object):defopen(self):print ‘Door is opened‘

defclose(self):print ‘Door is closed‘with contextlib.closing(Door()) as door:

door.open()

结果:

Door isopened

Dooris closed

contextlib.closing(xxx),原理如下:

classclosing(object):"""Context to automatically close something at the end of a block.

Code like this:

with closing(.open()) as f:

is equivalent to this:

f = .open()

try:

finally:

f.close()"""

def __init__(self, thing):

self.thing=thingdef __enter__(self):returnself.thingdef __exit__(self, *exc_info):

self.thing.close()

这个contextlib.closing()会帮它加上__enter__()和__exit__(),使其满足with的条件。

5、是不是只有类才能享受with的便利呀? 我单单一个方法行不行?

行!既然认识了contextlib.closing(),必须认识下contextlib.contextmanager

这是一个装饰器,可以让一个func()变成一个满足with条件的类实例…

!!!这个func()必须是生成器…

yield前半段用来表示__enter__()

yield后半段用来表示__exit__()

from contextlib importcontextmanager

@contextmanagerdeftag(name):print("" %name)yield

print("%s>" %name)

with tag("h1"):print ‘hello world!‘

结果:

hello world!

Wow,这个还真的挺酷的,以后可以用这个contextmanager来实现一些装饰器才能做的事,

比如给一段代码加时间cost计算:

装饰器版本:

importtimedefwrapper(func):def new_func(*args, **kwargs):

t1=time.time()

ret= func(*args, **kwargs)

t2=time.time()print ‘cost time=‘, (t2-t1)returnretreturnnew_func

@wrapperdefhello(a,b):

time.sleep(1)print ‘a + b =‘, a+b

hello(100,200)

结果:

a + b = 300cost time= 1.00243401527

contextmanger版本:

from contextlib importcontextmanager

@contextmanagerdefcost_time():

t1=time.time()yieldt2=time.time()print ‘cost time=‘,t2-t1

with cost_time():

time.sleep(1)

a= 100b= 200

print ‘a + b =‘, a + b

结果:

a + b = 300cost time= 1.00032901764

当然还是用装饰器方便美观点啦~

这是contextmanager原理:

1、因为func()已经是个生成器了嘛,所以运行__enter__()的时候,contextmanager调用self.gen.next()会跑到func的yield处,停住挂起,这个时候已经有了t1=time.time()

2、然后运行with语句体里面的语句,也就是a+b=300

3、跑完后运行__exit__()的时候,contextmanager调用self.gen.next()会从func的yield的下一句开始一直到结束。这个时候有了t2=time.time(),t2-t1从而实现了统计cost_time的效果,完美。

源码:

classGeneratorContextManager(object):"""Helper for @contextmanager decorator."""

def __init__(self, gen):

self.gen=gendef __enter__(self):try:returnself.gen.next()exceptStopIteration:raise RuntimeError("generator didn‘t yield")def __exit__(self, type, value, traceback):if type isNone:try:

self.gen.next()exceptStopIteration:return

else:raise RuntimeError("generator didn‘t stop")else:if value isNone:#Need to force instantiation so we can reliably

#tell if we get the same exception back

value =type()try:

self.gen.throw(type, value, traceback)raise RuntimeError("generator didn‘t stop after throw()")exceptStopIteration, exc:return exc is notvalueexcept:if sys.exc_info()[1] is notvalue:raise

defcontextmanager(func):

@wraps(func)def helper(*args, **kwds):return GeneratorContextManager(func(*args, **kwds))return helper

原文:https://www.cnblogs.com/yuanyongqiang/p/12609852.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值