Skip to content

Commit 46abf62

Browse files
committed
迁移到playwright;其他微调
1 parent 59d5d6d commit 46abf62

File tree

6 files changed

+253
-173
lines changed

6 files changed

+253
-173
lines changed

aiohttp_websession.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import sys
2+
import asyncio
3+
from typing import Any
4+
5+
import aiohttp
6+
7+
import printer
8+
9+
sem = asyncio.Semaphore(3)
10+
11+
12+
class WebSession:
13+
__slots__ = ('session',)
14+
15+
DEFAULT_OK_STATUS_CODES = (200,)
16+
DEFAULT_IGNORE_STATUS_CODES = ()
17+
18+
def __init__(self):
19+
self.session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=8))
20+
21+
@staticmethod
22+
async def _recv_json(rsp: aiohttp.ClientResponse):
23+
return await rsp.json(content_type=None)
24+
25+
@staticmethod
26+
async def _recv_str(rsp: aiohttp.ClientResponse):
27+
return await rsp.text()
28+
29+
@staticmethod
30+
async def _recv_bytes(rsp: aiohttp.ClientResponse):
31+
return await rsp.read()
32+
33+
@staticmethod
34+
async def _recv(rsp: aiohttp.ClientResponse):
35+
return rsp
36+
37+
# 基本就是通用的 request
38+
async def _orig_req(self, parse_rsp, method, url, keep_try=True, **kwargs):
39+
i = 0
40+
while keep_try or i == 0:
41+
i += 1
42+
if i >= 10:
43+
printer.warn(f'反复请求多次未成功, {url}, {kwargs}')
44+
await asyncio.sleep(1)
45+
try:
46+
async with self.session.request(method, url, **kwargs) as rsp:
47+
if rsp.status == 200:
48+
body = await parse_rsp(rsp)
49+
if body:
50+
return body
51+
except asyncio.CancelledError:
52+
raise
53+
except:
54+
# print('当前网络不好,正在重试,请反馈开发者!!!!')
55+
print(sys.exc_info()[0], sys.exc_info()[1], url)
56+
57+
async def request_json(self,
58+
method,
59+
url,
60+
keep_try=True,
61+
**kwargs) -> Any:
62+
return await self._orig_req(self._recv_json, method, url, keep_try, **kwargs)
63+
64+
async def request_binary(self,
65+
method,
66+
url,
67+
keep_try=True,
68+
**kwargs) -> bytes:
69+
return await self._orig_req(self._recv_bytes, method, url, keep_try, **kwargs)
70+
71+
async def request_text(self,
72+
method,
73+
url,
74+
keep_try=True,
75+
**kwargs) -> str:
76+
return await self._orig_req(self._recv_str, method, url, keep_try, **kwargs)
77+
78+
# 返回 response
79+
async def request(self,
80+
method,
81+
url,
82+
**kwargs) -> aiohttp.ClientResponse:
83+
return await self._orig_req(self._recv, method, url, **kwargs)

client.py

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1-
import time
21
import base64
32
from urllib import parse
3+
import asyncio
4+
from typing import Optional, Tuple, Any
5+
import time
46

57
import rsa
68

79
from printer import info as print
8-
from web_session import WebSession
10+
from aiohttp_websession import WebSession
911
from client_core import utils
1012

1113

1214
class Bili:
13-
def __init__(self):
15+
def __init__(self, web_session: WebSession):
1416
dict_user = utils.get_1st_user('client_core/conf/user.toml')
1517
dict_bili = utils.get_dict_bili('client_core/conf/bili.toml')
1618
self.user = utils.new_user(dict_user, dict_bili)
1719

1820
self.name = self.user.name
1921
self.password = self.user.password
20-
self.__web_session = WebSession()
22+
self._web_session = web_session
2123

22-
def get_key(self):
24+
async def get_key(self) -> Tuple[str, str]:
2325
url = f'https://passport.bilibili.com/api/oauth2/getKey'
2426
params = self.user.sort_and_sign()
25-
json_rsp = self.__web_session.request_json(
27+
json_rsp = await self._web_session.request_json(
2628
'POST', url, headers=self.user.dict_bili['appheaders'], params=params)
2729

2830
data = json_rsp['data']
@@ -37,61 +39,66 @@ def get_key(self):
3739

3840
return url_password, url_name
3941

40-
def login(self, url_password, url_name, seccode, challenge, validate):
41-
42+
async def login(self, url_password: str, url_name: str, seccode: str, challenge: str, validate: str) -> Optional[str]:
4243
extra_params = [
4344
# f'captcha=',
4445
f'password={url_password}',
4546
f'username={url_name}',
4647
f'ts={utils.curr_time()}',
47-
f'seccode={"" if not seccode else parse.quote_plus(seccode)}',
48-
f'challenge={"" if not challenge else parse.quote_plus(challenge)}',
49-
f'validate={"" if not validate else parse.quote_plus(validate)}',
48+
f'seccode={parse.quote_plus(seccode)}',
49+
f'challenge={parse.quote_plus(challenge)}',
50+
f'validate={parse.quote_plus(validate)}',
5051

5152
]
5253
params = self.user.sort_and_sign(extra_params)
53-
print(params)
5454

55-
url = 'https://passport.bilibili.com/api/v3/oauth2/login'
55+
url = f'https://passport.bilibili.com/api/v3/oauth2/login?{params}'
5656

57-
json_rsp = self.__web_session.request_json(
58-
'POST', url, headers=self.user.dict_bili['appheaders'], params=params)
59-
print(json_rsp)
57+
json_rsp = await self._web_session.request_json(
58+
'POST', url, headers=self.user.dict_bili['appheaders'], params=None)
59+
print(f'login response: {json_rsp}')
6060
if json_rsp['code'] == -105:
6161
url = json_rsp['data']['url']
6262
return url
63-
raise Exception('get_captcha', json_rsp)
63+
return None
6464

6565

6666
class CrackClient:
67-
def __init__(self, url):
68-
self.__web_session = WebSession()
69-
self.__url = url
67+
def __init__(self, url, web_session: WebSession):
68+
self._web_session = web_session
69+
self._url = url
7070

71-
def request_crack(self, url):
71+
async def request_crack(self, url: str) -> Any:
7272
data = {
7373
'url': url,
7474
}
75-
json_rsp = self.__web_session.request_json('POST', f'{self.__url}/crack', json=data)
75+
json_rsp = await self._web_session.request_json('POST', f'{self._url}/crack', json=data, keep_try=False)
7676
return json_rsp
7777

7878

79-
def main():
80-
bili = Bili()
81-
crack_client = CrackClient('http://127.0.0.1:3333')
79+
async def one_try():
80+
web_session = WebSession()
81+
bili = Bili(web_session)
82+
crack_client = CrackClient('http://127.0.0.1:3333', web_session)
83+
args = await bili.get_key()
8284
while True:
83-
args = bili.get_key()
84-
url = bili.login(*args, '', '', '')
85-
print(f'url {url}')
86-
result = crack_client.request_crack(url=url)
87-
print(f'Result: {result}')
88-
print('=' * 100, need_timestamp=False)
89-
if not result['code']:
90-
data = result['data']
91-
bili.login(*args, challenge=data['challenge'], seccode=data['seccode'], validate=data['validate'])
85+
url = await bili.login(*args, '', '', '')
86+
if url is not None:
87+
break
88+
print(f'url {url}')
89+
result = await crack_client.request_crack(url=url)
90+
print(f'request_crack result: {result}')
91+
if not result['code']:
92+
data = result['data']
93+
await bili.login(*args, challenge=data['challenge'], seccode=data['seccode'], validate=data['validate'])
94+
await web_session.session.close()
95+
9296

93-
time.sleep(5)
97+
async def main():
98+
start_time = time.time()
99+
await asyncio.gather(*[one_try() for _ in range(4)])
100+
print("--- %s seconds ---" % (time.time() - start_time))
94101

95102

96103
if __name__ == "__main__":
97-
main()
104+
asyncio.get_event_loop().run_until_complete(main())
File renamed without changes.

requirements.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
requests==2.25.1
22
toml==0.10.2
3-
selenium==3.141.0
43
scikit-image==0.18.1
54
opencv_python==4.5.1.48
65
numpy==1.20.1
7-
flask==1.1.2
8-
rsa==4.7.2
6+
rsa==4.7.2
7+
playwright==1.9.1
8+
aiohttp==3.7.4post0
9+
aiojobs==0.3.0

server.py

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,55 @@
1-
from flask import Flask, jsonify, request
1+
import asyncio
2+
from typing import Tuple
3+
4+
from aiohttp import web
5+
from aiojobs.aiohttp import atomic, setup
6+
from playwright.async_api import async_playwright, BrowserContext
27

38
from server_core.cracker import Cracker
49
from server_core.track_maker import TrackMaker
510
from server_core.find_gap_position import check_gap_position
11+
from aiohttp_websession import WebSession
12+
613

7-
track_maker = TrackMaker()
14+
async def init() -> Tuple[BrowserContext, WebSession, TrackMaker]:
15+
return await (await (await async_playwright().start()).chromium.launch(headless=True)).new_context(viewport={'width': 350, 'height': 560}), WebSession(), TrackMaker()
816

9-
app = Flask(__name__)
1017

18+
context, session, track_maker = asyncio.get_event_loop().run_until_complete(init())
1119

12-
@app.route("/")
13-
def root():
14-
jsonify({
20+
21+
@atomic
22+
async def root(_: web.Request):
23+
return web.json_response({
1524
'code': 0,
1625
'data': {
17-
'msg': 'HELLO WORLD.'
18-
},
19-
})
26+
'msg': 'Hello world.'
27+
}})
2028

2129

22-
@app.route("/crack", methods=['POST'])
23-
def crack():
24-
data = request.get_json()
25-
print(data['url'])
30+
@atomic
31+
async def crack(request: web.Request):
32+
try:
33+
json_data = await request.json()
34+
except:
35+
return web.json_response({
36+
'code': -1,
37+
'data': {
38+
'msg': 'Hello world.'
39+
}})
2640

27-
cracker = Cracker('C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe')
41+
page = await context.new_page()
42+
cracker = Cracker(page, session)
2843

29-
load_result = cracker.load_url(url=data['url'])
44+
load_result = await cracker.load_url(url=json_data['url'])
3045
while load_result:
31-
cracker.refresh()
32-
load_result = cracker.load_url()
46+
await cracker.refresh()
47+
load_result = await cracker.load_url()
3348

34-
reordered_fullbg_img, reordered_bg_img, gap_img = cracker.fetch_imgs()
35-
gap_position = check_gap_position(reordered_fullbg_img, reordered_bg_img, gap_img, verbose=True)
49+
reordered_fullbg_img, reordered_bg_img, gap_img = await cracker.fetch_imgs()
50+
gap_position = check_gap_position(reordered_fullbg_img, reordered_bg_img, gap_img, verbose=False)
3651

37-
ratio = cracker.position2actual_distance(reordered_bg_img)
52+
ratio = await cracker.position2actual_distance(reordered_bg_img)
3853

3954
# resized_reordered_bg_img = cv2.resize(reordered_bg_img, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_AREA)
4055
# cv2.line(resized_reordered_bg_img,
@@ -49,11 +64,20 @@ def crack():
4964
print('生成的轨迹', distance, ratio, distance * ratio, track)
5065

5166
# cracker.slide_slider(track, ratio)
52-
cracker.test_slide_slider(distance, ratio)
53-
geetest_seccode, geetest_challenge, geetest_validate = cracker.get_result()
67+
await cracker.test_slide_slider(distance, ratio)
68+
geetest_seccode, geetest_challenge, geetest_validate = await cracker.get_result()
69+
70+
print({
71+
'seccode': geetest_seccode,
72+
'challenge': geetest_challenge,
73+
'validate': geetest_validate,
74+
})
75+
print(json_data['url'])
76+
77+
await page.close()
5478

55-
if geetest_challenge is not None:
56-
return jsonify({
79+
if geetest_challenge:
80+
return web.json_response({
5781
'code': 0,
5882
'data': {
5983
'seccode': geetest_seccode,
@@ -62,11 +86,15 @@ def crack():
6286
},
6387
})
6488

65-
return jsonify({
89+
return web.json_response({
6690
'code': -1,
6791
'data': {},
6892
})
6993

7094

7195
if __name__ == "__main__":
72-
app.run('0.0.0.0', '3333')
96+
app = web.Application()
97+
setup(app)
98+
app.router.add_route('GET', '/', root)
99+
app.router.add_route('POST', '/crack', crack)
100+
web.run_app(app, port=3333)

0 commit comments

Comments
 (0)