Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions Login/login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import requests
import re
import qrcode
import time
from bs4 import BeautifulSoup
from Login.redirect import StudentSession
from PIL import Image

class QRCodeLogin:
def __init__(self,url="https://login.b8n.cn/qr/weixin/student/2"):
self.base_url = url
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36 MicroMessenger/7.0.10.1580(0x27000A50) Process/tools NetType/WIFI Language/zh_CN ABI/arm64',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://wx.qq.com/',
'sec-ch-ua-platform': 'Android',
'X-Requested-With': 'XMLHttpRequest',
})

def extract_qr_content(self, html):
"""从HTML中提取二维码内容"""
soup = BeautifulSoup(html, 'html.parser')
scripts = soup.find_all('script')
script = scripts[2]

# re匹配(sess、tm、sign)
pattern = r'https?://[^\s"\']+'
urls = re.findall(pattern, str(script))[0]

sess_pattern = r'[?&]sess=([^&]+)'
tm_pattern = r'[?&]tm=([^&]+)'
sign_pattern = r'[?&]sign=([^&]+)'

sess_match = re.search(sess_pattern, urls)
tm_match = re.search(tm_pattern, urls)
sign_match = re.search(sign_pattern, urls)

sess = sess_match.group(1) if sess_match else None
tm = tm_match.group(1) if tm_match else None
sign = sign_match.group(1) if sign_match else None

# print(f"sess: {sess}")
# print(f"tm: {tm}")
# print(f"sign: {sign}")
params = {
'sess': sess,
'tm': tm,
'sign': sign
}
return params

def create_qrcode_image(self, params, filename=None):
"""创建二维码图片"""
# 构建URL
wx_url = "http://login.b8n.cn/weixin/login/student/2"
query_string = "&".join([f"{k}={v}" for k, v in params.items()])
qr_url = f"{wx_url}?{query_string}"

# print(f" 二维码内容: {qr_url}")

# 生成二维码
img = qrcode.make(qr_url)
img.save("login_qrcode.png")

print(f" 二维码已保存: login_qrcode.png")
print(f" 请用微信扫描二维码登录")
image = Image.open('login_qrcode.png')
# 显示二维码
image.show()

def poll_login_status(self, max_attempts=20):
"""轮询登录状态"""
check_url = f"{self.base_url}?op=checklogin"

for i in range(max_attempts):
print(f"轮询检查登录状态... ({i + 1}/{max_attempts})")

try:
response = self.session.get(check_url)
# print("轮询响应" + response.text)
if response.status_code == 200:
try:
data = response.json()
if data.get('status'):
redirect_url = data.get('url')
print(f"登录成功!获取跳转URL: {redirect_url}")

return True, redirect_url
else:
print(f"等待扫码... ")
except:
print("响应不是JSON格式")

except Exception as e:
print(f"请求失败: {e}")

time.sleep(1) # 等待1秒

print("二维码已过期")
return False, None

def run(self):
html = self.session.get(self.base_url).text
params = self.extract_qr_content(html)

"""运行完整流程"""
print("=" * 50)
print("微信扫码登录流程开始")
print("=" * 50)

# 创建二维码图片
print("\n1. 生成二维码图片...")
self.create_qrcode_image(params)

print("\n2. 请用微信扫描二维码...")

# 轮询登录状态
print("\n3. 等待扫码确认...")
return self.poll_login_status()

def external_getCookieAndCourseId(self):
# 爬取并生成二维码
ok = False
url = ""
for retry in range(3):
print(f"\n\n尝试 #{retry + 1}: \n", end="")
ok, url = scraper.run()
if ok: break

if ok:
s = StudentSession()
cookie = s.access_login_url(url)
course_id = s.getClassId()
return cookie, course_id
return None, None

if __name__ == '__main__':
scraper = QRCodeLogin()
scraper.external_getCookieAndCourseId()
110 changes: 110 additions & 0 deletions Login/redirect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import re

import requests
from bs4 import BeautifulSoup


class StudentSession:
def __init__(self):
self.session = requests.Session()
self.session.headers.update({
"authority": "bj.k8n.cn",
"scheme": "https",
"path": "/student/uidlogin?",
"sec-ch-ua": '"Chromium";v="142", "Microsoft Edge";v="142", "Not_A Brand";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"dnt": "1",
"upgrade-insecure-requests": "1",
"prefer": "safe",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"sec-fetch-site": "cross-site",
"sec-fetch-mode": "navigate",
"sec-fetch-dest": "document",
"referer": "https://login.b8n.cn/",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"priority": "u=0, i",
})
self.cookie=None
self.course_id=None

def access_login_url(self,redirect_url:str)->str:
"""
这里禁止重定向是因为跳转到了/student页面后只有's'会话的cookie,没有remember_student的cookie
只有在这个跳转页里才发现了remember_student,有了remember_student,就可以用cookie去访问其他页面了
"""
# url处理
url = "https://bj.k8n.cn/student/uidlogin?" + redirect_url.split('?')[1]

response=self.session.get(url, allow_redirects=False)
print(f"状态码: {response.status_code}")
# print(f"最终URL: {response.url}")
# print(f"响应长度: {len(response.text)}")
# print(f"响应预览: {response.text}")
# 保存cookies供后续使用
cookies = self.session.cookies.get_dict()
#去除掉没用的cookie
cookies.pop("s")

# 使用列表推导式生成键值对字符串
cookie= [f"{key}={value}" for key, value in cookies.items()][0]

print(f"获取的Cookies: {cookie}")
self.cookie=cookie
return cookie

def getClassId(self)->str:
"""访问其他页面"""
url = "http://bj.k8n.cn/student"
resp=self.session.get(url)
print(f"学生页面状态码:{resp.status_code}")
# print(f"学生页面预览页:{resp.text}")

soup = BeautifulSoup(resp.text, 'html.parser')
div_element = soup.find('div', class_='card mb-3 course')
course_id = div_element.get('course_id')
print(f"ClassID: {course_id}")
self.course_id=course_id
return course_id

def other(self):
"""可以get其他子网获取信息:
比如获取名称信息和uid或者学号之类在cookie前面加注释之类的
又或者有其他大佬出手重构config.json,第一次看到这个项目的时候还是单人签到的,
现在被很多大佬贡献改成多人了,对于这个多人的签到我也有一些想法就是加一个user类,
json结构像这样
“user”:[
{
"username":"zhangsan",
"uid":"123",
"course_id":"123",
"cookie":"remember....."
"scheduletime": "01:30",
"lat": "123",
"lng": "342",
"acc": "12",
"time": 0,
},
{
"username":"zhangsan",
"uid":"123",
"course_id":"123",
"cookie":"remember....."
"scheduletime": "01:30",
"lat": "123",
"lng": "342",
"acc": "12",
"time": 0,
},
]
实现多人不同班不同地点不同时间的签到
如果我说的有什么问题还请大佬指教>.<!
"""
pass

# 立即执行
if __name__ == '__main__':
s = StudentSession()
s.access_login_url("http://bj.k8n.cn/student?uid=2789785&tm=1764778952&sign=acf6e7872ea5036bf66c94d05bb435c4&option=&")