zoukankan      html  css  js  c++  java
  • Python异步Request操作: aiohttp

    1. Tutorial

    homepage

    cnblog: aiohttp的使用

    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

    csdn

    github

    最新碰到一个用 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())
    
     
  • 相关阅读:
    MongoDB学习笔记(一:常见问题汇总)
    设计模式学习笔记(三:装饰模式)
    设计模式学习笔记(二:观察者模式)
    设计模式学习笔记(一:命令模式)
    Java基础知识笔记(七:接口、变量作用域和参数传递)
    Java基础知识笔记(六:网络程序设计)
    一周总结汇总_2016-09-25
    开涛spring3(8.1)
    开涛spring3(7.5)
    开涛spring3(7.4)
  • 原文地址:https://www.cnblogs.com/ExMan/p/14871284.html
Copyright © 2011-2022 走看看