iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Python

一些Python可以做的事系列 第 19

[Python] 自動簽到微博超話

  • 分享至 

  • xImage
  •  

今天要使用作天的自動登入微博做延伸,目的是可以一次性的簽到所有微博超話

基本流程包括兩個主要部分:

  1. 使用已保存的 Cookies 進行登入 ( requests ) 並執行簽到。
  2. 如果 Cookies 不存在,使用 Selenium 進行自動登入並保存 Cookies。

詳細步驟 :

  1. 設置瀏覽器選項
    • 程式首先設置 Chrome 瀏覽器的一些選項 : 隱藏通知,禁用保存密碼功能,讓瀏覽器運行得更平穩,避免一些自動化工具檢測的問題。
  2. 初始化 CookieLogin
    • 創建一個 CookieLogin 物件,這個物件用來加載和保存你的 Cookies。這樣你就可以保持登入狀態,不需要每次都重新登入。
  3. 獲取超話列表
    • 程式會去微博上發送一個請求,獲取你關注的超話列表。拿到超話列表後,程式會把每個超話的標題和 ID 提取出來,存在一個字典裡。
  4. 構建簽到請求的 URL
    • 為了進行簽到,程式會根據微博簽到接口的要求構建一個特定的請求 URL。這個 URL 包含 : 如超話 ID(指定要簽到的超話)、操作狀態(如“簽到”或“已簽到”)、請求的上下文(比如所處的頁面部分)、用戶環境(包括時區、語言、操作系統平台和用戶代理)以及一個隨機數(防止請求被緩存)。這些信息確保了服務器能正確處理你的簽到請求。
      https://ithelp.ithome.com.tw/upload/images/20240826/20168345D34Po4fk1k.png
  5. 執行簽到操作
    • 用剛才構建的 URL 發送簽到請求。如果請求成功,程式會根據回應消息來確認簽到是否成功。成功或失敗的結果會顯示出來。
    • 當微博服務器返回以下格式的回應:
      https://ithelp.ithome.com.tw/upload/images/20240826/20168345CHgp3Frzlr.png
      這表示以下幾點:
    1. code: 382004
      • 這是一個狀態代碼,表示簽到的結果。382004 是特定的代碼,用於指示某種特定的狀態或錯誤。這裡它表示用戶今天已經完成簽到。
    2. msg: "今天已签到(382004)"
      • 這是一條文字消息,告知用戶簽到的結果。"今天已签到(382004)" 表示用戶已經在當天完成了簽到,並且不需要再次簽到。消息中的數字 382004 是對應的狀態代碼。
    3. data: []
      • 這是返回的數據部分,通常包含與請求相關的詳細數據。在這個情況下,它是一個空的數組,表示沒有額外的數據需要返回。
    這個回應告訴我們簽到操作已經被認識為已完成,並且今天不需要再次進行簽到。
  6. 使用 Cookies 進行請求
    • 如果程式找到了之前保存的 Cookies,就會使用這些 Cookies 來進行請求。這樣可以免去重新登錄的麻煩。程序會設置一些頭信息,然後使用 requests 進行網頁請求。
    • 使用 BeautifulSoup 解析網頁內容,提取用戶名等信息。然後,程式會遍歷超話列表,對每個超話進行簽到。
  7. 如果 Cookies 不存在,使用 Selenium 進行登入
    • 如果找不到 Cookies,程式會啟動 Selenium 自動化工具,打開微博登錄頁面,讓用戶掃描二維碼完成登錄。登入成功後,程式會保存這些 Cookies,以後就可以直接使用。

總結

這段程式碼幫你自動在微博上簽到超話。如果之前有保存的 Cookies,它就用這些 Cookies 直接簽到。如果沒有,它會用 Selenium 自動幫你登入,並保存新的 Cookies 以便下次使用。

程式碼

import json
from bs4 import BeautifulSoup
import requests
from selenium import webdriver
from time import sleep
from cookies import CookieLogin

# 設置 Chrome 瀏覽器的選項
prefs = {
    'profile.default_content_setting_values': {
        'notifications': 2  # 隱藏 Chrome 瀏覽器的通知
    },
    'credentials_enable_service': False,  # 禁用 Chrome 瀏覽器的保存密碼功能
    'profile.password_manager_enabled': False  # 禁用 Chrome 瀏覽器的保存密碼功能
}

# 初始化 Chrome 瀏覽器選項
options = webdriver.ChromeOptions()
options.add_experimental_option('prefs', prefs)  # 設置 Chrome 的偏好設定
options.add_experimental_option('excludeSwitches', ['enable-automation'])  # 禁用 Chrome 的自動化檢測顯示,設置為開發者模式
options.add_argument('--disable-gpu')  # 禁用 GPU 加速,避免可能的錯誤

cookie_fname = 'cookie.json'  # 保存 Cookies 的文件名
login = CookieLogin(cookie_fname)  # 創建 CookieLogin 對象,用於處理 Cookies 的加載和保存

def get_super_topic_list(session):
    """
    獲取微博超話列表
    :param session: 已登錄的 requests Session 對象
    :return: 包含超話標題和 ID 的字典
    """
    list_url = "https://weibo.com/ajax/profile/topicContent?tabid=231093_-_chaohua"
    response = session.get(list_url)  # 發送 GET 請求以獲取超話列表
    json_data = json.loads(response.text)  # 將響應文本解析為 JSON 格式

    # 提取 JSON 中的超話列表數據
    topics = json_data.get('data', {}).get('list', [])
    map = {}  # 初始化一個空字典來存儲超話標題和 ID
    for topic in topics:
        title = topic.get('title', 'N/A')  # 提取超話標題,默認為 'N/A'
        link = topic.get('link', 'N/A')  # 提取超話鏈接,默認為 'N/A'
        # 找到鏈接中最後一個斜杠的位置
        last_slash_index = link.rfind("/")
        # 獲取最後一個斜杠之後的所有字符,即超話 ID (唯一)
        id = link[last_slash_index + 1:] if last_slash_index != -1 else link
        map[title] = id  # 將超話標題和 ID 添加到字典中

    return map  # 返回包含超話標題和 ID 的字典

def construct_sign_url(value):
    """
    構建簽到請求的 URL
    :param value: 超話 ID
    :return: 完整的簽到請求 URL
    """
    base_url = "https://weibo.com/p/aj/general/button"  # 請求的基礎 URL
    params = {
        "ajwvr": "6",  # AJAX 請求版本號
        "api": "http://i.huati.weibo.com/aj/super/checkin",  # 簽到的 API 地址
        "texta": "%E7%AD%BE%E5%88%B0",  # "签到" 的 URL 編碼
        "textb": "%E5%B7%B2%E7%AD%BE%E5%88%B0",  # "已签到" 的 URL 編碼
        "status": "0",  # 請求狀態
        "id": value,  # 超話 ID,從 get_super_topic_list 函數獲得
        "location": "page_100808_super_index",  # 請求位置,表示超話頁面的索引位置
        "timezone": "GMT+0800",  # 時區設置
        "lang": "zh-cn",  # 語言設置
        "plat": "Win32",  # 平台設置
        "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",  # 用戶代理字符串
        "screen": "2048*1152",  # 螢幕解析度
        "__rnd": "1720793419490"  # 隨機數,用於防止緩存
    }

    # 將參數字典轉換為 URL 查詢字符串
    query_string = '&'.join(f"{key}={value}" for key, value in params.items())

    # 組合完整的 URL
    full_url = f"{base_url}?{query_string}"
    return full_url

def sign(key, value, session):
    """
    簽到超話
    :param key: 超話標題
    :param value: 超話 ID
    :param session: 已登錄的 requests Session 對象
    :return: 簽到是否成功的標誌(1 表示成功,0 表示失敗)
    """
    sign_url = construct_sign_url(value)  # 根據超話 ID 構建簽到請求的 URL
    response = session.get(sign_url)  # 發送簽到請求
    rep = response.text.encode("utf-8")  # 以 UTF-8 編碼響應文本
    rep = json.loads(rep)  # 將編碼後的響應文本解析為 JSON 格式
     # 根據響應中的 code 和 msg 字段來判斷簽到結果
    if rep.get('msg') == "今天已签到(382004)":
        print(key + " 今天已經簽到過")
        return 0  # 返回 0 表示簽到失敗(已簽到過)
    elif rep.get('code') == 0 and rep.get('msg') == "签到成功":
        print(key + " 簽到成功")
        return 1  # 返回 1 表示簽到成功
    else:
        print(key + " 簽到結果未知")
        return -1  # 返回 -1 表示簽到結果未知或遇到錯誤

# 檢查是否已保存 Cookies
cookies = login.load_cookies()
if cookies:
    print("使用保存的 Cookies 進行請求")
    # 使用 requests 進行請求
    session = requests.Session()  # 創建一個新的 requests Session 對象
    for cookie in cookies:
        # 設置每個 cookie,指定 name, value 和 domain
        session.cookies.set(cookie['name'], cookie['value'], domain=cookie['domain'])

    # 設置請求的 headers
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
    })

    # 發送請求以檢查是否能成功加載頁面
    url = "https://s.weibo.com/weibo?q=%E6%96%B0%E5%86%A0%E7%96%AB%E6%83%85"
    response = session.get(url)

    # 使用 BeautifulSoup 解析頁面內容
    soup = BeautifulSoup(response.text, 'html.parser')

    # 提取用戶名(假設用戶名在頁面的某個特定位置,可以用 BeautifulSoup 查找)
    try:
        # 假設用戶名在某個特定的 HTML 元素中
        user_info = soup.find('script', string=lambda t: t and 'var $CONFIG' in t)
        if user_info:
            # 從 script 標籤中提取用戶名
            script_content = user_info.string
            start_index = script_content.find('nick') + 10  # 定位 'nick' 之後的起始位置
            end_index = script_content.find(';', start_index)  # 定位 ';' 之前的位置
            nick = script_content[start_index:end_index].strip().strip("'")  # 提取用戶名並去除多餘的引號
            print(f"用戶名: {nick}")
        else:
            print("未能找到用戶名")
    except Exception as e:
        print(f"提取用戶名時出錯: {e}")

    # 獲取超話列表
    map = get_super_topic_list(session)

    # 簽到超話
    success = 0  # 成功簽到的數量
    fail = 0  # 失敗簽到的數量
    for key in map:
        if sign(key, map[key], session):
            success += 1  # 如果簽到成功,增加成功計數
        else:
            fail += 1  # 如果簽到失敗,增加失敗計數
    print("===========+++++++++++===========")
    print("共{}個超話,簽到成功{}個,失敗{}個".format(len(map), success, fail))

else:
    print("Cookies 不存在,使用 Selenium 進行登入")

    # 使用 Selenium 進行登入
    wd = webdriver.Chrome(options=options)  # 初始化 Chrome 瀏覽器
    url = "https://passport.weibo.com/sso/signin?entry=miniblog&source=miniblog&disp=popup&url=https%3A%2F%2Fweibo.com%2Fnewlogin%3Ftabtype%3Dweibo%26gid%3D102803%26openLoginLayer%3D0%26url%3Dhttp%253A%252F%252Fmcn.weibo.com%252Fintroduce"
    wd.get(url=url)  # 打開登錄頁面

    sleep(20)  # 等待 20 秒以便用戶掃描二維碼進行登錄

    # 保存 Cookies 到本地
    cookies = wd.get_cookies()
    login.save_cookies(cookies)  # 保存 cookies,以便下次使用

    wd.close()  # 關閉瀏覽器
    wd.quit()  # 結束瀏覽器進程

資料來源 :
python爬虫实现微博超话自动签到


上一篇
[Python] 自動登入微博
系列文
一些Python可以做的事19
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言