ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MediaCrawler 项目架构深度解析:爬虫基类体系、存储工厂与反爬基础设施实现

MediaCrawler 项目架构深度解析:爬虫基类体系、存储工厂与反爬基础设施实现 MediaCrawler 项目架构深度解析爬虫基类体系、存储工厂与反爬基础设施实现【免费下载链接】MediaCrawler小红书笔记 | 评论爬虫、抖音视频 | 评论爬虫、快手视频 | 评论爬虫、B 站视频 评论爬虫、微博帖子 评论爬虫、百度贴吧帖子 百度贴吧评论回复爬虫 | 知乎问答文章评论爬虫项目地址: https://gitcode.com/GitHub_Trending/me/MediaCrawler本文基于仓库内的 项目架构文档 展开逐层剖析 MediaCrawler 这个多平台自媒体爬虫框架的系统架构从入口层、爬虫基类体系、平台客户端层到存储工厂与代理/缓存等基础设施并结合 main.py、base/base_crawler.py、proxy/proxy_ip_pool.py 等源码印证每一层的设计意图与调用关系。读完本篇你可以掌握该项目的分层设计、三种爬虫模式的运作机制、7 种数据存储方式的工厂化实现以及如何在此基础上扩展新平台、新存储方式与新代理提供商。1. 项目概述1.1 项目简介MediaCrawler 是一个多平台自媒体爬虫框架采用 Python 异步编程实现支持爬取主流社交媒体平台的内容、评论和创作者信息。项目基于 asyncio Playwright 构建浏览器自动化能力以 httpx 发起 API 请求以 SQLAlchemy / Motor 完成多形态数据落盘。1.2 支持的平台平台代号主要功能小红书xhs笔记搜索、详情、创作者抖音dy视频搜索、详情、创作者快手ks视频搜索、详情、创作者B站bili视频搜索、详情、UP主微博wb微博搜索、详情、博主百度贴吧tieba帖子搜索、详情知乎zhihu问答搜索、详情、答主这 7 个平台代号与 main.py 中CrawlerFactory.CRAWLERS的注册表一一对应class CrawlerFactory: CRAWLERS: dict[str, Type[AbstractCrawler]] { xhs: XiaoHongShuCrawler, dy: DouYinCrawler, ks: KuaishouCrawler, bili: BilibiliCrawler, wb: WeiboCrawler, tieba: TieBaCrawler, zhihu: ZhihuCrawler, }传入未知平台时工厂会抛出ValueError并列出所有受支持的代号main.py。1.3 核心功能特性多平台支持统一的爬虫接口支持 7 大主流平台多种登录方式二维码、手机号、Cookie 三种登录方式对应 base/base_crawler.py 中AbstractLogin的三个抽象方法多种存储方式CSV、JSON、JSONL、SQLite、MySQL、MongoDB、Excel另含 PostgreSQL 选项见 config/base_config.py 与 cmd_arg/arg.py 的SaveDataOptionEnum反爬虫对策CDP 模式、代理 IP 池、请求签名异步高并发基于 asyncio 的异步架构高效并发爬取词云生成自动生成评论词云图由 main.py 在爬取结束后按需触发依赖 docs/hit_stopwords.txt 停用词表与 docs/STZHONGS.TTF 中文字体。2. 系统架构总览2.1 高层架构图入口层的实际调用链在 main.py 中可以看到main()先调用cmd_arg.parse_cmd()解析命令行并覆写全局配置随后由CrawlerFactory.create_crawler(platformconfig.PLATFORM)构造平台爬虫实例并await crawler.start()。此外还有两个收尾动作若SAVE_DATA_OPTION excel则调用ExcelStoreBase.flush_all()刷盘main.py若存储方式为json/jsonl且开启了ENABLE_GET_WORDCLOUD则生成评论词云。2.2 数据流向图3. 目录结构MediaCrawler/ ├── main.py # 程序入口 ├── var.py # 全局上下文变量 ├── pyproject.toml # 项目配置 │ ├── base/ # 基础抽象类 │ └── base_crawler.py # 爬虫、登录、存储、客户端基类 │ ├── config/ # 配置管理 │ ├── base_config.py # 核心配置 │ ├── db_config.py # 数据库配置 │ └── {platform}_config.py # 平台特定配置 │ ├── media_platform/ # 平台爬虫实现 │ ├── xhs/ # 小红书 │ ├── douyin/ # 抖音 │ ├── kuaishou/ # 快手 │ ├── bilibili/ # B站 │ ├── weibo/ # 微博 │ ├── tieba/ # 百度贴吧 │ └── zhihu/ # 知乎 │ ├── store/ # 数据存储 │ ├── excel_store_base.py # Excel存储基类 │ └── {platform}/ # 各平台存储实现 │ ├── database/ # 数据库层 │ ├── models.py # ORM模型定义 │ ├── db_session.py # 数据库会话管理 │ └── mongodb_store_base.py # MongoDB基类 │ ├── proxy/ # 代理管理 │ ├── proxy_ip_pool.py # IP池管理 │ ├── proxy_mixin.py # 代理刷新混入 │ └── providers/ # 代理提供商 │ ├── cache/ # 缓存系统 │ ├── abs_cache.py # 缓存抽象类 │ ├── local_cache.py # 本地缓存 │ └── redis_cache.py # Redis缓存 │ ├── tools/ # 工具模块 │ ├── app_runner.py # 应用运行管理 │ ├── browser_launcher.py # 浏览器启动 │ ├── cdp_browser.py # CDP浏览器管理 │ ├── crawler_util.py # 爬虫工具 │ └── async_file_writer.py # 异步文件写入 │ ├── model/ # 数据模型 │ └── m_{platform}.py # Pydantic模型 │ ├── libs/ # JS脚本库 │ └── stealth.min.js # 反检测脚本 │ └── cmd_arg/ # 命令行参数 └── arg.py # 参数定义从源码结构看除上述架构文档列出的目录外仓库根目录还包含api/FastAPI 路由与服务层提供 Web 端运行爬虫与数据查询接口和webui/React Vite 前端两个目录它们构成面向 Web 的操作入口可视为入口层的补充形态本架构文档的主体聚焦于main.py驱动的 CLI 运行路径。4. 核心模块详解4.1 爬虫基类体系对照 base/base_crawler.py 的源码这套基类体系有几个值得注意的实现细节AbstractCrawler定义了start()、search()两个抽象方法与launch_browser()抽象方法launch_browser_with_cdp()是可选实现默认实现会回退到标准模式async def launch_browser_with_cdp(self, playwright, playwright_proxy, user_agent, headlessTrue): # Default implementation: fallback to standard mode return await self.launch_browser(playwright.chromium, playwright_proxy, user_agent, headless)这意味着不支持 CDP 的平台无需额外处理自动走 Playwright 启动 Chromium 的路径base/base_crawler.py。AbstractStore只强制要求store_content、store_comment、store_creator三个抽象方法store_image/store_video被拆分为独立的AbstractStoreImage/AbstractStoreVideo源码注释标明当前仅微博平台实现了媒体文件存储base/base_crawler.py。ProxyRefreshMixin是一个横切关注点被各平台 Client 组合继承。其实现约定非常明确proxy/proxy_mixin.py客户端类先调用init_proxy_pool(proxy_ip_pool)注入代理池引用每次发起request()前调用await _refresh_proxy_if_expired()若当前代理过期则调用get_or_refresh_proxy()取出新代理并刷新客户端自身的self.proxyhttpx 代理 URL若未注入代理池即未开启代理该方法直接返回对无代理场景零侵入。4.2 爬虫生命周期生命周期末端的清理逻辑在 main.py 中有具体落地async_cleanup()会优先清理 CDP 管理器cdp_manager.cleanup(forceTrue)否则关闭browser_context若存储方式为db/sqlite还会关闭数据库连接。程序入口通过run(main, async_cleanup, cleanup_timeout_seconds15.0, on_first_interrupt_force_stop)挂接信号处理——第一次 CtrlC 触发清理流程第二次则强制退出这与后文第 9.2 节的应用运行管理流程图一致。4.3 平台爬虫实现结构每个平台目录包含以下核心文件media_platform/{platform}/ ├── __init__.py # 模块导出 ├── core.py # 爬虫主实现类 ├── client.py # API客户端 ├── login.py # 登录实现 ├── field.py # 字段/枚举定义 ├── exception.py # 异常定义 ├── help.py # 辅助函数 └── {特殊实现}.py # 平台特定逻辑以小红书为例media_platform/xhs/下除了上述标准文件外还有xhs_sign.py、playwright_sign.py、extractor.py等平台特定逻辑文件签名算法与数据提取快手平台则额外携带graphql/目录存放 GraphQL 查询语句B站的field.py与贴吧的测试数据test_data/也体现了各平台差异化实现。这种标准文件 特殊实现的组织方式正是扩展新平台时的模板。4.4 三种爬虫模式模式配置值功能描述适用场景搜索模式search根据关键词搜索内容批量获取特定主题内容详情模式detail获取指定ID的详情精确获取已知内容创作者模式creator获取创作者所有内容追踪特定博主/UP主detail与creator模式分别由命令行参数--specified_id、--creator_id提供 ID 列表支持完整 URL 或纯 ID逗号分隔。cmd_arg/arg.py 会按平台将解析结果写入对应平台配置例如config.XHS_SPECIFIED_NOTE_URL_LIST、config.DY_CREATOR_ID_LIST贴吧平台还会做归一化处理_normalize_tieba_note_id从/p/id链接中提取数字 ID。5. 数据存储层5.1 存储架构图5.2 存储工厂模式# 以抖音为例 class DouyinStoreFactory: STORES { csv: DouyinCsvStoreImplement, db: DouyinDbStoreImplement, json: DouyinJsonStoreImplement, jsonl: DouyinJsonlStoreImplement, sqlite: DouyinSqliteStoreImplement, mongodb: DouyinMongoStoreImplement, excel: DouyinExcelStoreImplement, } staticmethod def create_store() - AbstractStore: store_class DouyinStoreFactory.STORES.get(config.SAVE_DATA_OPTION) return store_class()从 store/douyin/_store_impl.py 可以看到各实现的真实形态文件类存储CSV/JSON/JSONL统一委托给AsyncFileWriter按contents/comments/creators三种item_type分文件写入JSONL 采用追加写入适合大规模增量爬取数据库类存储DouyinDbStoreImplementDouyinSqliteStoreImplement直接继承它实现了upsert 去重先按业务唯一键如aweme_id、comment_id查询不存在则新建并写入add_ts时间戳存在则逐字段setattr更新后commitstore/douyin/_store_impl.py这正是数据库存储带去重功能的底层依据MongoDB 存储基于 database/mongodb_store_base.py 封装的MongoDBStoreBase以collection_prefixdouyin组织集合通过save_or_update完成去重写入Excel 存储通过ExcelStoreBase.get_instance(...)返回全局单例利用__new__实现配合 main.py 中flush_all()的收尾刷盘保证程序退出前所有行数据完整落盘。各平台存储实现集中在store/{platform}/_store_impl.py中media_platform/{platform}/core.py在构造爬虫时经由各平台的StoreFactory按config.SAVE_DATA_OPTION取得具体实例存储方式的选择对爬取主流程完全透明。5.3 存储方式对比存储方式配置值优点适用场景CSVcsv简单、通用小规模数据、快速查看JSONjson结构完整、易解析API对接、数据交换JSONLjsonl追加写入、性能好大规模数据、增量爬取默认SQLitesqlite轻量、无需服务本地开发、小型项目MySQLdb性能好、支持并发生产环境、大规模数据MongoDBmongodb灵活、易扩展非结构化数据、快速迭代Excelexcel可视化、易分享报告、数据分析补充一点当前仓库的SaveDataOptionEnumcmd_arg/arg.py还支持postgresconfig/db_config.py 中已提供 PostgreSQL 的连接配置而词云生成仅在json/jsonl两种文件存储方式下可用main.py。6. 基础设施层6.1 代理系统架构proxy/proxy_ip_pool.py 中ProxyIpPool的关键行为值得逐条对应load_proxies()调用提供商的get_proxy(ip_pool_count)拉取 IP 列表池容量由IP_PROXY_POOL_COUNT控制get_proxy()随机抽取并从池中移除该 IP避免短期内重复使用抽取带retry(stopstop_after_attempt(3), waitwait_fixed(1))重试若开启校验则用 httpx 经由该代理请求https://echo.apifox.cn/状态码 200 视为有效is_current_proxy_expired(buffer_seconds30)默认提前 30 秒判定过期短时效代理如分钟级有效期不会用到失效 IPget_or_refresh_proxy()供ProxyRefreshMixin每次请求前调用未过期直接复用当前代理过期则重新抽取静态代理StaticProxyProviderproxy/proxy_ip_pool.py直接解析STATIC_PROXY_URL形如http://user:passwordhost:port并将过期时间设为极大值、跳过有效性校验。提供商注册表IpProxyProviderproxy/proxy_ip_pool.py当前映射了kuaidaili、wandouhttp、static三种proxy/providers/目录下另存有jishu_http_proxy.py等提供商实现文件从源码结构看属于可注册的扩展实现。未知提供商名会在create_ip_pool()中抛出明确的ValueError并列出合法选项。6.2 登录流程三种登录方式对应 base/base_crawler.py 中AbstractLogin的抽象方法由 cmd_arg/arg.py 的LoginTypeEnum枚举约束qrcode | phone | cookie。手机号登录的滑块验证依赖 tools/slider_util.py 实现若登录时扫码始终失败config/base_config.py 的注释建议将HEADLESS置为False打开浏览器窗口手动完成滑动验证或手机验证。登录成功后若SAVE_LOGIN_STATE True登录态会持久化到用户数据目录USER_DATA_DIR按平台名区分下次启动可直接复用。6.3 浏览器管理两种模式的配置开关集中在 config/base_config.py配置项默认值说明ENABLE_CDP_MODETrue是否使用本地 Chrome/Edge经 CDP 协议控制反检测能力更强CDP_DEBUG_PORT9222调试端口被占用时自动尝试下一个可用端口CUSTOM_BROWSER_PATH自定义浏览器路径为空则自动检测 Chrome/Edge 安装位置CDP_HEADLESSFalseCDP 模式无头开关部分反检测功能在无头下可能失效BROWSER_LAUNCH_TIMEOUT60浏览器启动超时秒CDP_CONNECT_EXISTINGTrue连接用户已打开且启用远程调试的浏览器反检测效果最佳AUTO_CLOSE_BROWSERTrue程序结束是否自动关闭浏览器标准模式下的反检测脚本来自 libs/stealth.min.js浏览器路径检测与进程拉起由 tools/browser_launcher.py、CDP 连接管理由 tools/cdp_browser.py 承担。6.4 缓存系统工厂实现见 cache/cache_factory.pycache_type memory返回ExpiringLocalCache进程内带过期时间的本地缓存cache_type redis返回RedisCache其余取值抛出ValueError。类型常量CACHE_TYPE_REDIS redis与CACHE_TYPE_MEMORY memory定义在 config/db_config.pyRedis 连接参数主机、端口、密码、库号同样支持环境变量覆盖。代理 IP 池等组件即通过该缓存体系共享代理状态。7. 数据模型7.1 ORM模型关系ORM 模型统一定义在 database/models.py 中会话管理由 database/db_session.py 提供。以抖音为例内容表DouyinAweme与评论表DouyinAwemeComment均以业务 IDaweme_id/comment_id建唯一约束创作者表为DyCreator——存储层的 upsert 去重正是依赖这些唯一键。7.2 各平台数据表平台内容表评论表创作者表抖音DouyinAwemeDouyinAwemeCommentDyCreator小红书XHSNoteXHSNoteCommentXHSCreator快手KuaishouVideoKuaishouVideoCommentKsCreatorB站BilibiliVideoBilibiliVideoCommentBilibiliUpInfo微博WeiboNoteWeiboNoteCommentWeiboCreator贴吧TiebaNoteTiebaNoteComment-知乎ZhihuContentZhihuContentCommentZhihuCreator贴吧没有创作者表创作者模式走主页 URL 解析各平台的 Pydantic 响应模型则分别定义在 model/ 下的m_{platform}.py中。8. 配置系统8.1 核心配置项以下配置来自 config/base_config.py括号内为当前仓库的实际默认值# config/base_config.py # 平台选择 PLATFORM xhs # xhs | dy | ks | bili | wb | tieba | zhihu XHS_INTERNATIONAL False # 是否使用海外版小红书 (rednote.com) # 登录配置 KEYWORDS 编程副业,编程兼职 # 关键词英文逗号分隔 LOGIN_TYPE qrcode # qrcode | phone | cookie COOKIES SAVE_LOGIN_STATE True # 爬虫配置 CRAWLER_TYPE search # search | detail | creator CRAWLER_MAX_NOTES_COUNT 15 # 爬取内容数量上限 MAX_CONCURRENCY_NUM 1 # 并发爬虫数 START_PAGE 1 # 起始页码 CRAWLER_MAX_SLEEP_SEC 2 # 请求间隔 # 评论配置 ENABLE_GET_COMMENTS True # 是否抓取一级评论 ENABLE_GET_SUB_COMMENTS False # 是否抓取二级评论 CRAWLER_MAX_COMMENTS_COUNT_SINGLENOTES 10 # 单条内容一级评论数上限 # 媒体配置 ENABLE_GET_MEIDAS False # 是否抓取图片/视频资源 # 浏览器配置 HEADLESS False ENABLE_CDP_MODE True # 使用本地 Chrome/Edge 经 CDP 控制 CDP_DEBUG_PORT 9222 CUSTOM_BROWSER_PATH CDP_HEADLESS False BROWSER_LAUNCH_TIMEOUT 60 CDP_CONNECT_EXISTING True # 连接已开启远程调试的浏览器 AUTO_CLOSE_BROWSER True # 代理配置 ENABLE_IP_PROXY False IP_PROXY_POOL_COUNT 2 IP_PROXY_PROVIDER_NAME kuaidaili # kuaidaili | wandouhttp | static STATIC_PROXY_URL # static 模式下形如 http://user:passwordhost:port # 存储配置 SAVE_DATA_OPTION jsonl # csv | db | json | jsonl | sqlite | mongodb | excel | postgres SAVE_DATA_PATH # 为空则保存到 data 目录 # 词云配置 ENABLE_GET_WORDCLOUD False CUSTOM_WORDS {零几: 年份} # 自定义词组 STOP_WORDS_FILE ./docs/hit_stopwords.txt FONT_PATH ./docs/STZHONGS.TTF DISABLE_SSL_VERIFY False # 仅企业代理/中间人代理场景启用文件末尾通过from .xhs_config import *等方式导入 7 个平台专属配置config/base_config.py例如各平台的*_SPECIFIED_ID_LIST、*_CREATOR_ID_LIST。8.2 数据库配置config/db_config.py 中所有连接参数均支持环境变量覆盖os.getenv提供默认值# MySQL MYSQL_DB_USER os.getenv(MYSQL_DB_USER, root) MYSQL_DB_PWD os.getenv(MYSQL_DB_PWD, 123456) MYSQL_DB_HOST os.getenv(MYSQL_DB_HOST, localhost) MYSQL_DB_PORT os.getenv(MYSQL_DB_PORT, 3306) MYSQL_DB_NAME os.getenv(MYSQL_DB_NAME, media_crawler) # Redis REDIS_DB_HOST os.getenv(REDIS_DB_HOST, 127.0.0.1) REDIS_DB_PWD os.getenv(REDIS_DB_PWD, 123456) REDIS_DB_PORT os.getenv(REDIS_DB_PORT, 6379) REDIS_DB_NUM os.getenv(REDIS_DB_NUM, 0) CACHE_TYPE_REDIS redis CACHE_TYPE_MEMORY memory # SQLite路径固定为仓库内 database/sqlite_tables.db SQLITE_DB_PATH os.path.join(os.path.dirname(os.path.dirname(__file__)), database, sqlite_tables.db) # MongoDB MONGODB_HOST os.getenv(MONGODB_HOST, localhost) MONGODB_PORT os.getenv(MONGODB_PORT, 27017) MONGODB_USER os.getenv(MONGODB_USER, ) MONGODB_PWD os.getenv(MONGODB_PWD, ) MONGODB_DB_NAME os.getenv(MONGODB_DB_NAME, media_crawler) # PostgreSQL POSTGRES_DB_USER os.getenv(POSTGRES_DB_USER, postgres) POSTGRES_DB_PWD os.getenv(POSTGRES_DB_PWD, 123456) POSTGRES_DB_HOST os.getenv(POSTGRES_DB_HOST, localhost) POSTGRES_DB_PORT os.getenv(POSTGRES_DB_PORT, 5432) POSTGRES_DB_NAME os.getenv(POSTGRES_DB_NAME, media_crawler)9. 工具模块9.1 工具函数概览模块文件主要功能应用运行器app_runner.py信号处理、优雅退出、清理管理浏览器启动browser_launcher.py检测浏览器路径、启动浏览器进程CDP管理cdp_browser.pyCDP连接、浏览器上下文管理爬虫工具crawler_util.py二维码识别、验证码处理、User-Agent文件写入async_file_writer.py异步CSV/JSON写入、词云生成滑块验证slider_util.py滑动验证码破解时间工具time_util.py时间戳转换、日期处理9.2 应用运行管理对应 tools/app_runner.py 的run()入口main.py 以cleanup_timeout_seconds15.0注册清理超时并在首次中断时通过on_first_interrupt_force_stop强制回收 CDP 浏览器进程避免浏览器进程残留。10. 模块依赖关系从导入关系看cmd_arg/arg.py在解析参数时直接覆写config模块的全局变量cmd_arg/arg.py因此命令行参数 配置文件的优先级通过先加载 config、再用 CLI 值覆写这一机制实现这也是所有模块共享同一份import config的副作用式配置方案的体现。11. 扩展指南11.1 添加新平台在media_platform/下创建新目录实现以下核心文件core.py- 继承AbstractCrawlerclient.py- 继承AbstractApiClient和ProxyRefreshMixinlogin.py- 继承AbstractLoginfield.py- 定义平台枚举在store/下创建对应存储目录在 main.py 的CrawlerFactory.CRAWLERS中注册同时还需要在config/下新增{platform}_config.py并挂入base_config.py的 import 列表、在 cmd_arg/arg.py 的PlatformEnum中登记代号、在database/models.py中补充 ORM 表。11.2 添加新存储方式在store/下创建新的存储实现类继承AbstractStore基类实现store_content、store_comment、store_creator方法在各平台的StoreFactory.STORES中注册若要成为命令行合法选项还需同步扩充 cmd_arg/arg.py 的SaveDataOptionEnum。11.3 添加新代理提供商在proxy/providers/下创建新的代理类继承BaseProxy基类接口为 proxy/base_proxy.py 中的ProxyProvider实现get_proxy(num)方法在 proxy/proxy_ip_pool.py 的IpProxyProvider注册表中登记并在ProviderNameEnum中加入对应名称。12. 快速参考12.1 常用命令# 启动爬虫默认读取 config/base_config.py python main.py # 指定平台 python main.py --platform xhs # 指定登录方式 python main.py --lt qrcode # 指定爬虫类型 python main.py --type search # 指定关键词与数量 python main.py --platform dy --keywords AI,大模型 --crawler_max_notes_count 30 # 指定存储方式csv | db | json | jsonl | sqlite | mongodb | excel | postgres python main.py --save_data_option sqlite # 初始化数据库表结构sqlite | mysql | postgres python main.py --init_db sqlite完整参数还包括--start起始页、--get_comment/--get_sub_comment布尔开关支持 yes/true/t/y/1、--headless、--cookies、--specified_id、--creator_id、--max_comments_count_singlenotes、--max_concurrency_num、--save_data_path、--enable_ip_proxy、--ip_proxy_pool_count、--ip_proxy_provider_name、--static_proxy_url等cmd_arg/arg.py。所有参数的默认值均取自config模块配置非法时会回退到安全默认值并给出警告_coerce_enumcmd_arg/arg.py。12.2 关键文件路径用途文件路径程序入口main.py核心配置config/base_config.py数据库配置config/db_config.py爬虫基类base/base_crawler.py命令行解析cmd_arg/arg.pyORM模型database/models.py数据库会话database/db_session.pyMongoDB 基类database/mongodb_store_base.py代理池proxy/proxy_ip_pool.py代理刷新 Mixinproxy/proxy_mixin.py缓存工厂cache/cache_factory.pyCDP浏览器tools/cdp_browser.py平台示例存储实现store/douyin/_store_impl.py12.3 架构要点回顾分层 工厂入口层经CrawlerFactory与StoreFactory两个工厂解耦平台/存储选择config全局变量是各层的共享契约基类约定AbstractCrawler/AbstractApiClient/AbstractLogin/AbstractStore四套抽象类定义了平台实现的完整契约ProxyRefreshMixin以 Mixin 方式横切所有客户端反爬三件套CDP 真实浏览器模式、代理 IP 池含过期刷新与静态代理、签名脚本libs/与各平台xhs_sign.py等可插拔存储71 种存储方式统一收敛到AbstractStore三方法接口数据库类存储自带基于唯一键的 upsert 去重。掌握以上结构后无论是排查某平台为什么没有 CDP 实现回退逻辑在基类中还是回答换 MySQL 后重复数据如何避免upsert 在_store_impl.py中都可以在仓库中找到明确的代码依据。【免费下载链接】MediaCrawler小红书笔记 | 评论爬虫、抖音视频 | 评论爬虫、快手视频 | 评论爬虫、B 站视频 评论爬虫、微博帖子 评论爬虫、百度贴吧帖子 百度贴吧评论回复爬虫 | 知乎问答文章评论爬虫项目地址: https://gitcode.com/GitHub_Trending/me/MediaCrawler创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进