From d5d5bf90febe63cc6181652bca23ac5ae14e7fed Mon Sep 17 00:00:00 2001 From: xhy Date: Fri, 28 Mar 2025 18:23:30 +0800 Subject: [PATCH] init commit --- .gitignore | 281 ++++++++++++++++++ .idea/.gitignore | 8 + .idea/baidu-reporter.iml | 10 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + app/__init__.py | 1 + app/app.py | 123 ++++++++ app/config/__init__.py | 1 + app/config/config.py | 47 +++ app/engines/__init__.py | 0 app/engines/collector.py | 8 + app/engines/evidence.py | 7 + app/engines/reporter.py | 72 +++++ app/engines/reporters/__init__.py | 0 app/engines/reporters/base.py | 9 + app/engines/reporters/pc_reporter.py | 11 + app/engines/reporters/site_reporter.py | 9 + app/engines/reporters/wap_reporter.py | 11 + app/models/__init__.py | 0 app/models/base.py | 53 ++++ app/models/domain.py | 11 + app/models/report_urls.py | 17 ++ app/repositories/__init__.py | 0 app/utils/__init__.py | 0 app/utils/custom_base64.py | 154 ++++++++++ app/utils/dp.py | 23 ++ app/utils/ua.py | 259 ++++++++++++++++ config.local.toml | 12 + config.prod.toml | 12 + main.py | 18 ++ tests/__init__.py | 0 tests/test_custom_base64.py | 12 + tests/test_dp.py | 44 +++ tests/test_logger.py | 3 + 35 files changed, 1236 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/baidu-reporter.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 app/__init__.py create mode 100644 app/app.py create mode 100644 app/config/__init__.py create mode 100644 app/config/config.py create mode 100644 app/engines/__init__.py create mode 100644 app/engines/collector.py create mode 100644 app/engines/evidence.py create mode 100644 app/engines/reporter.py create mode 100644 app/engines/reporters/__init__.py create mode 100644 app/engines/reporters/base.py create mode 100644 app/engines/reporters/pc_reporter.py create mode 100644 app/engines/reporters/site_reporter.py create mode 100644 app/engines/reporters/wap_reporter.py create mode 100644 app/models/__init__.py create mode 100644 app/models/base.py create mode 100644 app/models/domain.py create mode 100644 app/models/report_urls.py create mode 100644 app/repositories/__init__.py create mode 100644 app/utils/__init__.py create mode 100644 app/utils/custom_base64.py create mode 100644 app/utils/dp.py create mode 100644 app/utils/ua.py create mode 100644 config.local.toml create mode 100644 config.prod.toml create mode 100644 main.py create mode 100644 tests/__init__.py create mode 100644 tests/test_custom_base64.py create mode 100644 tests/test_dp.py create mode 100644 tests/test_logger.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b624007 --- /dev/null +++ b/.gitignore @@ -0,0 +1,281 @@ +### VirtualEnv template +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +.Python +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts +pyvenv.cfg +.venv +pip-selfcheck.json + +### Windows template +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### PyCharm+all template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/baidu-reporter.iml b/.idea/baidu-reporter.iml new file mode 100644 index 0000000..e183936 --- /dev/null +++ b/.idea/baidu-reporter.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e912f80 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..9cfe7b4 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1 @@ +from .app import * \ No newline at end of file diff --git a/app/app.py b/app/app.py new file mode 100644 index 0000000..f7b2316 --- /dev/null +++ b/app/app.py @@ -0,0 +1,123 @@ +import argparse +import sys +import os + +from app.engines.reporter import Reporter + +from .config import load_config, AppConfig +from .models.base import connect_db, create_database + +from loguru import logger +import sqlalchemy.exc + + +class MainApp: + """主应用""" + + def __init__(self): + self.args = None + self.config: AppConfig = None + self.db_engine = None + + def parse_args(self): + """解析命令行参数""" + parser = argparse.ArgumentParser(description="Baidu Reporter") + + # 指定配置文件 + parser.add_argument( + "-c", + "--config", + default="./config.local.toml", + help="指定配置文件路径,默认为 ./config.local.toml", + ) + + # 添加输入文件参数 + parser.add_argument( + "-f", + "--file", + default="./urls.txt", + help="指定输入文件路径,默认为 ./urls.txt", + ) + + # 添加运行模式参数 + parser.add_argument( + "-m", + "--mode", + help="指定运行模式:pc/site/wap,不指定则运行所有模式,多个模式使用英文逗号分隔", + ) + + # 添加 web 服务器参数 + parser.add_argument( + "--web", action="store_true", help="启动 web 服务器,启动后将忽略其他选项" + ) + + # 如果没有传入任何参数,显示帮助信息 + if len(sys.argv) == 1: + parser.print_help() + sys.exit(0) + + args = parser.parse_args() + + # 处理模式参数 + if args.mode: + modes = [m.strip() for m in args.mode.split(",")] + valid_modes = ["pc", "site", "wap"] + invalid_modes = [m for m in modes if m not in valid_modes] + if invalid_modes: + parser.error(f'无效的运行模式: {", ".join(invalid_modes)}') + args.mode = modes + else: + args.mode = ["pc", "site", "wap"] + + # 检查输入的文件是否存在 + if not os.path.exists(args.file): + parser.error(f"输入的文件不存在: {args.file}") + + # 检查配置文件是否存在 + if not os.path.exists(args.config): + parser.error(f"配置文件不存在: {args.config}") + + self.args = args + + def start_cli(self): + """开启 CLI 模式""" + reporter = Reporter(self.args.file, self.args.mode, self.db_engine) + reporter.run() + + def start_web(self): + """开启 Web 模式""" + pass + + def run(self): + """运行应用""" + + # 解析命令行参数 + self.parse_args() + + # 加载配置文件 + self.config = load_config(self.args.config) + logger.info(f"加载配置文件 {self.args.config} 成功") + + # 连接数据库 + try: + self.db_engine = connect_db(self.config) + logger.info(f"连接数据库 {self.config.database.database} 成功") + except sqlalchemy.exc.OperationalError as e: + # 如果错误类型是数据库不存在,询问用户是否执行初始化操作 + if "1049" in str(e): + logger.info("数据库不存在,尝试初始化数据库") + create_database(self.config) + logger.info("数据库初始化成功,尝试连接数据库") + self.db_engine = connect_db(self.config) + logger.info(f"连接数据库 {self.config.database.database} 成功") + else: + logger.error(f"连接数据库失败,请检查配置文件或数据库服务是否正常: {e}") + sys.exit(1) + + # 如果指定了 --web 参数,启动 web 服务器,忽略其他选项 + if self.args.web: + logger.info("启动 Web 模式") + return self.start_web() + else: + logger.info("启动 CLI 模式") + return self.start_cli() diff --git a/app/config/__init__.py b/app/config/__init__.py new file mode 100644 index 0000000..9281934 --- /dev/null +++ b/app/config/__init__.py @@ -0,0 +1 @@ +from .config import load_config, AppConfig, DatabaseConfig, ChromeConfig, gAppConfig diff --git a/app/config/config.py b/app/config/config.py new file mode 100644 index 0000000..812b46d --- /dev/null +++ b/app/config/config.py @@ -0,0 +1,47 @@ +from dataclasses import dataclass +import toml + + +@dataclass +class DatabaseConfig: + """数据库配置""" + + host: str + port: int + user: str + password: str + database: str + + +@dataclass +class ChromeConfig: + """浏览器配置""" + + proxy: str + + +@dataclass +class AppConfig: + """总配置,如果未来增加 Web 服务,添加 WebConfig 即可""" + + debug: bool + database: DatabaseConfig + chrome: ChromeConfig + + +# 全局变量,存储配置信息,not best practice, but it's ok for now +gAppConfig = AppConfig() + + +def load_config(config_path: str) -> AppConfig: + """加载配置""" + with open(config_path, "r", encoding="utf-8") as f: + config_dict = toml.load(f) + + database_config = DatabaseConfig(**config_dict["database"]) + chrome_config = ChromeConfig(**config_dict["chrome"]) + + gAppConfig = AppConfig( + debug=config_dict["debug"], database=database_config, chrome=chrome_config + ) + return gAppConfig diff --git a/app/engines/__init__.py b/app/engines/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/engines/collector.py b/app/engines/collector.py new file mode 100644 index 0000000..388d425 --- /dev/null +++ b/app/engines/collector.py @@ -0,0 +1,8 @@ + +class Collector: + """色站URL采集器,自动在百度翻页搜索,并保存搜索结果""" + + def __init__(self): + pass + + diff --git a/app/engines/evidence.py b/app/engines/evidence.py new file mode 100644 index 0000000..a1d2f68 --- /dev/null +++ b/app/engines/evidence.py @@ -0,0 +1,7 @@ + +class EvidenceHolder: + """固定色站证据,搜索 URL 后截图,并生成举报链接存入数据库""" + + def __init__(self): + pass + diff --git a/app/engines/reporter.py b/app/engines/reporter.py new file mode 100644 index 0000000..79e0d7c --- /dev/null +++ b/app/engines/reporter.py @@ -0,0 +1,72 @@ +from sqlalchemy import Engine, select +from sqlmodel import Session + +from app.utils.dp import DPEngine +from .reporters.pc_reporter import PcReporter +from .reporters.wap_reporter import WapReporter +from .reporters.site_reporter import SiteReporter +from ..models.report_urls import ReportUrlModel + +from loguru import logger + + +class Reporter: + """举报器,目前有三个渠道,以后可以继续扩展""" + + def __init__(self, urls_file: str, mode: list[str], db_engine: Engine): + self.urls_file = urls_file + self.mode = mode + self.db_engine = db_engine + + # 初始化其他的 reporter + self.reporters = { + "pc": PcReporter(), + "wap": WapReporter(), + "site": SiteReporter(), + } + + # TODO 初始化 reporter 需要的公共数据,比如headless chrome等等 + # self.baseDP = DPEngine(is_wap=False, no_img=True) + + def run(self): + """开始k站""" + self.get_reports_data() + + def get_reports_data(self): + """获取举报数据:页面截图,举报链接等,并存到数据库中""" + + urls = self.read_urls() + logger.info(f"从文件 {self.urls_file} 读取到 {len(urls)} 个 URL") + + # 如果数据库中已经有了,就跳过 + # 如果数据库中没有,去获取页面截图、举报链接 + # 如果获取成功,就插入数据库 + # 如果获取失败,就记录日志 + dp = DPEngine(is_wap=False, no_img=True) # 用来截图的浏览器实例 + with Session(self.db_engine) as session: + for url in urls: + stmt = select(ReportUrlModel).where(ReportUrlModel.surl == url) + report_url = session.exec(stmt).one_or_none() + logger.debug(f"查询 {url} 的结果: {report_url}") + if report_url: + continue + + # 获取页面截图、举报链接 + # 1. 打开baidu搜索URL,如果有结果就截一张图,没有的话就跳过 + # 2. 点击举报按钮,获取举报链接 + # 3. 打开 URL 截一张图 + # 4. 存到数据库里 + dp.browser.new_tab(url) + + + def read_urls(self) -> list[str]: + """读取 urls 文件""" + urls: list[str] = [] + with open(self.urls_file, "r") as fp: + for url in fp: + url = url.strip() + if not url: + continue + urls.append(url) + return urls + diff --git a/app/engines/reporters/__init__.py b/app/engines/reporters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/engines/reporters/base.py b/app/engines/reporters/base.py new file mode 100644 index 0000000..adefa81 --- /dev/null +++ b/app/engines/reporters/base.py @@ -0,0 +1,9 @@ +from abc import ABC, abstractmethod + +class BaseReporter(ABC): + """所有 reporter 的基类""" + + @abstractmethod + def run(self): + """运行 reporter,子类必须实现此方法""" + pass diff --git a/app/engines/reporters/pc_reporter.py b/app/engines/reporters/pc_reporter.py new file mode 100644 index 0000000..15c9f92 --- /dev/null +++ b/app/engines/reporters/pc_reporter.py @@ -0,0 +1,11 @@ +from .base import BaseReporter + +class PcReporter(BaseReporter): + def __init__(self): + pass + + def run(self): + """实现 PC 端的举报逻辑""" + pass + + diff --git a/app/engines/reporters/site_reporter.py b/app/engines/reporters/site_reporter.py new file mode 100644 index 0000000..07ad950 --- /dev/null +++ b/app/engines/reporters/site_reporter.py @@ -0,0 +1,9 @@ +from .base import BaseReporter + +class SiteReporter(BaseReporter): + def __init__(self): + pass + + def run(self): + """实现 PC 端的举报逻辑""" + pass diff --git a/app/engines/reporters/wap_reporter.py b/app/engines/reporters/wap_reporter.py new file mode 100644 index 0000000..09dd960 --- /dev/null +++ b/app/engines/reporters/wap_reporter.py @@ -0,0 +1,11 @@ +from .base import BaseReporter + +class WapReporter(BaseReporter): + def __init__(self): + pass + + def run(self): + """实现 WAP 端的举报逻辑""" + pass + + diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/models/base.py b/app/models/base.py new file mode 100644 index 0000000..271f009 --- /dev/null +++ b/app/models/base.py @@ -0,0 +1,53 @@ +from datetime import datetime + +from sqlalchemy import create_engine, event, text +from sqlalchemy.dialects.mysql import BIGINT +from sqlmodel import SQLModel, Field, Session +from sqlalchemy.exc import OperationalError +from loguru import logger + +from ..config import AppConfig + + +def get_timestamp(): + return int(datetime.now().timestamp()) + + +class BaseModel(SQLModel): + """数据库基类""" + + id: int = Field(default=None, primary_key=True, sa_type=BIGINT(unsigned=True)) + created_at: int = Field(default=get_timestamp, sa_type=BIGINT(unsigned=True)) + updated_at: int = Field(default=get_timestamp, sa_type=BIGINT(unsigned=True)) + + +@event.listens_for(BaseModel, "before_update") +def update_updated_at(mapper, connection, target): + """更新数据库记录的时候,自动更新 updated_at 字段""" + target.updated_at = get_timestamp() + + + +def connect_db(config: AppConfig): + """连接数据库""" + + # 导入所有模型,为了自动创建数据表 + from .domain import DomainModel + from .report_urls import ReportUrlModel + + dsn = f"mysql+pymysql://{config.database.user}:{config.database.password}@{config.database.host}:{config.database.port}/{config.database.database}" + engine = create_engine(dsn, echo=config.debug) + + SQLModel.metadata.create_all(engine) + + return engine + +def create_database(config: AppConfig): + """如果数据库不存在,就调用这个函数初始化数据库""" + + dsn = f"mysql+pymysql://{config.database.user}:{config.database.password}@{config.database.host}:{config.database.port}" + engine = create_engine(dsn, echo=config.debug) + + with engine.connect() as conn: + conn.execute(text(f"CREATE DATABASE IF NOT EXISTS {config.database.database} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")) + conn.commit() diff --git a/app/models/domain.py b/app/models/domain.py new file mode 100644 index 0000000..647d845 --- /dev/null +++ b/app/models/domain.py @@ -0,0 +1,11 @@ +from sqlmodel import Field +from sqlalchemy import VARCHAR + +from .base import BaseModel + + +class DomainModel(BaseModel, table=True): + """存储域名的模型""" + + domain: str = Field(alias="domain", default="", sa_type=VARCHAR(1024)) + status: int = Field(alias="status", default=0) diff --git a/app/models/report_urls.py b/app/models/report_urls.py new file mode 100644 index 0000000..262bf13 --- /dev/null +++ b/app/models/report_urls.py @@ -0,0 +1,17 @@ +from sqlalchemy import VARCHAR +from sqlmodel import Field + +from .base import BaseModel + + +class ReportUrlModel(BaseModel, table=True): + """存储举报 URL 的模型""" + + domain: str = Field(alias="domain", default="", sa_type=VARCHAR(1024)) + surl: str = Field(alias="surl", default="", sa_type=VARCHAR(2048)) # 待举报的 URL + token: str = Field(alias="token", default="", sa_type=VARCHAR(64)) + title: str = Field(alias="title", default="", sa_type=VARCHAR(1024)) + q: str = Field(alias="q", default="", sa_type=VARCHAR(1024)) # TODO: 这是干啥的? + is_report_by_one: bool = Field(alias="is_report_by_one", default=False) + is_report_by_site: bool = Field(alias="is_report_by_site", default=False) + is_report_by_wap: bool = Field(alias="is_report_by_wap", default=False) diff --git a/app/repositories/__init__.py b/app/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/custom_base64.py b/app/utils/custom_base64.py new file mode 100644 index 0000000..021b313 --- /dev/null +++ b/app/utils/custom_base64.py @@ -0,0 +1,154 @@ +import base64 + +from loguru import logger + + +class CustomBase64: + """自定义的Base64编码和解码""" + + mapping = { + "Y": "V", + "X": "U", + "A": "Z", + "s": "p", + "J": "G", + "F": "C", + "U": "R", + "u": "r", + "W": "T", + "i": "f", + "V": "S", + "E": "B", + "2": "2", + "P": "M", + "C": "X", + "8": "8", + "r": "o", + "L": "I", + "H": "E", + "M": "J", + "j": "g", + "b": "y", + "p": "m", + "O": "L", + "l": "i", + "R": "O", + "G": "D", + "I": "F", + "y": "v", + "t": "q", + "0": "0", + "c": "x", + "Q": "N", + "7": "7", + "N": "K", + "3": "3", + "Z": "W", + "n": "k", + "1": "1", + "d": "a", + "5": "5", + "S": "P", + "K": "H", + "h": "e", + "k": "h", + "w": "t", + "T": "Q", + "4": "4", + "m": "j", + "z": "w", + "g": "d", + "D": "A", + "v": "s", + "B": "Y", + "/": "/", + "q": "n", + "f": "c", + "a": "z", + "9": "9", + "o": "l", + "e": "b", + "x": "u", + } + reverse_mapping = { + "V": "Y", + "U": "X", + "Z": "A", + "p": "s", + "G": "J", + "C": "F", + "R": "U", + "r": "u", + "T": "W", + "f": "i", + "S": "V", + "B": "E", + "2": "2", + "M": "P", + "X": "C", + "8": "8", + "o": "r", + "I": "L", + "E": "H", + "J": "M", + "g": "j", + "y": "b", + "m": "p", + "L": "O", + "i": "l", + "O": "R", + "D": "G", + "F": "I", + "v": "y", + "q": "t", + "0": "0", + "x": "c", + "N": "Q", + "7": "7", + "K": "N", + "3": "3", + "W": "Z", + "k": "n", + "1": "1", + "a": "d", + "5": "5", + "P": "S", + "H": "K", + "e": "h", + "h": "k", + "t": "w", + "Q": "T", + "4": "4", + "j": "m", + "w": "z", + "d": "g", + "A": "D", + "s": "v", + "Y": "B", + "/": "/", + "n": "q", + "c": "f", + "z": "a", + "9": "9", + "l": "o", + "b": "e", + "u": "x", + } + + @staticmethod + def decode(encoded): + std_encoded = "".join(CustomBase64.reverse_mapping.get(c, c) for c in encoded) + if not len(std_encoded) % 4 == 0: + std_encoded = std_encoded + "=" * (4 - len(std_encoded) % 4) + try: + decoded = base64.b64decode(std_encoded).decode() + return decoded + except Exception as e: + logger.error(f"解码错误: {e}") + return None + + @staticmethod + def encode(text): + std_encoded = base64.b64encode(text.encode()).decode() + custom_encoded = "".join(CustomBase64.mapping.get(c, c) for c in std_encoded) + return custom_encoded.replace("=", "") diff --git a/app/utils/dp.py b/app/utils/dp.py new file mode 100644 index 0000000..cad7b21 --- /dev/null +++ b/app/utils/dp.py @@ -0,0 +1,23 @@ +from DrissionPage import Chromium, ChromiumOptions + +from app.config import gAppConfig +from app.utils import random_ua + +class DPEngine: + """DrissionPage 引擎""" + + def __init__(self, is_wap: bool = False, no_img: bool = True): + chrome_opts = ChromiumOptions() + chrome_opts.mute(True) # 静音 + chrome_opts.headless(True) # 无头模式 + chrome_opts.no_image(no_img) # 不加载图片 + chrome_opts.set_argument("--disable-gpu") # 禁用GPU + chrome_opts.set_argument('--ignore-certificate-errors') # 忽略证书错误 + chrome_opts.set_argument('--start-maximized') # 最大化启动 + chrome_opts.set_argument(f'--user-agent={random_ua(is_wap)}') # 设置 UA + # 设置代理 + if gAppConfig.chrome.proxy: + chrome_opts.set_argument('--proxy-server', gAppConfig.chrome.proxy) + + # 创建浏览器对象 + self.browser = Chromium(addr_or_opts=chrome_opts) diff --git a/app/utils/ua.py b/app/utils/ua.py new file mode 100644 index 0000000..faf847c --- /dev/null +++ b/app/utils/ua.py @@ -0,0 +1,259 @@ +import random +import os +import time + +# 尝试使用/dev/urandom作为随机数种子,如果不可用则使用time.time() +try: + with open('/dev/urandom', 'rb') as f: + random.seed(int.from_bytes(f.read(4), 'big')) +except (FileNotFoundError, OSError): + random.seed(int(time.time())) + +WAP_UA = [ + "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G960F) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.0 Chrome/87.0.4280.141 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.74 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 7.0; Nexus 5X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 9; Redmi Note 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; Mi 11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A5010) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A715F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; P30 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J730F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-N975U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 8.0.0; Pixel XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 6.0.1; Galaxy J7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A217F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G960U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-M315F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G996U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A105F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A505FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1", + "Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-M307FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G988B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A207F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-J600G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J410F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A515F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A715F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J610F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A105FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A217M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G965F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Moto G6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A305F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 7.0; SM-G610F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J415FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A526B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A205F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A405FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G930F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SM-G900F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; Redmi 7A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A715FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; Moto G5 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A605FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G960FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; Redmi Note 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G955F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1; Nokia 5.1 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G991U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A105FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G780F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G960W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A515FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Moto G5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; Redmi Note 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A505G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-A525F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A605G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-N960F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G991N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A505U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 7.0; Moto G4 Plus) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.93 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G988N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G770F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A505F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-N975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G973N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G781B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Redmi 6A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-A725F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A307FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J415G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A715GM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Moto G6 Play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-A515W) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A705FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G950N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-N986N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A202F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G986B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G965N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A405G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G770U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J810G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-M215F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SM-G935F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; Mi A3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J810Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-J730G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A750F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G970F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-G988U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-M305F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G981U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-J600FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-J701F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Redmi Note 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G986U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A405FM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-J701M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; Pixel 2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-N971N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A305FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A217F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.93 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-A405FM) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-A202G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-J610FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G996B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; SM-N975U1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 9; SM-G950U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36", +] + +PC_UA = [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.137 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.92 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.77 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36", + "Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.124 Safari/537.36", + "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.61 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/82.0.4085.124 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_4_11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_3_9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.146 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_2_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_1_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/17.0.963.83 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/11.0.696.77 Safari/537.36", +] + +def random_ua(is_wap: bool = False) -> str: + """获取 UA """ + if is_wap: + return random.choice(WAP_UA) + else: + return random.choice(PC_UA) + diff --git a/config.local.toml b/config.local.toml new file mode 100644 index 0000000..ac29e81 --- /dev/null +++ b/config.local.toml @@ -0,0 +1,12 @@ +debug = true + +[database] +host = "localhost" +port = 3306 +user = "root" +password = "123456" +database = "baidu_reporter" + +[chrome] +proxy = "http://127.0.0.1:7890" +browser_path = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" \ No newline at end of file diff --git a/config.prod.toml b/config.prod.toml new file mode 100644 index 0000000..292dcf1 --- /dev/null +++ b/config.prod.toml @@ -0,0 +1,12 @@ +debug = false + +[database] +host = "localhost" +port = 3306 +user = "root" +password = "123456" +database = "baidu_reporter" + +[chrome] +proxy = "http://127.0.0.1:7890" +browser_path = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" diff --git a/main.py b/main.py new file mode 100644 index 0000000..bfc0201 --- /dev/null +++ b/main.py @@ -0,0 +1,18 @@ +from app import MainApp +import sys + +import traceback + + +def main(): + try: + app = MainApp() + app.run() + except Exception as e: + print(f"程序运行失败,错误 {e} 信息如下:") + traceback.print_exc() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_custom_base64.py b/tests/test_custom_base64.py new file mode 100644 index 0000000..bb5f299 --- /dev/null +++ b/tests/test_custom_base64.py @@ -0,0 +1,12 @@ +from app.utils import custom_base64 +from loguru import logger + +raw = "hello! 你好!" + +data = custom_base64.CustomBase64.encode(raw) +logger.debug(data) + +decodeData = custom_base64.CustomBase64.decode(data) +logger.debug(decodeData) + +assert decodeData == raw \ No newline at end of file diff --git a/tests/test_dp.py b/tests/test_dp.py new file mode 100644 index 0000000..1ed0853 --- /dev/null +++ b/tests/test_dp.py @@ -0,0 +1,44 @@ +from DrissionPage import Chromium, ChromiumOptions + +def md5_hash(text: str): + """计算文本的 MD5 哈希值""" + import hashlib + return hashlib.md5(text.encode()).hexdigest() + +chrome_opts = ChromiumOptions() +chrome_opts.mute(True) # 静音 +chrome_opts.no_imgs(False) +chrome_opts.set_argument("--disable-gpu") +chrome_opts.set_argument('--ignore-certificate-errors') +chrome_opts.set_argument("--proxy-server=http://127.0.0.1:7890") +chrome_opts.incognito(True) +chrome_opts.set_browser_path(r"C:\Program Files\Google\Chrome\Application\chrome.exe") +browser = Chromium(addr_or_opts=chrome_opts) + +domain = "www.yunzhiju.net" +keyword = "www.yunzhiju.net/zxysx/9850.html" + +# tab = browser.new_tab(f"https://www.baidu.com/s?wd={keyword}") +# tab = browser.new_tab(f"https://ip.im") + +tab = browser.new_tab(f"https://www.baidu.com/s?wd={keyword}") + +# tab.wait.eles_loaded('#timeRlt') +# time_rtl_el = tab.ele('#timeRlt') +# print(time_rtl_el.text) +# time_rtl_el.click(by_js=True) + +# tab.wait.eles_loaded("@class:time_pop_") +# week_btn_el = tab.ele('t:li@@text()= 一月内 ') +# week_btn_el.click(by_js=True) +# tab.wait(2) + +if "未找到相关结果" in tab.html: + print("未找到相关结果") +else: + print("找到相关结果") + img_path = f"./imgs/{domain}/{md5_hash(keyword)}.png" + print(img_path) + tab.get_screenshot(img_path) + + diff --git a/tests/test_logger.py b/tests/test_logger.py new file mode 100644 index 0000000..71e8174 --- /dev/null +++ b/tests/test_logger.py @@ -0,0 +1,3 @@ +from loguru import logger + +logger.debug("111") \ No newline at end of file