在线解析下载链接《飞猫盘》(附部分源码)
foxe6
2022年09月08日 21:26
收录于文集
共5篇

接招,三连奉上地址


不多废话上演示


解析过程

大概用了十个小时写好前后台加网域设置

这次当作记一次web开发过程

首先,当然要弄个帐号😏

然后,写好浏览器自动化脚本,目的是解滑块,

可惜飞猫刚刚更新了,失效了很尴尬。。。

没关系,又花了一个小时研究飞猫API和UI

终于认我找到了跳过验证码的方法

这里不说什么方法了,给打补丁了就真的尴尬了

总而言之,我把UI和API的都写好了

日后可以的话会持续更新后台

不保证解析速度,毕竟是公用的

炸了等我修复好了

需要更多功能、使用权的私我吧

web ui


部分源码

以下是浏览器rpc部分,处理解析

纯粹网页前后台就不发了

代码块
JavaScript
自动换行
复制代码
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)

复制成功