python异步requests_Python异步Request操作: aiohttp

1. Tutorial

2. 其他库推荐

2.1. aiohttp-requests

这个库时对aiohttp库的网络请求模块的封装,用了这个库,在异步网络请求的时候,可以在写法上更简洁易懂。本质上还是aiohttp库的使用。推荐使用这个库来做网络请求。

2.2. aiofiles

aiofiles是一个用Python编写,用于处理asyncio应用程序中的本地磁盘文件。爬虫过程中用它来进行文件的异步操作。

2.3. grequests

grequests模块相当于是封装了gevent的requests模块。

3. 问题记录

3.1. Multipart.FormData 示例

下面示例展示上传图片至SM.MS。

with open(abspath_file, 'rb') as fp:

multipart_form_data = aiohttp.FormData(quote_fields=False) # quote_fields: 将对中文进行转码

multipart_form_data.add_field('smfile', fp,

content_type="image/jpeg",

filename=os.path.basename(relpath_file),

content_transfer_encoding="base64")

headers = {'Authorization': self.api_token} if self.api_token else None

# headers = {"Content-Type": "multipart/form-data"}

async with aiohttp.ClientSession() as session:

async with session.post(self.endpoint,

data=multipart_form_data,

headers=headers) as resp:

await resp.text()

str_response = await resp.text()

json_content = json.loads(str_response)

if not json_content['success']:

logger.error(json_content)

raise UploadError()

print(f"[+] 完成上传: {relpath_file}")

3.2. with open("xxx") 会被自动关闭

程序是这样的:

with open("xxx", "rb") as fp:

...

async with aiohttp.ClientSession() as session:

async with session.post(self.endpoint, data=fp) as resp:

await resp.text()

...

file_hash = hashlib.md5()

while chunk := fp.read(8192): # 这里报错:ValueError: read of closed file

file_hash.update(chunk)

return file_hash.hexdigest()

报错:ValueError: read of closed file

找到一篇相似的文章,解释不保证准确:

问题是open(...)返回一个文件对象,并且您要将同一文件对象传递给要start()在顶层创建的所有协程。恰好先调度的协程实例将文件对象session.post()作为的一部分传输data,session.post()并将读取文件到最后并关闭文件对象。下一个start()协程将尝试从现在关闭的对象中读取,这将引发异常。

要解决此问题而不多次打开文件,您需要确保实际将数据作为字节对象读取:

data = {'file': open('test_img.jpg', 'rb').read()}

这会将相同的字节对象传递给所有协程,它们应按预期工作。

3.3. filename中文错误

使用post方式,上传multipart到SM.MS时,图像存储没问题,但文件名从中文变成了诸如 %E9%B2%8D%E9%B.jpg 的样子……应该是编码问题。怎么避免呢?

multipart_form_data = aiohttp.FormData(quote_fields=False) # quote_fields: 将对中文进行转码

使用参数 quote_fields 将避免该问题。

3.4. aiohttp(yarl)对url部分字符自动urldecode

最新碰到一个用 aiohttp 访问不出内容,但是用 requests 能访问的情况,url 是事先进行了 urlencode 的, 下面的 url 随便找了个站点代替,但是把重点的参数提了出来

%40 对应的是 `@`

%3a 对应的是 `:`

解决方案:

str_url = "https://www.xxx.com?xxx%40yyy%3azzz"

proxy_url = "http://localhost:8080"

async with session.get(URL(str_url), proxy=proxy_url) as resp:

print(await resp.text())

async with session.get(URL(str_url, encoded=True), proxy=proxy_url) as resp:

print(await resp.text())

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值