図書館のWeChat公式アカウントに席取りに行ってみた【Python編】

初心者がほとんどなので、ここで一旦考えを整理して、第10回更新まで飛ばさせていただきます!

荷物をキャプチャして席を確保するための最初のアップデート

まずレンダリングを見てみましょう (最初に興味のある部分が完全にコード化されます)
ここに画像の説明を挿入します


本校では少し前に学校のサーバーにシステムを導入したのでアドレスはここには載せませんが、そのアイデアについて簡単にお話しましょう。

前に書いた内容:
① コードは非常にシンプルで、要望だけです、後ほど最適化していきます まず要望をお話しますと、
<1> 全自動座席取得を実現し、毎日定時取得を開始します図書館開館時
<2> 開館効果を達成するために人間よりも速いため、今後最適化する必要があります。このブログはリクエストリクエストを送信しただけで、タイムスタンプなどを追加していなかったので、これは② プロセス中に複数のリクエストが避けられないため、アンチクライミングや IP ブロックを避けるために
後の段階でプロキシ プールなどを追加する必要があります (ただし、教師が本当にあなたに干渉したいのです、彼は間違いなくあなたの情報を持っています、だからみんな急いでください)これは最初は無視できます、このプログラムはこの種の問題を引き起こしません 条件

アイデア:
① Python のリクエスト ライブラリを使用して get/post リクエストを送信します。get または post を使用するかどうかは、全員が自分でパケットをキャプチャして分析する必要があります。 ② パケット キャプチャ ソフトウェアとして Fiddler を使用します。 ③ 携帯電話を
Fiddlerに接続する
必要があります。ヘッダー データクッキーなどの投稿パラメーター(2 回目の更新は携帯電話 PC WeChat を取得しなくても解決できます!)最後のステップは、投稿リクエストを送信するコードを記述することです。落とし穴: 1. Cookie を取得するには携帯電話のリクエストを使用するのが最善です。PC で WeChat を使用して予約をとりますが、結果は構文エラーになります。私が正しく理解できなかった可能性もあります。その後、携帯電話の Cookie が使用可能になったとき、PC では再度試しませんでした。セルフテストをしてみましょう。後でテストすると、 (2 回目の更新でPC 側を解決できます) 2. get/post について楽観的に考えてください。リクエストと送信されたデータは json または他の形式ですか? 3. 暴力的なリクエストの場合は、プロキシ プールを追加する必要があります。ブロックされたらダメです。
ここに画像の説明を挿入します




コードをアップロードします(具体的には、状況に応じてパケットをキャプチャして分析できます。システムごとに異なります。ここではアイデアについてのみ説明します)

import json
import time

import requests

header = {
    
    
    'Host': 'xxxx',
    'Connection': 'keep-alive',
    'Content-Length': '',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x6309001c) XWEB/6763',
    'Content-Type': '',
    'Accept': '*/*',
    'X-Requested-With': '',
    'Origin': '',
    'Sec-Fetch-Site': '',
    'Sec-Fetch-Mode': '',
    'Sec-Fetch-Dest': '',
    'Referer': '',
    'Accept-Encoding': '',
    'Accept-Language': 'zh-CN,zh',
    'Cookie': 'xxxx'
}
url = 'xxxx'
data = \
    {
    
    "operationName": "reserveSeat",
     "query": "mutation reserveSeat($libId: Int!, $seatKey: String!, $captchaCode: String, $captcha: String!) {\n userAuth {\n reserve {\n reserveSeat(\n libId: $libId\n seatKey: $seatKey\n captchaCode: $captchaCode\n captcha: $captcha\n )\n }\n }\n}",
     "variables": {
    
    "seatKey": "35,18", "libId": 525, "captchaCode": "", "captcha": ""}}
res = requests.post(url=url, headers=header, json=data)
tm = res.elapsed.total_seconds()# 获取请求时间
print(tm)
print(res.status_code)
print(res.text)

2 回目の更新: 2023 年 4 月 28 日 (更新され、指定された時間に座席取得のタイムスタンプが追加されました)

今回は、秒単位の精度で指定された時間に基づいて座席を取得するようにプログラムが更新されました。
テスト後、PC クライアントは WeChat を使用して公式アカウントにログインし、Cookie を取得します。取得された Cookie は有効です。これにより、面倒な作業が省かれます。」携帯電話を使用して席を確保する手順。素晴らしいですね。✌

# -----------------------------正题--------------------------------
struct_openTime = "2023-4-28 17:20:00"
openTime = time.strptime(struct_openTime, "%Y-%m-%d %H:%M:%S")
openTime = time.mktime(openTime)
request_cnt = 0
while True:
    # nowTime = int(time.mktime(time.localtime()))
    print(time.time(), openTime)
    if time.time() >= openTime:
        # print(nowTime, openTime,time.time())
        print("------------------------------")
        print(time.time(), openTime)
        print("ok Try to grab seat!")
        grab_time = time.localtime(time.time())
        ts = time.strftime("%Y-%m-%d %H:%M:%S", grab_time)
        print('当前时间是: ' + ts)
        request_cnt += 1
        res = requests.post(url=url, headers=header, json=data3)
        tm = res.elapsed.total_seconds()
        print(tm)
        print(res.status_code)
        print(res.text)
        # break
        if str(res.text).count("true"):
            print("恭喜你!抢座成功!程序即将结束......")
            break
        else:
            time.sleep(0.2)
        print("------------------------------\n\n")
    if request_cnt >= 5:  # 防止请求过多 被老师XX 所以这里我只敢 “最多” 请求5次
        break  # 另一个作用是避免图书馆服务器有延迟 加上上面的sleep 延迟时间可以控制在 5*0.2s = 1s 内 而且避免了过多的请求(程序1秒内发送的请求是很可怕的数量)
print("程序结束成功!")

この写真はテスト開始時に撮影したスクリーンショットです。プログラム全体のスクリーンショットはありません。ただし、プログラムは使用できます。時間があれば後で追加します。
ここに画像の説明を挿入します

2023年5月9日 第3回更新(遅延時間テスト成功事例を更新)

今回は実戦で遭遇する問題点とその解決方法についてお話します。
プログラムを書いて練習してみると、学校のサーバーに遅延があることが分かり、以前設定したsleep(0.2) * 5 = 1sでは要件を満たしていなかったため、sleep(0.3) * 10 = 3sに変更しました。結果は非常にスムーズで、実際の戦闘中に学校のサーバーに合わせてスケールすることができます。さらに、今日は手動ハンドスピードとプログラムグラブもテストしましたが、結果は基本的にプログラムに殺されました...

落とし穴:
① Cookie の適時性に注意してください。Cookie は一定期間内に期限切れになるため、再度取得する必要があります。どのくらいの頻度で期限切れになるかわかりません (30 分程度で期限切れになります)。席に着くたびに最新の Cookie が表示されます。ジワンでこれについて説明しているセクションを見つけたようです。確認したら更新します... ② サーバーが
遅延しています。数回テストしてください。 . または、長時間プレイしてcをタップすれば大丈夫です。

ここに画像の説明を挿入します
ここで遅延があったので一度失敗しましたが、10回リクエストするように設定し、成功する限りプログラムが壊れるので次は成功しました。それで終わりです!
ここに画像の説明を挿入します
完全なコード:

import json
import time

import requests

header = {
    
    
    'Host': '',
    'Connection': 'keep-alive',
    'Content-Length': '353',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x6309001c) XWEB/6763',
    'Content-Type': 'application/json',
    'Accept': '*/*',
    'X-Requested-With': 'com.tencent.mm',
    'Origin': '',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Dest': 'empty',
    'Referer': '',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh',
    'Cookie': ''
}
url = ''
# 2楼 60号
data3 = \
    {
    
    "operationName": "reserveSeat",
     "query": "mutation reserveSeat($libId: Int!, $seatKey: String!, $captchaCode: String, $captcha: String!) {\n userAuth {\n reserve {\n reserveSeat(\n libId: $libId\n seatKey: $seatKey\n captchaCode: $captchaCode\n captcha: $captcha\n )\n }\n }\n}",
     "variables": {
    
    "seatKey": "35,18", "libId": 525, "captchaCode": "", "captcha": ""}}
# 
data = {
    
    "operationName": "reserveSeat",
        "query": "mutation reserveSeat($libId: Int!, $seatKey: String!, $captchaCode: String, $captcha: String!) {\n userAuth {\n reserve {\n reserveSeat(\n libId: $libId\n seatKey: $seatKey\n captchaCode: $captchaCode\n captcha: $captcha\n )\n }\n }\n}",
        "variables": {
    
    "seatKey": "**,**", "libId": ***, "captchaCode": "", "captcha": ""}}

# -----------------------------测试--------------------------------
# res = requests.post(url=lib_url2, headers=header, json=data3)
# tm = res.elapsed.total_seconds()
# print(tm)
# print(res.status_code)
# print(res.text)

# -----------------------------正题--------------------------------
struct_openTime = "2023-5-9 14:00:00"
openTime = time.strptime(struct_openTime, "%Y-%m-%d %H:%M:%S")
openTime = time.mktime(openTime)
request_cnt = 0
while True:
    # nowTime = int(time.mktime(time.localtime()))
    print(time.time(), openTime)
    if time.time() >= openTime:
        # print(nowTime, openTime,time.time())
        print("------------------------------")
        print(time.time(), openTime)
        print("ok Try to grab seat!")
        grab_time = time.localtime(time.time())
        ts = time.strftime("%Y-%m-%d %H:%M:%S", grab_time)
        print('当前时间是: ' + ts)
        request_cnt += 1
        res = requests.post(url=url, headers=header, json=data)  # 此处data3 是2楼 60
        tm = res.elapsed.total_seconds()
        print(tm)
        print(res.status_code)
        print(res.text)
        # break
        if str(res.text).count("true"):
            print("******************************")
            print("恭喜你!抢座成功!程序即将结束......")
            print("******************************\n")
            break
        else:
            time.sleep(0.3)
        print("------------------------------\n\n")
    if request_cnt >= 10:  # 防止请求过多 被老师XX 所以这里我只敢 “最多” 请求10次
        break  # 另一个作用是避免图书馆服务器有延迟 加上上面的sleep 延迟时间可以控制在 10*0.3s = 3s 内 而且避免了过多的请求(程序1秒内发送的请求是很可怕的数量)
print("程序结束成功!")

2023年5月31日 第4回更新(プログラム内のURLの取得について)

まず、Fiddler と PC の WeChat を開き、WeChat で図書館の公開アカウントを開き、座席の選択をシミュレートします。
ここに画像の説明を挿入します

ここに画像の説明を挿入します

ここに画像の説明を挿入します
Fiddler では、送信した座席選択リクエストとさまざまなヘッダー パラメーターを確認できます。URL は、POST の後ろに青色のライトが付いているものです。

2023年6月1日 第5回アップデート(コメント欄に表示された不具合について(リモートヘルプは解決しました))

一部の学生は使用中にさまざまなエラーを返しました。ここに更新の波があります。

アクセス拒否等について

ここに画像の説明を挿入します

この問題は主に、無効な Cookie または不正な Cookie の入力が原因で発生します。Cookie を選択すると、さまざまな形式の Cookie が存在する可能性があり、多くのパラメータ行が存在する可能性があります。必要なのは、HTTP リクエストでリクエストをシミュレートする HTTP リクエスト内で Cookie を見つけることだけです。 fiddler. 、Cookie に複数のパラメータがある場合はセミコロンで区切る必要がありますが、fiddler は Raw でパラメータをすでに区切っているため、それらを直接使用できることに注意してください。
ここに画像の説明を挿入します
上記は初めて Cookie を取得するプロセスです。ヘッダー内の他のパラメーターを取得する必要があるため、手動でシミュレートする必要があります。今後使用する場合は、ログイン ページの Cookie を取得するだけで済みます。毎回行う必要はありません。その後、手動で座席を選択して座席を確保してください

最後に、穴を埋めます: fiddler が実行されているとき、プロキシは自動的にオンになります。
ここに画像の説明を挿入します
ここに画像の説明を挿入します
以下をオフにしてからプログラムを実行するか、Cookie を取得してプログラムを実行した後に fiddler をオフにします。このプロキシがオンになっている場合、プログラムは実行されません。
第 2 に、Fiddler がオンになっていて異常にシャットダウンすると、次回起動時に Web ページが開かなくなるということです。解決策は、Fiddler を再度開いてからシャットダウンすることです。要は、fiddler をオンにしてシャットダウンすると、その時点のプロキシ サーバーが保存される、つまり、以下に示すようにプロキシ IP アドレスとして保存され、Web ページを開けなくなるということです。
ここに画像の説明を挿入します

2023-6-30 第6回アップデート(皆様が考えていた明日予約機能をアップデート)

多忙でこの機能の実装を考える時間がないというのが主な理由ですが、当図書館から突然、明日の予約機能のみに対応するように座席選択ルールを変更するというお知らせがあり、とても困っています。怒り!やむなく開発させていただきました~
座席指定と同じように、データパラメータを変更するだけで実現できると常々思っていましたが、まさかこのアイデアが簡単すぎるとは思いませんでした
。行列のロジック その後、駅Bで偉い人に会ったのですが、兄貴のホームページをご丁寧に添付させていただきますので、サンリアンにご注目ください!パケット キャプチャで WebSocket 接続であることが判明しましたが、この点は盲点でした。私は上司のコードにたどり着き、キューイング ロジックを取り出し、明日の予約機能を実装することに成功しました。

コードを直接アップロードする

import json
import time

import requests

import websocket

cookieStr = 'Authorization=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VySWQiOjI0Nzg2NjU4LCJzY2hJZCI6MTMyLCJleHBpcmVBdCI6MTY4ODEzOTAwOH0.DNTDgOcTbEkipn1vCNMA1MlVapTc5nk-XbdHZp4tdV5Q7k3E-t3r4q1lHXenVp3u8ukvNQx3MhTq-3TT8spvQvAprE9X5DI3XKJC6zAgdWowZxiqPyg9CttQaNG3FSKcehPHDIb7ro5eY91iPf57G9KH26Yb10fpmrgrYBh6QXR-QZzk7F_enyEJuJCg92gX-NrTFAWwXG24mvaBdF-Cve6EqqD5R1bc1f34_YdMdtDapCrIgO6TodJejJJC9P7Yzws7Oqtumx_V87a6xtwzF25gD_PYXrrkeCV0pWlmRv5VYltHgRZ9AuoEN7lYl8cwefGDWv5fTkL1KRJtmFYSHg'

queue_header = {
    
    
    'Host': '**',
    'Connection': 'Upgrade',
    'Pragma': 'no-cache',
    'Cache-Control': 'no-cache',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090551) XWEB/6945 Flue',
    'Upgrade': 'websocket',
    'Origin': 'https://**',
    'Sec-WebSocket-Version': '13',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh',
    'Sec-WebSocket-Key': 'eTYh3AZI8PuXyuPRr65Zbg==',
    'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
    'Cookie': cookieStr
}

pre_header = {
    
    
    'Host': '**',
    'Connection': 'keep-alive',
    'Content-Length': '307',
    'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090551) XWEB/6945 Flue',
    'Content-Type': 'application/json',
    'Accept': '*/*',
    'X-Requested-With': 'com.tencent.mm',
    'Origin': 'https://**',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Dest': 'empty',
    'Referer': 'https://***/web/index.html',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh',
    'Cookie': cookieStr
}
data = {
    
    "operationName": "save",
        "query": "mutation save($key: String!, $libid: Int!, $captchaCode: String, $captcha: String) {\n userAuth {\n prereserve {\n save(key: $key, libId: $libid, captcha: $captcha, captchaCode: $captchaCode)\n }\n }\n}",
        "variables": {
    
    "key": "*,*", "libid": **, "captchaCode": "", "captcha": ""}}

url = '**'


def pass_queue():
    print("================================")
    print("开始排队。。。")
    ws = websocket.WebSocket()
    # ws.connect("wss://wechat.**.com/ws?ns=prereserve/queue", header=headers)
    ws.connect("wss://******/ws?ns=prereserve/queue", header=queue_header)

    if ws.connected:
        print('test pass queue connect')
        while True:
            ws.send('{"ns":"prereserve/queue","msg":""}')
            a = ws.recv()
            if a.find('u6392') != -1:  # 排队成功返回的第一个字符
                break
            if a.find('u6210') != -1:  # 已经抢座成功的返回
                print("rsp msg:{}".format(json.loads(str(a))["msg"]))
                time.sleep(5)
                break
            print("排队中,rsp:{}".format(a))
            time.sleep(0.05)
        # 关闭连接
        ws.close()
    time.sleep(0.05)
    print("排队结束。。。")
    print("================================")


# -----------------------------测试--------------------------------
# pass_queue()
# pass_queue()
#
# print('test pass queue ==> ok!')
# res = requests.post(url=url, headers=pre_header, json=data)
# print('test request ==> ok!')
# tm = res.elapsed.total_seconds()
# print(tm)
# print(res.status_code)
# print(res.text)

# -----------------------------正题--------------------------------

struct_openTime = "2023-6-30 23:14:00"
openTime = time.strptime(struct_openTime, "%Y-%m-%d %H:%M:%S")
openTime = time.mktime(openTime)
request_cnt = 0
while True:
    # nowTime = int(time.mktime(time.localtime()))
    print(time.time(), openTime)
    if time.time() >= openTime:
        # print(nowTime, openTime,time.time())
        print("------------------------------")
        print(time.time(), openTime)
        print("ok Try to grab seat!")
        grab_time = time.localtime(time.time())
        ts = time.strftime("%Y-%m-%d %H:%M:%S", grab_time)
        print('当前时间是: ' + ts)
        request_cnt += 1

        pass_queue()
        pass_queue()
        print('test pass queue ==> ok!')
        res = requests.post(url=url, headers=pre_header, json=data)
        print('test request ==> ok!')
        tm = res.elapsed.total_seconds()
        print(tm)
        print(res.status_code)
        print(res.text)
        # break
        if str(res.text).count("true"):
            print("******************************")
            print("恭喜你!预定成功!程序即将结束......")
            print("******************************\n")
            break
        else:
            time.sleep(0.3)
        print("------------------------------\n\n")
    if request_cnt >= 20:  # 防止请求过多 被老师XX 所以这里我只敢 “最多” 请求10次
        break  # 另一个作用是避免图书馆服务器有延迟 加上上面的sleep 延迟时间可以控制在 10*0.3s = 3s 内 而且避免了过多的请求(程序1秒内发送的请求是很可怕的数量)
print("程序结束成功!")

2023 年 7 月 1 日の 7 回目のアップデート (Bilibili と Github の 2 つの大手に触発され、パケット キャプチャなしで Cookie を取得するようにアップデート)

コードに直接アクセスします。ライブラリの公式公開アカウントを使用している場合は、Github に直接アクセスしてプロジェクト コードを確認できます。URL の QR コードと、コメントアウトした完全な部分を直接取得できます。チュートリアルなので使えます。学校サーバーなので完全なコードは載せませんが、初めてパケットをキャプチャすることができます 使い方や入力するURLの取得方法については、GithubまたはBilibiliボスのビデオ。

import urllib.request
import urllib.parse
import http.cookiejar


def get_code(url):
    query = urllib.parse.urlparse(url).query
    codes = urllib.parse.parse_qs(query).get('code')
    if codes:
        return codes.pop()
    else:
        raise ValueError("Code not found in URL")


def get_cookie_string(code):
    cookiejar = http.cookiejar.MozillaCookieJar()
    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar))
    response = opener.open(
        "https://**/urlNew/auth.html?" + urllib.parse.urlencode({
    
    
            "r": "https://**/web/index.html",
            "code": code,
            "state": 1
        })
    )
    print(response)
    cookie_items = []
    for cookie in cookiejar:
        cookie_items.append(f"{
      
      cookie.name}={
      
      cookie.value}")
    cookie_string = '; '.join(cookie_items)
    return cookie_string

def main():
    url = input("Please enter the URL: ")
    code = get_code(url)
    print(code)
    cookie_string = get_cookie_string(code)
    print("\nCookie string: \n")
    print(cookie_string)


if __name__ == '__main__':
    main()

2023 年 7 月 10 日の 8 回目の更新 (例外が報告された後に実行を継続できなくなることを回避するために、例外キャプチャを追加しました)

座席指定データと予約データは異なりますし、固有パラメータも異なりますのでご注意ください!libId と libid は大文字と小文字が区別されるので、使用するときは明確に読む必要があります。
加えて!time.time() は、ローカル コンピュータ システムの時刻を取得します。複数のリクエスト (おそらく 1 週間連続で? 数秒遅くなります。ご自身でテストしてください) を実行すると、北京時間より速くなるか遅くなります。プログラムを早く終了したり、遅く開始したりできます! システム時刻を時々同期したい場合は、設定で時刻を検索するか、直接時刻を検索するだけです。Win11はかなり便利です。もう 1 つの解決策は北京時間を直接呼び出すことですが、本当に忙しいので実装したくありません。以前はプログラムを最適化するために徹夜しなければならなかったので、2 ~ 3 日回復しませんでした。今後のパフォーマンスを見てみましょう。

import json
import time
from datetime import datetime
from datetime import timedelta
from datetime import timezone
import requests

import websocket

# -----------------------------测试--------------------------------
# rqst = 0
# while True:
#     try:
#         pass_queue()
#         pass_queue()
#
#         print('test pass queue ==> ok!')
#         res = requests.post(url=url, headers=pre_header, json=data)
#         print('test request ==> ok!')
#         tm = res.elapsed.total_seconds()
#         print(tm)
#         print(res.status_code)
#         print(res.text)
#         rqst += 1
#         if rqst >= 2:
#             break
#     except Exception as e:
#         print(e)
#         pass

# -----------------------------正题--------------------------------
# def get_utcTime():
#     utc_now = datetime.utcnow().replace(tzinfo=timezone.utc)
#
#     SHA_TZ = timezone(
#         timedelta(hours=8),
#         name='Asia/Shanghai',
#     )
#
#     # 北京时间
#     beijing_now = utc_now.astimezone(SHA_TZ)
#     print(beijing_now)
#     print(type(beijing_now))
#
#     fmt = '%Y-%m-%d %H:%M:%S'
#     now_fmt = beijing_now.strftime(fmt)
#     print(now_fmt)
#     print(type(now_fmt))
#     print('---------------------------')
#     return now_fmt


struct_openTime = "2023-7-10 22:00:00"
openTime = time.strptime(struct_openTime, "%Y-%m-%d %H:%M:%S")
openTime = time.mktime(openTime)
request_cnt = 0
while True:
    # nowTime = int(time.mktime(time.localtime()))
    # print(get_utcTime(), openTime)
    # print(, openTime)
    timestamp = time.time()

    # 转换成localtime
    time_local = time.localtime(timestamp)
    # 转换成新的时间格式(2016-05-05 20:28:54)
    dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
    print(dt, struct_openTime)
    if time.time() >= openTime:
        # print(nowTime, openTime,time.time())
        print("------------------------------")
        # print(time.time(), openTime)
        print("ok Try to grab seat!")
        grab_time = time.localtime(timestamp)
        ts = time.strftime("%Y-%m-%d %H:%M:%S", grab_time)
        print('当前时间是: ' + ts)
        request_cnt += 1
        try:
            pass_queue()
            pass_queue()

            print('test pass queue ==> ok!')
            res = requests.post(url=url, headers=pre_header, json=data)
            print('test request ==> ok!')
            tm = res.elapsed.total_seconds()
            print(tm)
            print(res.status_code)
            print(res.text)
            if str(res.text).count("true"):
                print("******************************")
                print("恭喜你!预定成功!程序即将结束......")
                print("******************************\n")
                break
            else:
                print('---睡眠0.3s---')
                time.sleep(0.3)
        except Exception as e:
            print(e)
        # break
        print('test Exception continue.')

        print("------------------------------\n\n")
    if request_cnt >= 100:  # 防止请求过多 被老师XX 所以这里我只敢 “最多” 请求10次
        break  # 另一个作用是避免图书馆服务器有延迟 加上上面的sleep 延迟时间可以控制在 10*0.3s = 3s 内 而且避免了过多的请求(程序1秒内发送的请求是很可怕的数量)
print("程序结束成功!")

ここに画像の説明を挿入します

2023 年 9 月 10 日の 9 回目の更新 (座席情報の取得方法に関する皆様のフィードバックを更新)

座席選択ページに入り、行きたいフロアを選択してクリックします。
ここに画像の説明を挿入します

このページに移動して、fldder によって送信されたリクエストに注目してください。
ここに画像の説明を挿入します

ここに画像の説明を挿入します
皆さん、それを正確に見つけなければなりません。これがない場合は、別のものを試してみてください。世間知らずにならないでください。
ここに画像の説明を挿入します
これをクリックして開きます。見た目を良くするための JSON 解析 Web サイトを見つけることができます。ポップアップ txt ファイルで、Ctrl+F を使用して行きたい座席番号を検索し、対応するキーを見つけます。学校ごとに対応方法が違うのかもしれませんが、自分の目で見てみると、みんな同じ考えを持っています。
ここに画像の説明を挿入します

2023 年 9 月 16 日の 10 回目の更新 (完全なコード + パケット キャプチャ手順のコンパイル)

import json
import time
import requests

import websocket


# 本代码初衷只为了测试post单次请求,并不会对服务器造成伤害,恶意修改请求与作者本人无关

# 以下代码需要自己动手的全用XXXX注释掉了,已测可用!

# -2.去抓url 参考第四次更新
# -1.去抓pre_header参考第四次更新,也就是url那次,我红框画出来了,直接填上‘XXXX’对应的就行(具体已大家自己抓的为准,少参数就补上,多参数就删除)queue_header里面的参数同pre_header中的一致。
# 0.去抓座位表 修改key 参考第九次更新
# 1.获取cookie 一定要使用十分钟内获取的新cookie!(这个可以用上面第七次更新的github上大佬写好的(前提是用的官方服务器哈,自己学校部署的话只能自己去fiddler抓了,随便找个登录的请求就含这个cookie的,很简单))
# 2.修改时间
# 3.开始运行代码
# 4.有bug评论区反馈,或者留言都可,看到回复,也有成功的小伙伴在帮助大家!

cookieStr = 'Authorization=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VySWQiOjM4NDQyNDU3LCJzY2hJZCI6MTMyLCJleHBpcmVBdCI6MTY5NDYyMTkzMH0.ZOkbMn1pQlUeUgix4OCXD6QZ1xf1Qkm7sJEavOdY3XjENj4mRAq5ovSaIQFcipNYE--QDNctWuK9YrH6EN6O-djiQZl_3p-X4Rnr52TAmA61tgkI2JUv8grqFVpPjCGIEPAWKbuTmvsMeIDNXdNTYOkA0GnWjskbkHRvpFGDienG8e8PD0nFw65N_XffWmdneMe7UR8Ut3kJV0nayzNsDgDzC2QIR1lf_oSORvcREKWFevwOikUpUbBXOvUA59u1_geuPw4f_yxD7bIgpyZ8lqnBgTUcGZyGhth2aeWwNDWuv6JY6mmFDLVTf-lvtJeIDN_lDlfKGtFaIxsyLqOvhg'
# cookies = []
queue_header = {
    
    
    'Host': 'XXXX',
    'Connection': 'Upgrade',
    'Pragma': 'no-cache',
    'Cache-Control': 'no-cache',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090551) XWEB/6945 Flue',
    'Upgrade': 'websocket',
    'Origin': 'XXXX',
    'Sec-WebSocket-Version': '13',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh',
    'Sec-WebSocket-Key': 'eTYh3AZI8PuXyuPRr65Zbg==',
    'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
    'Cookie': cookieStr
}

pre_header = {
    
    
    'Host': 'XXXX',
    'Connection': 'keep-alive',
    'Content-Length': '307',
    'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090551) XWEB/6945 Flue',
    'Content-Type': 'application/json',
    'Accept': '*/*',
    'X-Requested-With': 'com.tencent.mm',
    'Origin': 'XXXX',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Dest': 'empty',
    'Referer': 'XXXX',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh',
    'Cookie': cookieStr
}

# 预约data
data = {
    
    "operationName": "save",
        "query": "mutation save($key: String!, $libid: Int!, $captchaCode: String, $captcha: String) {\n userAuth {\n prereserve {\n save(key: $key, libId: $libid, captcha: $captcha, captchaCode: $captchaCode)\n }\n }\n}",
        "variables": {
    
    "key": "35,18", "libid": 525, "captchaCode": "", "captcha": ""}}

# 抢座data
data3 = \
    {
    
    "operationName": "reserveSeat",
     "query": "mutation reserveSeat($libId: Int!, $seatKey: String!, $captchaCode: String, $captcha: String!) {\n userAuth {\n reserve {\n reserveSeat(\n libId: $libId\n seatKey: $seatKey\n captchaCode: $captchaCode\n captcha: $captcha\n )\n }\n }\n}",
     "variables": {
    
    "seatKey": "35,18", "libId": 525, "captchaCode": "", "captcha": ""}}

url = 'XXXX'


def pass_queue():
    print("================================")
    print("开始排队。。。")
    ws = websocket.WebSocket()
    # ws.connect("wss://XXXX/ws?ns=prereserve/queue", header=headers)
    ws.connect("wss://XXXX/ws?ns=prereserve/queue", header=queue_header) # 这里的XXXX和Host内容是一致的

    if ws.connected:
        print('test pass queue connect')
        while True:
            ws.send('{"ns":"prereserve/queue","msg":""}')
            a = ws.recv()
            if a.find('u6392') != -1:  # 排队成功返回的第一个字符
                break
            if a.find('u6210') != -1:  # 已经抢座成功的返回
                print("rsp msg:{}".format(json.loads(str(a))["msg"]))
                time.sleep(5)
                break
            print("排队中,rsp:{}".format(a))
            # time.sleep(0.01)
        # 关闭连接
        ws.close()
    # time.sleep(0.01)
    print("排队结束。。。")
    print("================================")


struct_openTime = "2023-8-29 22:00:00"
openTime = time.strptime(struct_openTime, "%Y-%m-%d %H:%M:%S")
openTime = time.mktime(openTime)
request_cnt = 0
while True:
    timestamp = time.time()

    # 转换成localtime
    time_local = time.localtime(timestamp)
    # 转换成新的时间格式(2016-05-05 20:28:54)
    dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
    print(dt, struct_openTime)
    if time.time() >= openTime:

        print("------------------------------")

        print("ok Try to grab seat!")
        grab_time = time.localtime(timestamp)
        ts = time.strftime("%Y-%m-%d %H:%M:%S", grab_time)

        request_cnt += 1
        try:
            pass_queue()
            pass_queue()
            print('test pass queue ==> ok!')
            res = requests.post(url=url, headers=pre_header, json=data)
            print('test request ==> ok!')

            unicode = str(res.text).encode('utf-8').decode('unicode_escape')
            print(unicode)
            if str(res.text).count("true"):
                print("******************************")
                print("恭喜你!预定成功!程序即将结束......")
                print("******************************\n")
                break
            else:
                # print('---睡眠0.3s---')
                pass_queue()
                pass_queue()
                time.sleep(0.3)
        except Exception as e:
            time.sleep(0.3)
            print(e)
            # print('test Exception continue.')
        # break
        print("------------------------------\n\n")
    if request_cnt >= 100:  # 防止请求过多 被老师XX 所以这里我只敢 “最多” 请求10次
        break  # 另一个作用是避免图书馆服务器有延迟 加上上面的sleep 延迟时间可以控制在 10*0.3s = 3s 内 而且避免了过多的请求(程序1秒内发送的请求是很可怕的数量)
print("程序结束成功!")

バグ フィードバック エリア、継続的に更新されます...

バグがある場合は、プライベートメッセージを送ってください。時間があれば調べます。
pycharmの実行エラーについて(解決済み)
ここに画像の説明を挿入します
環境問題: webscoket のみがインストールされていますが、websocket-client はインストールされていません。この記事に移動してください。

webscoket と websocket-client # 両方をインストールする必要があります
pip install webscoket
pip install websocket-client

このエラーには 2 つの可能性があります:
① Cookie の失敗msg1000を返す
② キューイングロジックを無断で改変!
ここに画像の説明を挿入します
返品後はページを更新してくださいその理由は、キュー リクエストは 1 回しか呼び出されず、2 回呼び出す必要があるためです。
ここに画像の説明を挿入します

この更新の最後に書かれていますが、この更新後にプログラムが最適化されることはほとんどないと推定されています。完全に自動でシートを取得するまでには至っていませんが (プログラムが自動的に Cookie を取得し、定期的にログインを送信することを意味します)、基本的な UI インターフェイスを備えています。結局のところ、手動​​でクッキーを取得するのにかかる時間はほんの数秒であり、このプログラムの本来の目的は、お気に入りの席が奪われないようにすることであるため、大学院入試の年には最適化を行うための時間とエネルギーはあまりありません。半自動化によってその目標は達成されており、さらに、毎日誰かに席を確保してもらうことはできないため、通常は席を選択して携帯電話で送信するだけで済みます。
2023-6-30 23:27 更新: 席を確保する場合でも、明日のアポイントを取る場合でも、このブログはすべて実装されています。方法は比較的低いかもしれませんが、時間通りに取得できます。さらなる最適化については、 、お任せします!
2023-9-10 22:44 更新: すべてのソース コードは記事内にあることに注意してください。少し乱雑かもしれませんが、実際にはそうです。ただし、最後に更新された完全なコードを参照してください。その中で、私は要所要所で * を使用 * むしろ全員が逃げることは不可能です! そして、立候補したい場合は、住所と座席を自分で取得する必要があるため、直接立候補しても意味がありません。
ご多幸をお祈り申し上げます。

おすすめ

転載: blog.csdn.net/weixin_51461002/article/details/130292567