
接招,三连奉上地址

大概用了十个小时写好前后台加网域设置
这次当作记一次web开发过程
首先,当然要弄个帐号😏
然后,写好浏览器自动化脚本,目的是解滑块,
可惜飞猫刚刚更新了,失效了很尴尬。。。
没关系,又花了一个小时研究飞猫API和UI
终于认我找到了跳过验证码的方法
这里不说什么方法了,给打补丁了就真的尴尬了
总而言之,我把UI和API的都写好了
日后可以的话会持续更新后台
不保证解析速度,毕竟是公用的
炸了等我修复好了
需要更多功能、使用权的私我吧

web ui
以下是浏览器rpc部分,处理解析
纯粹网页前后台就不发了
from playwright.sync_api import sync_playwright, Response, Request, Route
from omnitools import def_template, WriterU
from unencryptedsocket import SS, SC
import threadwrapper
import traceback
import threading
import requests
import random
import pickle
import json
import time
import math
import os
import re
def show_exception(o):
def _(*args, **kwargs):
try:
return o(*args, **kwargs)
except:
import traceback
print(o, args, kwargs, traceback.format_exc())
return _
def handle_popup(page):
add_page_handlers(page)
def add_page_handlers(page):
page.on("popup", handle_popup)
def save_storage_state(context):
open("auth.json", "wb").write(json.dumps(context.storage_state(), indent=2).encode())
def _add_job(jobs):
def _(t, v):
jobs[t] = v
return True
return _
def _get_job_result(job_results):
def _(t):
try:
return job_results.pop(t)
except:
return KeyError()
return _
def wait(page, selector, timeout=10):
t = time.time()
while time.time()-t<timeout:
if ":visible" in selector:
r = page.evaluate("()=>{{let e=document.querySelector(`{}`);return !!(e&&e.offsetParent);}}".format(selector.replace(":visible", "")))
else:
r = page.evaluate("()=>!!document.querySelector(`{}`)".format(selector))
if r:
return True
page.wait_for_timeout(100)
return False
def solve_slide(page):
if not wait(page, ".noCaptchaModel .btn_slide:visible"):
raise
btn_slide = page.query_selector(".noCaptchaModel .btn_slide")
box = page.evaluate("(e)=>e.getBoundingClientRect()", btn_slide)
btn_slide_x = box["x"]
btn_slide_y = box["y"]
btn_slide_w = box["width"]
btn_slide_h = box["height"]
btn_slide_mx = btn_slide_x+btn_slide_w/2
btn_slide_my = btn_slide_y+btn_slide_h/2
slide_w = 400
slide_h_offset = random.randint(-100, 100)
step = random.randint(10, 20)
def coordinates():
steps = math.ceil(slide_w/step)
for _ in range(0, steps):
yield [
_ == 0,
_ == steps-1,
btn_slide_mx+slide_w/steps*_,
btn_slide_my+slide_h_offset/steps*_,
]
for first, last, x, y in coordinates():
page.mouse.move(x, y)
if first:
page.mouse.down(button="left")
if last:
page.mouse.up(button="left")
def goto(page, url, retry=5):
for _ in range(0, retry):
try:
page.goto(url)
return True
except:
time.sleep(1)
raise RuntimeError("goto", url)
def login():
with sync_playwright() as pw:
driver = pw.webkit.launch(
timeout=5000,
headless=not True,
)
context = driver.new_context(
locale="en-US",
timezone_id="America/Phoenix",
viewport={"width": 1280, "height": 1000},
ignore_https_errors=True,
bypass_csp=True,
color_scheme="dark",
)
page = context.new_page()
goto(page, "https://www.feimaoyun.com/login?path=home")
if not wait(page, "div.infolist.pointer div.one:nth-child(2)"):
raise
page.click("div.infolist.pointer div.one:nth-child(2)")
if not wait(page, ".user > div:not([slot]) input"):
raise
username, pw = page.query_selector_all(".user > div:not([slot]) input")
username.type(..., delay=50)
pw.type(..., delay=50)
page.query_selector(".loginbtn button").click(delay=100)
# if wait(page, ".noCaptchaModel"):
# solve_slide(page)
# if wait(page, ".vipIcon"):
# save_storage_state(context)
# else:
# raise RuntimeError("cannot login")
# time.sleep(5)
# 自己去验证,好了按回车
if input("done? "):
save_storage_state(context)
driver.close()
# 已失效
def resolve2(context, page, jobs, job_results):
detail = []
resolved = []
def router1(route: Route):
try:
response = page.request.fetch(route.request)
resolved.append(response.json()["data"])
route.abort()
except:
traceback.print_exc()
page.route(re.compile("svipdown_v2$"), router1)
def router2(route: Route):
try:
response = page.request.fetch(route.request)
detail.append(response.json()["data"]["file_name"])
route.fulfill(response=response)
except:
traceback.print_exc()
page.route(re.compile("new_detailv2$"), router2)
goto(page, "https://www.feimaoyun.com/home")
print("started")
while True:
try:
k = next(iter(jobs.keys()))
url, pw = jobs.pop(k)
print(url, pw)
resolved.clear()
detail.clear()
try:
goto(page, url)
if not wait(page, "div.act.act1:visible"):
raise RuntimeError("div.act.act1 not found")
page.query_selector("div.act.act1").click(delay=50)
if wait(page, ".noCaptchaModel"):
solve_slide(page)
t = time.time()
while time.time()-t<20:
try:
if resolved:
r = {"url": resolved.pop(), "name": detail.pop()}
save_storage_state(context)
break
else:
raise
except:
page.wait_for_timeout(100)
if time.time()-t>=20:
raise RuntimeError("resolve timeout")
except:
r = traceback.format_exc()
job_results[k] = r
except StopIteration:
page.wait_for_timeout(10)
def resolve(context, page, jobs, job_results, startSS):
handling = set()
handle_lock = threading.Lock()
tw = threadwrapper.ThreadWrapper(threading.Semaphore(128))
s = requests.Session()
[s.cookies.set(_["name"], _["value"], domain=_["domain"], path=_["path"]) for _ in context.cookies()]
goto(page, "https://www.feimaoyun.com/home")
page.once("request", lambda x: [s.headers.update(x.all_headers()), s.headers.pop("host")])
startSS()
print("started")
class Return(Exception):
pass
def cleanup(id):
...
@show_exception
def job(k, url, pw):
if time.time()-k>=30:
job_results[k] = "queue job timeout"
return
pw = pw or ""
code = None
r = None
try:
with handle_lock:
code = url.split("/s/", 1)[-1]
if len(code) != 8 or not re.search(r"^[a-z0-9]+$", code):
code = None
r = {"error": "incorrect file code format"}
raise Return()
while True:
if time.time()-k>=30:
job_results[k] = "queue job timeout"
return
with handle_lock:
_ = code in handling
if _:
time.sleep(1)
continue
break
handling.add(code)
# print("code={}&pucode={}".format(code, pw))
response = s.post(
"https://www.feimaoyun.com/index.php/down/new_detailv2",
data={
"code": code,
"pucode": pw
}
)
response = response.json()
# print(response)
if response["status"] != 1:
r = {"error": "file not found"}
raise Return()
file_id = response["data"]["file_id"]
file_name = response["data"]["file_name"]
file_size = int(response["data"]["file_origin_size"])
if file_size >= 5*1024*1024*1024:
r = {"error": "file exceeds 5GB"}
raise Return()
# 机密
...
threading.Thread(target=cleanup, args=(files[0],)).start()
r = {"name": file_name, "size": file_size, "link": response["data"]}
except Exception as e:
if not r:
r = traceback.format_exc()
if not isinstance(e, Return):
print(r)
r = {"error": r}
if code:
with handle_lock:
handling.remove(code)
job_results[k] = r
ptime = time.time()
while True:
try:
if time.time()-ptime>60*10:
ptime = time.time()
page.reload()
save_storage_state(context)
k = next(iter(jobs.keys()))
url, pw = jobs.pop(k)
tw.add(job=def_template(job, k, url, pw))
page.wait_for_timeout(100)
except StopIteration:
page.wait_for_timeout(10)
def main(sc_port):
if not os.path.isfile("auth.json"):
for _ in range(0, 5):
try:
login()
break
except:
if _ == 4:
raise
jobs = dict()
job_results = dict()
add_job = _add_job(jobs)
get_job_result = _get_job_result(job_results)
def startSS():
ss = SS(host="127.0.0.1", port=sc_port, silent=True, functions=dict(
get_job_result=get_job_result,
add_job=add_job,
))
p = threading.Thread(target=lambda: ss.start())
p.daemon = True
p.start()
with sync_playwright() as pw:
driver = pw.webkit.launch(
timeout=5000,
headless=not True,
)
context = driver.new_context(
locale="en-US",
timezone_id="America/Phoenix",
viewport={"width": 400, "height": 300},
ignore_https_errors=True,
bypass_csp=True,
color_scheme="dark",
storage_state="auth.json",
)
o_new_page = context.new_page
def new_page():
page = o_new_page()
add_page_handlers(page)
return page
context.new_page = new_page
page = context.new_page()
resolve(context, page, jobs, job_results, startSS)
driver.stop()
if __name__ == "__main__":
main(39991)