Fui até a conta oficial do WeChat da biblioteca para conseguir um lugar [versão Python]

Como a maioria deles são novatos, vou reorganizar meus pensamentos aqui e pular para a décima atualização!

A primeira atualização para capturar pacotes e conseguir assentos

Vamos dar uma olhada nas renderizações primeiro ( os interesses serão totalmente codificados primeiro )
Insira a descrição da imagem aqui


Como nossa escola já implantou o sistema no servidor da escola há algum tempo, não vou colocar o endereço aqui, vamos falar brevemente sobre a ideia.

Escrito na frente:
①O código é muito simples, apenas uma solicitação. O autor continuará a otimizá-lo mais tarde. Deixe-me falar sobre minhas necessidades primeiro: <1>
Realize a captura de assento totalmente automática e comece a ocupar assentos em horários regulares todos os dias, quando a biblioteca abre
<2> Mais rápido que os humanos, para conseguir o efeito de abertura do museu, então isso deve ser otimizado no futuro. Porque este blog apenas enviou uma solicitação, e não adicionou carimbo de data e hora nem nada, isso é muito bom para que todos possam jogar livremente. ② Múltiplas solicitações não podem ser evitadas no processo, portanto, para
evitar anti-escalada e bloqueio de IP, você deve adicionar um pool de proxy e similares no estágio posterior (mas se o professor realmente quer mexer com você, ele com certeza terá suas informações, então todos devem se apressar) Isso pode ser ignorado primeiro, este programa não causará esse tipo de problema Condição

Ideias:
① Use a biblioteca de solicitações do Python para enviar solicitações get/post. Usar get ou post exige que todos capturem e analisem os pacotes por conta própria. ②
Eu uso o Fiddler como software de captura de pacotes.
③ Precisamos conectar o telefone celular ao Fiddler e, em seguida, marque manualmente um compromisso para obtê-lo. Poste parâmetros, como cookies de dados de cabeçalho, etc. (A segunda atualização pode ser resolvida sem pegar o WeChat do PC do celular!)
Insira a descrição da imagem aqui
A última etapa é escrever o código para enviar a solicitação de postagem.
Armadilhas:
1. É melhor usar a solicitação do celular para obter cookies., Eu uso o WeChat no PC para marcar uma consulta e o resultado é um erro de sintaxe? Também pode ser que eu não tenha acertado. Mais tarde, quando os cookies do celular ficaram disponíveis, não tentei novamente no PC. Vamos fazer um autoteste. Se eu testar mais tarde, eu vai compensar (a segunda atualização pode resolver o lado do PC)
2. Seja otimista sobre get/post. A solicitação e os dados transmitidos estão em json ou outros formatos
? 3. Para solicitações violentas, você precisa adicionar um pool de proxy e ele será ruim se estiver bloqueado. . . .

Faça upload do código (especificamente, você pode capturar e analisar pacotes de acordo com sua situação. Cada sistema é diferente. Aqui falo apenas sobre as ideias)

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)

Segunda atualização em 28 de abril de 2023 (atualizado e adicionado carimbo de data/hora para obtenção de assento no horário designado)

Desta vez, o programa foi atualizado para obter assentos com base no tempo especificado, com precisão de segundos.
Após o teste, o cliente de PC usa o WeChat para fazer login na conta oficial para obter os cookies. Os cookies obtidos são válidos. Isso evita o tedioso passos para usar o celular para pegar assentos. É ótimo. ✌

# -----------------------------正题--------------------------------
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("程序结束成功!")

Esta imagem é uma captura de tela tirada no início do teste. Não há captura de tela do programa completo. No entanto, o programa pode ser usado. Adicionarei a imagem mais tarde, se tiver tempo.
Insira a descrição da imagem aqui

A terceira atualização em 9 de maio de 2023 (caso de sucesso do teste de tempo de atraso atualizado)

Desta vez falarei sobre os problemas encontrados no combate real e como resolvê-los.
Quando escrevi o programa e fui praticar, descobri que o servidor da nossa escola estava atrasado. O sleep(0.2) * 5 = 1s definido anteriormente não atendia aos requisitos, então mudei para sleep(0.3) * 10 = 3s para capturá-lo. O resultado é muito suave. Você pode dimensioná-lo de acordo com o servidor da sua escola durante o combate real. Além disso, também testei a velocidade manual da mão e a captura do programa hoje, e os resultados foram basicamente eliminados pelo programa...

Armadilhas:
① Preste atenção à pontualidade do cookie. O cookie irá expirar dentro de um determinado período de tempo e você precisa obtê-lo novamente. Não sei com que frequência ele irá expirar (expira em cerca de 30 minutos), então irei obter o cookie mais recente toda vez que me sento. Parece que encontrei uma seção no Jiwang que fala sobre isso. Vou atualizá-lo depois de revisá-lo... ②
O servidor está atrasado. Basta testá-lo algumas vezes Ou se você jogar por mais tempo e tocar em c, tudo ficará bem.

Insira a descrição da imagem aqui
Houve um atraso aqui, então falhou uma vez, mas configurei para solicitar 10 vezes. Se for bem-sucedido, o programa será interrompido, então o próximo foi bem-sucedido. Esse é o fim!
Insira a descrição da imagem aqui
Código completo:

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("程序结束成功!")

A quarta atualização em 31 de maio de 2023 (sobre a captura de URLs no programa)

Primeiro abra nosso Fiddler e PC WeChat e abra a conta pública da biblioteca no WeChat para simular a seleção de assentos.
Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
No Fiddler, você pode ver a solicitação de seleção de assento e vários parâmetros de cabeçalho que enviamos, e a url é aquela com luz azul atrás do POST.

A quinta atualização em 1º de junho de 2023 (em relação aos bugs que apareceram na área de comentários (a ajuda remota foi resolvida))

Alguns alunos retornaram vários erros durante o uso. Aqui está uma onda de atualizações.

Sobre acesso negado ou outros

Insira a descrição da imagem aqui

Esse problema é causado principalmente por cookies inválidos ou preenchimento incorreto de cookies. Quando você seleciona cookies, pode haver vários formatos de cookies e pode haver muitas linhas de parâmetros. Só precisamos encontrar o cookie na solicitação Http que simula a solicitação em fiddler. , observe que se o cookie tiver vários parâmetros, eles precisam ser separados por ponto e vírgula, mas o fiddler já os separou no Raw, então você pode usá-los diretamente.
Insira a descrição da imagem aqui
O acima é o processo de obtenção de cookies pela primeira vez. Como precisamos obter outros parâmetros no cabeçalho, precisamos simulá-lo manualmente. No uso futuro, só precisamos pegar o cookie da página de login. Não Não é necessário fazer isso sempre. Em seguida, selecione manualmente os assentos para obtê-los.

Finalmente, preencha uma lacuna: quando o violinista estiver em execução, o proxy será ativado automaticamente. Desligue
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
o seguinte e execute o programa, ou desligue o violinista após obter o cookie para executar o programa. Se este proxy estiver ativado, o programa não será executado.
Em segundo lugar, a questão é que se o violinista for ligado e desligado de forma anormal, a página da web não abrirá na próxima vez que você inicializar. A solução é reabrir o violinista e então desligá-lo. A essência é que se o violinista for ligado e desligado, o servidor proxy neste momento será salvo, ou seja, salvo como o endereço IP do proxy conforme mostrado abaixo, fazendo com que a página da web não possa ser aberta.
Insira a descrição da imagem aqui

A sexta atualização em 30/06/2023 (atualizada a função de reserva de amanhã que todos estão pensando)

A principal razão é que estou muito ocupado e não tenho tempo para pensar em como implementar esta função, mas nossa biblioteca de repente emitiu um aviso dizendo que as regras de seleção de assentos serão alteradas para suportar apenas a função de reserva para amanhã. Isso me faz nervoso! Fui forçado a desenvolvê-lo ~
Sempre pensei que, assim como a seleção de assentos, poderia alcançar essa função apenas alterando um parâmetro de dados. Não esperava que essa ideia fosse muito simples. O principal motivo foi que nunca passei
do lógica da fila. Mais tarde, conheci um chefão na estação B. Estou anexando educadamente a página inicial do irmão mais velho. Por favor, preste atenção em Sanlian! , e a captura de pacotes revelou que era uma conexão websocket. Esse aspecto era um ponto cego. Cheguei ao código do chefe, retirei sua lógica de fila e implementei com sucesso a função de reserva de amanhã.

Carregue o código diretamente

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("程序结束成功!")

A sétima atualização em 1º de julho de 2023 (atualizada para obter cookies sem captura de pacotes, inspirada nos dois marmanjos do Bilibili e do Github)

Vá diretamente para o código. Se você estiver usando a conta pública oficial da biblioteca, você pode ir diretamente ao Github para ver o código do projeto. Você pode obter diretamente o código QR da URL e a parte completa que comentei. Lá é um tutorial e pode ser usado. Como somos um servidor escolar, não colocaremos o código completo aqui. Você pode capturar o pacote pela primeira vez. Para saber como usá-lo e como obter a URL que precisa ser inserida, acesse o Github ou o vídeo do chefe 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()

A oitava atualização em 10 de julho de 2023 (adicionada captura de exceção para evitar a impossibilidade de continuar a execução após uma exceção ser relatada)

Observe que os dados para reservas de assento e dados de reserva são diferentes, e os parâmetros específicos também são diferentes! ! ! libId e libid diferenciam maiúsculas de minúsculas ~ então você deve lê-los claramente ao usá-los! ! !
além disso! time.time() obtém a hora do sistema de computador local. Após várias solicitações (talvez por uma semana continuamente? Será alguns segundos mais lento, teste você mesmo), será mais rápido ou mais lento que o horário de Pequim, causando assim o programa para terminar mais cedo ou começar mais tarde! Se quiser sincronizar a hora do sistema de vez em quando, basta procurar a hora nas configurações ou diretamente! Win11 é bastante conveniente. Outra solução é ligar diretamente para o horário de Pequim, mas não quero implementá-la porque estou muito ocupado! ! ! Anteriormente, eu tinha que ficar acordado a noite toda para otimizar o programa, então não me recuperei por dois ou três dias. Vamos ver como você se sai no futuro!

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("程序结束成功!")

Insira a descrição da imagem aqui

A nona atualização em 10 de setembro de 2023 (atualiza o feedback de todos sobre como capturar informações de assentos)

Entre na página de seleção de assentos, selecione o andar para o qual deseja ir e clique em
Insira a descrição da imagem aqui

Acesse esta página e preste atenção na solicitação enviada pelo fldder
Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
Todos vocês devem encontrá-lo com precisão. Se não tiverem este, tentem outro. Não sejam muito ingênuos.
Insira a descrição da imagem aqui
Basta clicar aqui para abri-lo. Você pode encontrar um site de análise json para torná-lo mais bonito. No arquivo txt pop-up, use Ctrl+F para pesquisar o número do assento que você deseja acessar e encontrar a chave correspondente. é possível que o método correspondente de cada escola seja diferente.Quando cada um olha por si mesmo, todos têm a mesma ideia.
Insira a descrição da imagem aqui

A décima atualização em 16 de setembro de 2023 (código completo + compilação das etapas de captura de pacotes)

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("程序结束成功!")

Área de feedback de bugs, atualizada continuamente...

Se você tiver algum bug, basta me enviar uma mensagem privada e darei uma olhada quando tiver tempo.
Sobre o erro de execução do pycharm (resolvido)
Insira a descrição da imagem aqui
Problema ambiental: apenas o webscocket está instalado, mas não o websocket-client. Vá para este artigo .

webscocket e websocket-client # Ambos precisam ser instalados
pip install webscoket
pip install websocket-client

Existem duas possibilidades para este erro:
① Falha no cookieRetornar msg1000
② Modifique a lógica de fila sem autorização!
Insira a descrição da imagem aqui
postar retornos por favor atualize a páginaA razão é que a solicitação da fila só é chamada uma vez e precisa ser chamada duas vezes!
Insira a descrição da imagem aqui

Escrito no final desta atualização, estima-se que o programa raramente será otimizado após esta atualização. Embora não tenha alcançado a captura de assento totalmente automática (o que significa que o programa obtém cookies automaticamente e depois envia logins regularmente), ele nem mesmo tem uma interface UI básica. Afinal, não tenho muito tempo e energia para otimizar no ano do vestibular de pós-graduação, pois pegar os biscoitos manualmente leva apenas alguns segundos, e a intenção original deste programa é evitar que seus assentos favoritos sejam roubados. Agora ele atingiu seu objetivo por meio da semiautomação.Além disso, você também não pode deixar alguém reservar um lugar para você todos os dias, então normalmente você pode apenas selecionar um assento e enviá-lo no seu celular.
Atualização de 30/06/2023 às 23:27: Seja para conseguir um lugar ou para marcar um encontro amanhã, este blog foi totalmente implementado. O método pode ser relativamente baixo, mas você pode pegá-lo na hora certa. Quanto a mais otimização , Eu deixo para você!
Atualização 2023/09/10 22:44: Observe que todos os códigos-fonte estão no artigo. Pode ser um pouco confuso, mas na verdade é. No entanto, consulte o último código completo atualizado. Entre eles, eu usado * para muitos pontos-chave. *Em vez disso, não é possível que todos simplesmente fujam! E se quiser concorrer, você mesmo deve conseguir o endereço e os assentos, então não adianta concorrer diretamente.
Em suma, muitas felicidades!

Acho que você gosta

Origin blog.csdn.net/weixin_51461002/article/details/130292567
Recomendado
Clasificación