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())


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM