2025年4月19日 星期六

Python的requests與aiohttp筆記

只要是有研究過使用Python的爬蟲程式的話
這兩個應用名稱應該是熟到不行了
這次剛好先後用上,所以做個筆記

為什麼是先後呢?
因為之前某隻程式是用urllib3寫的
在問過AI後,得到這函式無法管理cookies
它推薦使用request裡的session進行連線與管理
並且在我輸入舊程式碼後,幫我替換掉舊的函式庫引入與寫法
太棒了,太懶人了
科技進步萬歲

使用requests裡session的流程很簡單
先建立headers準備騙伺服器說是瀏覽器的連線
再來就是要登入資料,使用者名稱,密碼
然後建立session並預先載入headers,這樣就不用每次傳資料還要載入
接著檢查有沒有上次cookies,有就載入
載入後,連線測試,如果成功,就跳出
如果失敗,就砍掉舊cookie,然後使用帳號密碼登入
登入後,確認成功就把cookies存下來
然後回報成功
確認登入後,接下來就可以取得裡面的網頁資料
然後丟到html parser裡面解析出想要的資料
程式碼的範本如下:

from bs4 import BeautifulSoup
import requests
import pickle
import os

headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"        
        }
        
# 請替換為實際網址
login_url="登入用網址"
target_url="目標網址"

# cookies 文件路徑
cookies_file = "cookies"

# 登入憑證(請替換為真實用戶名和密碼)
payload = {
    "Username": "使用者名稱",
    "Password": "密碼"        
}        

#建立session
session = requests.Session()
#將headers載入session中
session.headers.update(headers)

try:
    # 檢查 cookies 文件是否存在
    if os.path.exists(cookies_file):
        print("找到 cookies 文件,嘗試讀取 cookies")
        with open(cookies_file, "rb") as f:
            session.cookies.update(pickle.load(f))
        print(f"Cookies 已從 {cookies_file} 讀取")
        # 進一步檢查讀取cookies後可否登入
        # 如果前面session沒有用update(headers),這邊get就要補, headers=headers)
        response = session.get(target_url)
        if not (response.status_code == 200):
            #清除session的cookies
            session.cookies.clear()
            #刪除cookies檔案
            os.remove(cookies_file)      
        
    if not os.path.exists(cookies_file):
        print("未找到 cookies 文件,執行登入")
        # 執行登入
        # 如果前面沒有用update(headers),這邊post還要補, headers=headers)
        response = session.post(login_url, data=payload)
        if not (response.status_code == 200):
            raise Exception("初始登入失敗,程式終止")
        # 保存 cookies
        with open(cookies_file, "wb") as f:
            pickle.dump(session.cookies, f)
        print(f"Cookies 已保存到 {cookies_file}")
    
    # 正式讀取目標網頁
    # 如果前面session沒有用update(headers),這邊get就要補, headers=headers)
    response = session.get(target_url)
    # 把網頁丟入解析器中
    parser = BeautifulSoup(response.text, "html.parser")
    
except Exception as e:
    print(f"發生錯誤:{e}")

是不難,而且請AI替換超快的,根本不用我動手
同時,它還會教我一些應用與注意事項
現在學程式真方便啊
不過,問AI還是沒有百分之百正確
上面是沒問題的
可是延著這個對話再問下去,它就給了錯誤的答案了

我有另一個工具程式也是用urllib3寫
然後當時是用異步的寫法下去運作的
所以我就問AI,那異步應用上使用requests的寫法
(其實,我試過原寫法直接替換就可以用了,不過我還是好奇問一下)
然後AI就推了aiohttp這個異步專用的函式庫
並說明,因為原生就使用異步會比使用非異步寫法的requests好,所以建議替換掉
好吧,要換就換,反正是AI換
但是替換時就出問題了
原本requests的cookies,之前範例是用pickle函式庫儲存,然後用update_cookies讀取
然後aiohttp照抄用pickle儲存時就出問題了
pickle在dump這個cookie_jar時,因為格式不對,所以不給存,產生了一個空檔案
而讀取時,雖然不確定正常能不能成功,但這裡絕對失敗,因為讀了一個空的檔案
唉~~果然不能全信
直接用google查aiohttp裡cookie_jar的API,原來自己就有save與load功能
靠,那還用什麼pickle,直接cookie_jar.load(PATH)跟cookie_jar.save(PATH)就好
所以上面的程式碼用aiohttp改寫後正確版本如下:

from bs4 import BeautifulSoup
import aiohttp
#import pickle #不需要pickle了
import os
import asyncio #導入異步用函式庫

async def main():
    headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
            }
            
    # 請替換為實際網址
    login_url="登入用網址"
    target_url="目標網址"

    # cookies 文件路徑
    cookies_file = "cookies"

    # 登入憑證(請替換為真實用戶名和密碼)
    payload = {
        "Username": "使用者名稱",
        "Password": "密碼"        
    }        

    #建立session,並將headers載入session中
    async with aiohttp.ClientSession(headers=headers) as session:
        try:
            # 檢查 cookies 文件是否存在
            if os.path.exists(cookies_file):
                print("找到 cookies 文件,嘗試讀取 cookies")
                session.cookie_jar.load(cookies_file)
                print(f"Cookies 已從 {cookies_file} 讀取")
                # 進一步檢查讀取cookies後可否登入
                # 如果前面沒有引入headers,這邊get還要補, headers=headers)
                async with session.get(target_url) as response:
                    if not (response.status == 200):
                        #清除session的cookies
                        session.cookie_jar.clear()
                        #刪除cookies檔案
                        os.remove(cookies_file)
                
            if not os.path.exists(cookies_file):
                print("未找到 cookies 文件,執行登入")
                # 執行登入
                # 如果前面沒有引入headers,這邊post還要補, headers=headers)
                async with session.post(login_url, data=payload) as response:
                    if not (response.status == 200):
                        raise Exception("初始登入失敗,程式終止")
                # 保存 cookies
                session.cookie_jar.save(cookies_file)
                print(f"Cookies 已保存到 {cookies_file}")
            
            # 正式讀取目標網頁
            # 如果前面沒有引入headers,這邊get還要補, headers=headers)
            async with session.get(target_url) as response:
                # 使用response.text()讀取網頁內谷
                html_content = await response.text()
                # 把網頁丟入解析器中
                parser = BeautifulSoup(html_content, "html.parser")
            
        except Exception as e:
            print(f"發生錯誤:{e}")

# 使用異步執行程式
asyncio.get_event_loop().run_until_complete(main())

現在AI寫程式真的超方便的
有一個陳年老計畫看來可以挖出來實現了
雖然現在已經沒有當年的實值效益了
不過至少懸掛多年的待辦清單可以再清掉一項
不,應該說再完成一項,自己DIY的東西
真期待之後完成的那一天

沒有留言: