-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
5,231 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,36 @@ | ||
# yz | ||
点点鼠标快速上线一个研招网成绩查询的接口 | ||
### 介绍一下? | ||
无需拥有服务器,点点鼠标就能上线一个研招网成绩查询的接口。 | ||
|
||
实质是通过腾讯云无服务器云函数,制作一个REST风格的接口,通过GET请求即可**查询研究生入学考试的初试成绩**。 | ||
|
||
### 特性 | ||
- [x] 自动识别验证码 | ||
- [x] 无需修改我的💩脚本 | ||
- [x] 支持Server酱 | ||
|
||
### 预览一下? | ||
|
||
> 作者不会收集任何人的信息。代码是开源的,最好自行部署较为放心。 | ||
请求方式:GET | ||
|
||
` | ||
https://service-5ur64h8n-1251079053.ap-shanghai.apigateway.myqcloud.com/release/yanzhao?xm=姓名&id=身份证号&kh=准考证号 | ||
` | ||
|
||
返回样例:JSON | ||
|
||
`{"Code": 101, "Msg": "Score not released yet", "Request_id": "e43f5c16-2dde-11e9-93a2-5254005d5fdb"}` | ||
|
||
### 如何部署? | ||
你需要准备注册[腾讯云](https://console.cloud.tencent.com/scf)和[腾讯优图](https://open.youtu.qq.com/#/open)。 | ||
|
||
- 下载最新的release压缩包 | ||
- [腾讯云SCF](https://console.cloud.tencent.com/scf)后台新建 > 空白函数 ,函数名请随意,运行环境选择Python36 | ||
- 执行方法填入`index.main_handler` | ||
- 提交方法选择本地上传ZIP包,上传刚下载的ZIP包 | ||
- 环境变量请配置`app_id`、`secret_id`、`secret_key`,请在腾讯优图开放平台获取这三个值 | ||
- 保存 | ||
- 触发方式 > API网关触发 > 默认参数保存,获得一个公网的查询地址 | ||
|
||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
# 6r6 | ||
|
||
import os | ||
import time | ||
import random | ||
import hmac | ||
import hashlib | ||
import binascii | ||
import base64 | ||
import json | ||
import logging | ||
import re | ||
import requests | ||
|
||
# (*)腾讯优图配置 | ||
app_id = '' | ||
secret_id = '' | ||
secret_key = '' | ||
|
||
# Server酱V3配置 | ||
sckey = '' | ||
|
||
logger = logging.getLogger() | ||
|
||
class Youtu(object): | ||
|
||
def __init__(self, app_id, secret_id, secret_key, qq=10000): | ||
self.app_id = app_id | ||
self.secret_id = secret_id | ||
self.secret_key = secret_key | ||
self.qq = qq | ||
|
||
def cal_sig(self): | ||
timestamp = int(time.time()) | ||
expired = str(timestamp + 2592000) | ||
rdm = str(random.randint(0, 999999999)) | ||
plain_text = 'a={appid}&k={secret_id}&e={expired}&t={timestamp}&r={rdm}&u={qq}&f=' | ||
plain_text = plain_text.format(appid=self.app_id, | ||
secret_id=self.secret_id, | ||
timestamp=timestamp, | ||
rdm=rdm, qq=self.qq, | ||
expired=expired) | ||
bin = hmac.new(self.secret_key.encode(), plain_text.encode(), hashlib.sha1).hexdigest() | ||
s = binascii.unhexlify(bin) | ||
s = s + plain_text.encode('ascii') | ||
signature = base64.b64encode(s).rstrip().decode() | ||
return signature | ||
|
||
def get_text(self, image_raw): | ||
signature = self.cal_sig() | ||
headers = {'Host': 'api.youtu.qq.com', 'Content-Type': 'text/json', 'Authorization': signature} | ||
data = {'app_id': self.app_id, 'image': ''} | ||
data['image'] = base64.b64encode(image_raw).rstrip().decode('utf-8') | ||
resp = requests.post('https://api.youtu.qq.com/youtu/ocrapi/generalocr', | ||
data=json.dumps(data), | ||
headers=headers) | ||
if 'items' in resp.text: | ||
return resp.content.decode('utf-8') | ||
else: | ||
return '0' | ||
|
||
class SocreQuery: | ||
|
||
def __init__(self, xm, id, ksbh): | ||
self.xm = xm | ||
self.id = id | ||
self.ksbh = ksbh | ||
self.cookies = requests.cookies.RequestsCookieJar() | ||
self.headers = { | ||
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', | ||
'Accept-Encoding':'gzip, deflate, br', | ||
'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8', | ||
'Cache-Control':'max-age=0', | ||
'Content-Type':'application/x-www-form-urlencoded', | ||
'DNT':'1', | ||
'Host':'yz.chsi.com.cn', | ||
'Origin':'https://yz.chsi.com.cn', | ||
'Referer':'https://yz.chsi.com.cn/apply/cjcx/', | ||
'Upgrade-Insecure-Requests':'1', | ||
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.37 (KHTML, like Gecko) Chrome/70.0.3537.110 Safari/537.37' | ||
} | ||
|
||
def get_cookies(self): | ||
base_url = 'https://yz.chsi.com.cn/apply/cjcx' | ||
session = requests.session() | ||
base_resp = session.get(base_url, headers=self.headers) | ||
self.cookies = base_resp.cookies | ||
|
||
def get_checkcode(self): | ||
pic_url = 'https://yz.chsi.com.cn/apply/cjcx/image.do' | ||
resp = requests.get(pic_url, headers=self.headers, cookies=self.cookies).content | ||
ocr = Youtu(app_id, secret_id, secret_key) | ||
try: | ||
resp = ocr.get_text(resp) | ||
resp = eval(resp) | ||
return resp['items'][0]['itemstring'] | ||
except: | ||
return '0' | ||
|
||
def get_score_page(self): | ||
self.get_cookies() | ||
checkcode = self.get_checkcode().replace(' ','') | ||
post_url = 'https://yz.chsi.com.cn/apply/cjcx/cjcx.do' | ||
data = { | ||
'xm': self.xm, | ||
'zjhm':self.id, | ||
'ksbh':self.ksbh, | ||
'bkdwdm':None, | ||
'checkcode':checkcode | ||
} | ||
post_resp = requests.post(post_url,data=data, headers=self.headers).text | ||
return post_resp | ||
|
||
@staticmethod | ||
def get_mid_text(w1, w2, text): | ||
pat = re.compile(w1+'(.*?)'+w2,re.S) | ||
result_dict = pat.findall(text) | ||
return result_dict | ||
|
||
@staticmethod | ||
def notice(key, title, desp): | ||
url = 'https://sc.ftqq.com/{}.send'.format(key) | ||
payload = {'text':title,'desp':desp} | ||
r = requests.get(url,params=payload) | ||
return r.text | ||
|
||
|
||
def main_handler(event, context): | ||
data = { | ||
"isBase64Encoded": False, | ||
"statusCode": 200, | ||
"headers": {"Content-Type":"application/json"}, | ||
"body": ""} | ||
try: | ||
rid = context["request_id"] | ||
xm = event['queryString']['xm'] | ||
id = event['queryString']['id'] | ||
kh = event['queryString']['kh'] | ||
query = SocreQuery(xm,id,kh) | ||
page = query.get_score_page() | ||
if '无查询结果' in page: | ||
logging.info('成绩还没出') | ||
data['body'] = json.dumps({"Code":101,"Msg":"Score not released yet","Request_id":rid}) | ||
return data | ||
elif '总分' in page: | ||
score_content = query.get_mid_text('<tbody>','</tbody>',page)[0] | ||
logging.info('成绩查询成功') | ||
data['headers']['Content-Type'] = 'text/html' | ||
data['body'] = score_content | ||
#query.notice(sckey,'成绩出了',page) | ||
return data | ||
else: | ||
data['body'] = json.dumps({"Code":103,"Msg":"Unexpected page contents","Request_id":rid}) | ||
return data | ||
except: | ||
data['body'] = json.dumps({"Code":102,"Msg":"Unexpected url parameters","Request_id":rid}) | ||
return data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# __ | ||
# /__) _ _ _ _ _/ _ | ||
# / ( (- (/ (/ (- _) / _) | ||
# / | ||
|
||
""" | ||
Requests HTTP Library | ||
~~~~~~~~~~~~~~~~~~~~~ | ||
Requests is an HTTP library, written in Python, for human beings. Basic GET | ||
usage: | ||
>>> import requests | ||
>>> r = requests.get('https://www.python.org') | ||
>>> r.status_code | ||
200 | ||
>>> 'Python is a programming language' in r.content | ||
True | ||
... or POST: | ||
>>> payload = dict(key1='value1', key2='value2') | ||
>>> r = requests.post('https://httpbin.org/post', data=payload) | ||
>>> print(r.text) | ||
{ | ||
... | ||
"form": { | ||
"key2": "value2", | ||
"key1": "value1" | ||
}, | ||
... | ||
} | ||
The other HTTP methods are supported - see `requests.api`. Full documentation | ||
is at <http://python-requests.org>. | ||
:copyright: (c) 2017 by Kenneth Reitz. | ||
:license: Apache 2.0, see LICENSE for more details. | ||
""" | ||
|
||
import urllib3 | ||
import chardet | ||
import warnings | ||
from .exceptions import RequestsDependencyWarning | ||
|
||
|
||
def check_compatibility(urllib3_version, chardet_version): | ||
urllib3_version = urllib3_version.split('.') | ||
assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git. | ||
|
||
# Sometimes, urllib3 only reports its version as 16.1. | ||
if len(urllib3_version) == 2: | ||
urllib3_version.append('0') | ||
|
||
# Check urllib3 for compatibility. | ||
major, minor, patch = urllib3_version # noqa: F811 | ||
major, minor, patch = int(major), int(minor), int(patch) | ||
# urllib3 >= 1.21.1, <= 1.24 | ||
assert major == 1 | ||
assert minor >= 21 | ||
assert minor <= 24 | ||
|
||
# Check chardet for compatibility. | ||
major, minor, patch = chardet_version.split('.')[:3] | ||
major, minor, patch = int(major), int(minor), int(patch) | ||
# chardet >= 3.0.2, < 3.1.0 | ||
assert major == 3 | ||
assert minor < 1 | ||
assert patch >= 2 | ||
|
||
|
||
def _check_cryptography(cryptography_version): | ||
# cryptography < 1.3.4 | ||
try: | ||
cryptography_version = list(map(int, cryptography_version.split('.'))) | ||
except ValueError: | ||
return | ||
|
||
if cryptography_version < [1, 3, 4]: | ||
warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version) | ||
warnings.warn(warning, RequestsDependencyWarning) | ||
|
||
# Check imported dependencies for compatibility. | ||
try: | ||
check_compatibility(urllib3.__version__, chardet.__version__) | ||
except (AssertionError, ValueError): | ||
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported " | ||
"version!".format(urllib3.__version__, chardet.__version__), | ||
RequestsDependencyWarning) | ||
|
||
# Attempt to enable urllib3's SNI support, if possible | ||
try: | ||
from urllib3.contrib import pyopenssl | ||
pyopenssl.inject_into_urllib3() | ||
|
||
# Check cryptography version | ||
from cryptography import __version__ as cryptography_version | ||
_check_cryptography(cryptography_version) | ||
except ImportError: | ||
pass | ||
|
||
# urllib3's DependencyWarnings should be silenced. | ||
from urllib3.exceptions import DependencyWarning | ||
warnings.simplefilter('ignore', DependencyWarning) | ||
|
||
from .__version__ import __title__, __description__, __url__, __version__ | ||
from .__version__ import __build__, __author__, __author_email__, __license__ | ||
from .__version__ import __copyright__, __cake__ | ||
|
||
from . import utils | ||
from . import packages | ||
from .models import Request, Response, PreparedRequest | ||
from .api import request, get, head, post, patch, put, delete, options | ||
from .sessions import session, Session | ||
from .status_codes import codes | ||
from .exceptions import ( | ||
RequestException, Timeout, URLRequired, | ||
TooManyRedirects, HTTPError, ConnectionError, | ||
FileModeWarning, ConnectTimeout, ReadTimeout | ||
) | ||
|
||
# Set default logging handler to avoid "No handler found" warnings. | ||
import logging | ||
from logging import NullHandler | ||
|
||
logging.getLogger(__name__).addHandler(NullHandler()) | ||
|
||
# FileModeWarnings go off per the default. | ||
warnings.simplefilter('default', FileModeWarning, append=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# .-. .-. .-. . . .-. .-. .-. .-. | ||
# |( |- |.| | | |- `-. | `-. | ||
# ' ' `-' `-`.`-' `-' `-' ' `-' | ||
|
||
__title__ = 'requests' | ||
__description__ = 'Python HTTP for Humans.' | ||
__url__ = 'http://python-requests.org' | ||
__version__ = '2.21.0' | ||
__build__ = 0x022100 | ||
__author__ = 'Kenneth Reitz' | ||
__author_email__ = 'me@kennethreitz.org' | ||
__license__ = 'Apache 2.0' | ||
__copyright__ = 'Copyright 2018 Kenneth Reitz' | ||
__cake__ = u'\u2728 \U0001f370 \u2728' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
""" | ||
requests._internal_utils | ||
~~~~~~~~~~~~~~ | ||
Provides utility functions that are consumed internally by Requests | ||
which depend on extremely few external helpers (such as compat) | ||
""" | ||
|
||
from .compat import is_py2, builtin_str, str | ||
|
||
|
||
def to_native_string(string, encoding='ascii'): | ||
"""Given a string object, regardless of type, returns a representation of | ||
that string in the native string type, encoding and decoding where | ||
necessary. This assumes ASCII unless told otherwise. | ||
""" | ||
if isinstance(string, builtin_str): | ||
out = string | ||
else: | ||
if is_py2: | ||
out = string.encode(encoding) | ||
else: | ||
out = string.decode(encoding) | ||
|
||
return out | ||
|
||
|
||
def unicode_is_ascii(u_string): | ||
"""Determine if unicode string only contains ASCII characters. | ||
:param str u_string: unicode string to check. Must be unicode | ||
and not Python 2 `str`. | ||
:rtype: bool | ||
""" | ||
assert isinstance(u_string, str) | ||
try: | ||
u_string.encode('ascii') | ||
return True | ||
except UnicodeEncodeError: | ||
return False |
Oops, something went wrong.