first commit
This commit is contained in:
parent
9c7e1d499b
commit
f74ad7926e
255
README.md
255
README.md
@ -1,170 +1,141 @@
|
|||||||
# 🔥 自媒体平台爬虫🕷️MediaCrawler🔥
|
# 小红书内容智能分析系统
|
||||||
<a href="https://trendshift.io/repositories/8291" target="_blank"><img src="https://trendshift.io/api/badge/repositories/8291" alt="NanmiCoder%2FMediaCrawler | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
|
||||||
|
|
||||||
[![GitHub Stars](https://img.shields.io/github/stars/NanmiCoder/MediaCrawler?style=social)](https://github.com/NanmiCoder/MediaCrawler/stargazers)
|
## 项目概述
|
||||||
[![GitHub Forks](https://img.shields.io/github/forks/NanmiCoder/MediaCrawler?style=social)](https://github.com/NanmiCoder/MediaCrawler/network/members)
|
本项目旨在构建一个自动化的小红书内容采集和智能分析系统。通过爬虫采集、多模态内容处理和AI分析,将小红书的图文视频内容转化为结构化的知识输出。
|
||||||
[![GitHub Issues](https://img.shields.io/github/issues/NanmiCoder/MediaCrawler)](https://github.com/NanmiCoder/MediaCrawler/issues)
|
|
||||||
[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/NanmiCoder/MediaCrawler)](https://github.com/NanmiCoder/MediaCrawler/pulls)
|
|
||||||
[![License](https://img.shields.io/github/license/NanmiCoder/MediaCrawler)](https://github.com/NanmiCoder/MediaCrawler/blob/main/LICENSE)
|
|
||||||
|
|
||||||
> **免责声明:**
|
## 系统架构
|
||||||
>
|
|
||||||
> 大家请以学习为目的使用本仓库⚠️⚠️⚠️⚠️,[爬虫违法违规的案件](https://github.com/HiddenStrawberry/Crawler_Illegal_Cases_In_China) <br>
|
|
||||||
>
|
|
||||||
>本仓库的所有内容仅供学习和参考之用,禁止用于商业用途。任何人或组织不得将本仓库的内容用于非法用途或侵犯他人合法权益。本仓库所涉及的爬虫技术仅用于学习和研究,不得用于对其他平台进行大规模爬虫或其他非法行为。对于因使用本仓库内容而引起的任何法律责任,本仓库不承担任何责任。使用本仓库的内容即表示您同意本免责声明的所有条款和条件。
|
|
||||||
>
|
|
||||||
> 点击查看更为详细的免责声明。[点击跳转](#disclaimer)
|
|
||||||
|
|
||||||
# 仓库描述
|
### 1. 数据采集层
|
||||||
|
#### 1.1 内容爬取
|
||||||
|
- 使用 MediaCrawler 爬虫框架
|
||||||
|
- 根据指定关键词抓取小红书笔记
|
||||||
|
- 将原始数据保存为 JSON 格式
|
||||||
|
- 包含笔记文本、图片URL、视频URL等信息
|
||||||
|
|
||||||
**小红书爬虫**,**抖音爬虫**, **快手爬虫**, **B站爬虫**, **微博爬虫**,**百度贴吧爬虫**,**知乎爬虫**...。
|
#### 1.2 数据存储
|
||||||
目前能抓取小红书、抖音、快手、B站、微博、贴吧、知乎等平台的公开信息。
|
- 将 JSON 数据导入 MySQL 数据库
|
||||||
|
- 建立规范的数据表结构
|
||||||
|
- 实现数据的持久化存储和管理
|
||||||
|
|
||||||
原理:利用[playwright](https://playwright.dev/)搭桥,保留登录成功后的上下文浏览器环境,通过执行JS表达式获取一些加密参数
|
#### 1.3 媒体文件下载
|
||||||
通过使用此方式,免去了复现核心加密JS代码,逆向难度大大降低
|
- 从数据库读取媒体文件URL
|
||||||
|
- 下载笔记关联的图片和视频
|
||||||
|
- 按笔记ID分类存储在本地文件系统
|
||||||
|
|
||||||
# 功能列表
|
### 2. 内容处理层
|
||||||
| 平台 | 关键词搜索 | 指定帖子ID爬取 | 二级评论 | 指定创作者主页 | 登录态缓存 | IP代理池 | 生成评论词云图 |
|
#### 2.1 视频处理
|
||||||
| ------ | ---------- | -------------- | -------- | -------------- | ---------- | -------- | -------------- |
|
- 使用 Faster-Whisper 模型
|
||||||
| 小红书 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
- 将视频音频转换为文字
|
||||||
| 抖音 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
- 支持中文语音识别
|
||||||
| 快手 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
- 保存字幕文本
|
||||||
| B 站 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| 微博 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| 贴吧 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
| 知乎 | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
||||||
|
|
||||||
### MediaCrawlerPro重磅发布啦!!!
|
#### 2.2 图像处理
|
||||||
> 主打学习成熟项目的架构设计,不仅仅是爬虫,Pro中的其他代码设计思路也是值得学习,欢迎大家关注!!!
|
- 使用 ChatGPT-4-Vision 模型
|
||||||
|
- 分析图片内容
|
||||||
|
- 提取图片中的关键信息
|
||||||
|
- 生成图片描述文本
|
||||||
|
|
||||||
[MediaCrawlerPro](https://github.com/MediaCrawlerPro) 版本已经重构出来了,相较于开源版本的优势:
|
### 3. 智能分析层
|
||||||
- 多账号+IP代理支持(重点!)
|
#### 3.1 内容理解
|
||||||
- 去除Playwright依赖,使用更加简单
|
- 使用 ChatGPT 处理文本内容
|
||||||
- 支持linux部署(Docker docker-compose)
|
- 整合视频字幕和图片描述
|
||||||
- 代码重构优化,更加易读易维护(解耦JS签名逻辑)
|
- 生成内容摘要
|
||||||
- 代码质量更高,对于构建更大型的爬虫项目更加友好
|
- 提取关键信息点
|
||||||
- 完美的架构设计,更加易扩展,源码学习的价值更大
|
|
||||||
|
#### 3.2 知识图谱
|
||||||
|
- 基于内容分析生成思维导图
|
||||||
|
- 展示主题间的逻辑关系
|
||||||
|
- 可视化知识结构
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
- 爬虫框架:MediaCrawler
|
||||||
|
- 数据库:MySQL
|
||||||
|
- 音频处理:Faster-Whisper
|
||||||
|
- 图像识别:ChatGPT-4-Vision
|
||||||
|
- 自然语言处理:ChatGPT
|
||||||
|
- 编程语言:Python
|
||||||
|
|
||||||
|
## 工作流程图
|
||||||
|
![工作流程图](docs/static/images/fig1.png)
|
||||||
|
|
||||||
|
|
||||||
# 安装部署方法
|
## 预期成果
|
||||||
> 开源不易,希望大家可以Star一下MediaCrawler仓库!!!!十分感谢!!! <br>
|
1. 自动化的内容采集系统
|
||||||
|
2. 结构化的多模态数据存储
|
||||||
|
3. 智能化的内容理解和分析
|
||||||
|
4. 可视化的知识展示
|
||||||
|
|
||||||
## 创建并激活 python 虚拟环境
|
## 应用场景
|
||||||
> 如果是爬取抖音和知乎,需要提前安装nodejs环境,版本大于等于:`16`即可 <br>
|
- 内容创作参考
|
||||||
```shell
|
- 市场趋势分析
|
||||||
# 进入项目根目录
|
- 用户行为研究
|
||||||
cd MediaCrawler
|
- 知识管理系统
|
||||||
|
|
||||||
# 创建虚拟环境
|
## 后续优化方向
|
||||||
# 我的python版本是:3.9.6,requirements.txt中的库是基于这个版本的,如果是其他python版本,可能requirements.txt中的库不兼容,自行解决一下。
|
1. 提高爬虫效率和稳定性
|
||||||
python -m venv venv
|
2. 优化媒体文件存储结构
|
||||||
|
3. 提升AI模型处理精度
|
||||||
|
4. 增强可视化展示效果
|
||||||
|
5. 添加用户交互界面
|
||||||
|
|
||||||
# macos & linux 激活虚拟环境
|
## 风险分析
|
||||||
source venv/bin/activate
|
|
||||||
|
|
||||||
# windows 激活虚拟环境
|
### 1. 法律合规风险
|
||||||
venv\Scripts\activate
|
|
||||||
|
|
||||||
```
|
#### 1.1 违反网络安全法风险
|
||||||
|
- 根据《中华人民共和国网络安全法》第四十四条规定,任何个人和组织不得窃取或者以其他非法方式获取个人信息
|
||||||
|
- 在爬取过程中必须避免收集用户个人隐私信息
|
||||||
|
- 确保数据采集和使用符合相关法律法规
|
||||||
|
|
||||||
## 安装依赖库
|
#### 1.2 侵犯知识产权风险
|
||||||
|
- 需注意平台内容的版权问题
|
||||||
|
- 避免大规模复制和传播他人原创内容
|
||||||
|
- 不得将爬取的内容用于商业牟利
|
||||||
|
|
||||||
```shell
|
#### 1.3 违反平台服务条款风险
|
||||||
pip install -r requirements.txt
|
- 违反平台规则可能面临账号封禁
|
||||||
```
|
- 过度爬取可能导致IP封锁
|
||||||
|
- 严重违规可能引发平台法律诉讼
|
||||||
|
|
||||||
## 安装 playwright浏览器驱动
|
### 2. 技术风险
|
||||||
|
|
||||||
```shell
|
#### 2.1 反爬虫机制
|
||||||
playwright install
|
- 平台可能部署各种反爬虫措施
|
||||||
```
|
- IP被封禁影响采集效率
|
||||||
|
- 需要不断更新技术方案应对
|
||||||
|
|
||||||
## 运行爬虫程序
|
#### 2.2 数据质量风险
|
||||||
|
- 采集数据可能不完整或有误
|
||||||
|
- 多媒体内容下载失败
|
||||||
|
- 数据格式变化导致解析错误
|
||||||
|
|
||||||
```shell
|
### 3. 使用建议
|
||||||
### 项目默认是没有开启评论爬取模式,如需评论请在config/base_config.py中的 ENABLE_GET_COMMENTS 变量修改
|
|
||||||
### 一些其他支持项,也可以在config/base_config.py查看功能,写的有中文注释
|
|
||||||
|
|
||||||
# 从配置文件中读取关键词搜索相关的帖子并爬取帖子信息与评论
|
#### 3.1 合规使用
|
||||||
python main.py --platform xhs --lt qrcode --type search
|
- 仅采集公开可见的内容
|
||||||
|
- 避免采集用户个人信息
|
||||||
|
- 采集频率保持合理范围
|
||||||
|
- 遵守平台的robots.txt规则
|
||||||
|
|
||||||
# 从配置文件中读取指定的帖子ID列表获取指定帖子的信息与评论信息
|
#### 3.2 技术防范
|
||||||
python main.py --platform xhs --lt qrcode --type detail
|
- 使用代理IP分散请求
|
||||||
|
- 控制请求频率和并发数
|
||||||
|
- 做好异常处理和日志记录
|
||||||
|
- 定期备份重要数据
|
||||||
|
|
||||||
# 打开对应APP扫二维码登录
|
### 4. 案例警示
|
||||||
|
|
||||||
# 其他平台爬虫使用示例,执行下面的命令查看
|
根据[GitHub上的中国爬虫违法违规案例汇总](https://github.com/HiddenStrawberry/Crawler_Illegal_Cases_In_China),以下行为可能带来严重法律后果:
|
||||||
python main.py --help
|
|
||||||
```
|
|
||||||
|
|
||||||
## 数据保存
|
- 爬取和贩卖个人隐私数据
|
||||||
- 支持关系型数据库Mysql中保存(需要提前创建数据库)
|
- 破解验证码并提供服务
|
||||||
- 执行 `python db.py` 初始化数据库数据库表结构(只在首次执行)
|
- 未经授权爬取并复制商业数据
|
||||||
- 支持保存到csv中(data/目录下)
|
- 大规模爬取导致目标网站服务中断
|
||||||
- 支持保存到json中(data/目录下)
|
|
||||||
|
|
||||||
|
### 5. 合规建议
|
||||||
|
|
||||||
|
1. 项目启动前进行法律可行性评估
|
||||||
# 其他常见问题可以查看在线文档
|
2. 建立数据安全管理制度
|
||||||
>
|
3. 保留完整的操作日志记录
|
||||||
> 在线文档包含使用方法、常见问题、加入项目交流群等。
|
4. 定期进行合规性自查
|
||||||
> [MediaCrawler在线文档](https://nanmicoder.github.io/MediaCrawler/)
|
5. 如有必要可咨询法律专家
|
||||||
>
|
|
||||||
|
|
||||||
# 知识付费服务
|
|
||||||
[作者的知识付费栏目介绍](https://nanmicoder.github.io/MediaCrawler/%E7%9F%A5%E8%AF%86%E4%BB%98%E8%B4%B9%E4%BB%8B%E7%BB%8D.html)
|
|
||||||
|
|
||||||
# 项目微信交流群
|
|
||||||
|
|
||||||
[加入微信交流群](https://nanmicoder.github.io/MediaCrawler/%E5%BE%AE%E4%BF%A1%E4%BA%A4%E6%B5%81%E7%BE%A4.html)
|
|
||||||
|
|
||||||
# 感谢下列Sponsors对本仓库赞助支持
|
|
||||||
- <a href="https://sider.ai/ad-land-redirect?source=github&p1=mi&p2=kk">【Sider】全网最火的ChatGPT插件,我也免费薅羊毛用了快一年了,体验拉满。</a>
|
|
||||||
|
|
||||||
成为赞助者,可以将您产品展示在这里,每天获得大量曝光,联系作者微信:yzglan 或 email:relakkes@gmail.com
|
|
||||||
|
|
||||||
|
|
||||||
# 爬虫入门课程
|
|
||||||
我新开的爬虫教程Github仓库 [CrawlerTutorial](https://github.com/NanmiCoder/CrawlerTutorial) ,感兴趣的朋友可以关注一下,持续更新,主打一个免费.
|
|
||||||
|
|
||||||
# star 趋势图
|
|
||||||
- 如果该项目对你有帮助,帮忙 star一下 ❤️❤️❤️,让更多的人看到MediaCrawler这个项目
|
|
||||||
|
|
||||||
[![Star History Chart](https://api.star-history.com/svg?repos=NanmiCoder/MediaCrawler&type=Date)](https://star-history.com/#NanmiCoder/MediaCrawler&Date)
|
|
||||||
|
|
||||||
|
|
||||||
# 参考
|
|
||||||
|
|
||||||
- xhs客户端 [ReaJason的xhs仓库](https://github.com/ReaJason/xhs)
|
|
||||||
- 短信转发 [参考仓库](https://github.com/pppscn/SmsForwarder)
|
|
||||||
- 内网穿透工具 [ngrok](https://ngrok.com/docs/)
|
|
||||||
|
|
||||||
|
|
||||||
# 免责声明
|
|
||||||
<div id="disclaimer">
|
|
||||||
|
|
||||||
## 1. 项目目的与性质
|
|
||||||
本项目(以下简称“本项目”)是作为一个技术研究与学习工具而创建的,旨在探索和学习网络数据采集技术。本项目专注于自媒体平台的数据爬取技术研究,旨在提供给学习者和研究者作为技术交流之用。
|
|
||||||
|
|
||||||
## 2. 法律合规性声明
|
|
||||||
本项目开发者(以下简称“开发者”)郑重提醒用户在下载、安装和使用本项目时,严格遵守中华人民共和国相关法律法规,包括但不限于《中华人民共和国网络安全法》、《中华人民共和国反间谍法》等所有适用的国家法律和政策。用户应自行承担一切因使用本项目而可能引起的法律责任。
|
|
||||||
|
|
||||||
## 3. 使用目的限制
|
|
||||||
本项目严禁用于任何非法目的或非学习、非研究的商业行为。本项目不得用于任何形式的非法侵入他人计算机系统,不得用于任何侵犯他人知识产权或其他合法权益的行为。用户应保证其使用本项目的目的纯属个人学习和技术研究,不得用于任何形式的非法活动。
|
|
||||||
|
|
||||||
## 4. 免责声明
|
|
||||||
开发者已尽最大努力确保本项目的正当性及安全性,但不对用户使用本项目可能引起的任何形式的直接或间接损失承担责任。包括但不限于由于使用本项目而导致的任何数据丢失、设备损坏、法律诉讼等。
|
|
||||||
|
|
||||||
## 5. 知识产权声明
|
|
||||||
本项目的知识产权归开发者所有。本项目受到著作权法和国际著作权条约以及其他知识产权法律和条约的保护。用户在遵守本声明及相关法律法规的前提下,可以下载和使用本项目。
|
|
||||||
|
|
||||||
## 6. 最终解释权
|
|
||||||
关于本项目的最终解释权归开发者所有。开发者保留随时更改或更新本免责声明的权利,恕不另行通知。
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## 感谢JetBrains提供的免费开源许可证支持
|
|
||||||
<a href="https://www.jetbrains.com/?from=MediaCrawler">
|
|
||||||
<img src="https://www.jetbrains.com/company/brand/img/jetbrains_logo.png" width="100" alt="JetBrains" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
|
155
README_v1.md
Normal file
155
README_v1.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# 🔥 自媒体平台爬虫🕷️MediaCrawler🔥
|
||||||
|
z
|
||||||
|
# 仓库描述
|
||||||
|
|
||||||
|
**小红书爬虫**,**抖音爬虫**, **快手爬虫**, **B站爬虫**, **微博爬虫**,**百度贴吧爬虫**,**知乎爬虫**...。
|
||||||
|
目前能抓取小红书、抖音、快手、B站、微博、贴吧、知乎等平台的公开信息。
|
||||||
|
|
||||||
|
原理:利用[playwright](https://playwright.dev/)搭桥,保留登录成功后的上下文浏览器环境,通过执行JS表达式获取一些加密参数
|
||||||
|
通过使用此方式,免去了复现核心加密JS代码,逆向难度大大降低
|
||||||
|
|
||||||
|
# 功能列表
|
||||||
|
| 平台 | 关键词搜索 | 指定帖子ID爬取 | 二级评论 | 指定创作者主页 | 登录态缓存 | IP代理池 | 生成评论词云图 |
|
||||||
|
| ------ | ---------- | -------------- | -------- | -------------- | ---------- | -------- | -------------- |
|
||||||
|
| 小红书 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| 抖音 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| 快手 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| B 站 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| 微博 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| 贴吧 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| 知乎 | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
|
### MediaCrawlerPro重磅发布啦!!!
|
||||||
|
> 主打学习成熟项目的架构设计,不仅仅是爬虫,Pro中的其他代码设计思路也是值得学习,欢迎大家关注!!!
|
||||||
|
|
||||||
|
[MediaCrawlerPro](https://github.com/MediaCrawlerPro) 版本已经重构出来了,相较于开源版本的优势:
|
||||||
|
- 多账号+IP代理支持(重点!)
|
||||||
|
- 去除Playwright依赖,使用更加简单
|
||||||
|
- 支持linux部署(Docker docker-compose)
|
||||||
|
- 代码重构优化,更加易读易维护(解耦JS签名逻辑)
|
||||||
|
- 代码质量更高,对于构建更大型的爬虫项目更加友好
|
||||||
|
- 完美的架构设计,更加易扩展,源码学习的价值更大
|
||||||
|
|
||||||
|
|
||||||
|
# 安装部署方法
|
||||||
|
> 开源不易,希望大家可以Star一下MediaCrawler仓库!!!!十分感谢!!! <br>
|
||||||
|
|
||||||
|
## 创建并激活 python 虚拟环境
|
||||||
|
> 如果是爬取抖音和知乎,需要提前安装nodejs环境,版本大于等于:`16`即可 <br>
|
||||||
|
```shell
|
||||||
|
# 进入项目根目录
|
||||||
|
cd MediaCrawler
|
||||||
|
|
||||||
|
# 创建虚拟环境
|
||||||
|
# 我的python版本是:3.9.6,requirements.txt中的库是基于这个版本的,如果是其他python版本,可能requirements.txt中的库不兼容,自行解决一下。
|
||||||
|
python -m venv venv
|
||||||
|
|
||||||
|
# macos & linux 激活虚拟环境
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# windows 激活虚拟环境
|
||||||
|
venv\Scripts\activate
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安装依赖库
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安装 playwright浏览器驱动
|
||||||
|
|
||||||
|
```shell
|
||||||
|
playwright install
|
||||||
|
```
|
||||||
|
|
||||||
|
## 运行爬虫程序
|
||||||
|
|
||||||
|
```shell
|
||||||
|
### 项目默认是没有开启评论爬取模式,如需评论请在config/base_config.py中的 ENABLE_GET_COMMENTS 变量修改
|
||||||
|
### 一些其他支持项,也可以在config/base_config.py查看功能,写的有中文注释
|
||||||
|
|
||||||
|
# 从配置文件中读取关键词搜索相关的帖子并爬取帖子信息与评论
|
||||||
|
python main.py --platform xhs --lt qrcode --type search
|
||||||
|
|
||||||
|
# 从配置文件中读取指定的帖子ID列表获取指定帖子的信息与评论信息
|
||||||
|
python main.py --platform xhs --lt qrcode --type detail
|
||||||
|
|
||||||
|
# 打开对应APP扫二维码登录
|
||||||
|
|
||||||
|
# 其他平台爬虫使用示例,执行下面的命令查看
|
||||||
|
python main.py --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据保存
|
||||||
|
- 支持关系型数据库Mysql中保存(需要提前创建数据库)
|
||||||
|
- 执行 `python db.py` 初始化数据库数据库表结构(只在首次执行)
|
||||||
|
- 支持保存到csv中(data/目录下)
|
||||||
|
- 支持保存到json中(data/目录下)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 其他常见问题可以查看在线文档
|
||||||
|
>
|
||||||
|
> 在线文档包含使用方法、常见问题、加入项目交流群等。
|
||||||
|
> [MediaCrawler在线文档](https://nanmicoder.github.io/MediaCrawler/)
|
||||||
|
>
|
||||||
|
|
||||||
|
# 知识付费服务
|
||||||
|
[作者的知识付费栏目介绍](https://nanmicoder.github.io/MediaCrawler/%E7%9F%A5%E8%AF%86%E4%BB%98%E8%B4%B9%E4%BB%8B%E7%BB%8D.html)
|
||||||
|
|
||||||
|
# 项目微信交流群
|
||||||
|
|
||||||
|
[加入微信交流群](https://nanmicoder.github.io/MediaCrawler/%E5%BE%AE%E4%BF%A1%E4%BA%A4%E6%B5%81%E7%BE%A4.html)
|
||||||
|
|
||||||
|
# 感谢下列Sponsors对本仓库赞助支持
|
||||||
|
- <a href="https://sider.ai/ad-land-redirect?source=github&p1=mi&p2=kk">【Sider】全网最火的ChatGPT插件,我也免费薅羊毛用了快一年了,体验拉满。</a>
|
||||||
|
|
||||||
|
成为赞助者,可以将您产品展示在这里,每天获得大量曝光,联系作者微信:yzglan 或 email:relakkes@gmail.com
|
||||||
|
|
||||||
|
|
||||||
|
# 爬虫入门课程
|
||||||
|
我新开的爬虫教程Github仓库 [CrawlerTutorial](https://github.com/NanmiCoder/CrawlerTutorial) ,感兴趣的朋友可以关注一下,持续更新,主打一个免费.
|
||||||
|
|
||||||
|
# star 趋势图
|
||||||
|
- 如果该项目对你有帮助,帮忙 star一下 ❤️❤️❤️,让更多的人看到MediaCrawler这个项目
|
||||||
|
|
||||||
|
[![Star History Chart](https://api.star-history.com/svg?repos=NanmiCoder/MediaCrawler&type=Date)](https://star-history.com/#NanmiCoder/MediaCrawler&Date)
|
||||||
|
|
||||||
|
|
||||||
|
# 参考
|
||||||
|
|
||||||
|
- xhs客户端 [ReaJason的xhs仓库](https://github.com/ReaJason/xhs)
|
||||||
|
- 短信转发 [参考仓库](https://github.com/pppscn/SmsForwarder)
|
||||||
|
- 内网穿透工具 [ngrok](https://ngrok.com/docs/)
|
||||||
|
|
||||||
|
|
||||||
|
# 免责声明
|
||||||
|
<div id="disclaimer">
|
||||||
|
|
||||||
|
## 1. 项目目的与性质
|
||||||
|
本项目(以下简称“本项目”)是作为一个技术研究与学习工具而创建的,旨在探索和学习网络数据采集技术。本项目专注于自媒体平台的数据爬取技术研究,旨在提供给学习者和研究者作为技术交流之用。
|
||||||
|
|
||||||
|
## 2. 法律合规性声明
|
||||||
|
本项目开发者(以下简称“开发者”)郑重提醒用户在下载、安装和使用本项目时,严格遵守中华人民共和国相关法律法规,包括但不限于《中华人民共和国网络安全法》、《中华人民共和国反间谍法》等所有适用的国家法律和政策。用户应自行承担一切因使用本项目而可能引起的法律责任。
|
||||||
|
|
||||||
|
## 3. 使用目的限制
|
||||||
|
本项目严禁用于任何非法目的或非学习、非研究的商业行为。本项目不得用于任何形式的非法侵入他人计算机系统,不得用于任何侵犯他人知识产权或其他合法权益的行为。用户应保证其使用本项目的目的纯属个人学习和技术研究,不得用于任何形式的非法活动。
|
||||||
|
|
||||||
|
## 4. 免责声明
|
||||||
|
开发者已尽最大努力确保本项目的正当性及安全性,但不对用户使用本项目可能引起的任何形式的直接或间接损失承担责任。包括但不限于由于使用本项目而导致的任何数据丢失、设备损坏、法律诉讼等。
|
||||||
|
|
||||||
|
## 5. 知识产权声明
|
||||||
|
本项目的知识产权归开发者所有。本项目受到著作权法和国际著作权条约以及其他知识产权法律和条约的保护。用户在遵守本声明及相关法律法规的前提下,可以下载和使用本项目。
|
||||||
|
|
||||||
|
## 6. 最终解释权
|
||||||
|
关于本项目的最终解释权归开发者所有。开发者保留随时更改或更新本免责声明的权利,恕不另行通知。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## 感谢JetBrains提供的免费开源许可证支持
|
||||||
|
<a href="https://www.jetbrains.com/?from=MediaCrawler">
|
||||||
|
<img src="https://www.jetbrains.com/company/brand/img/jetbrains_logo.png" width="100" alt="JetBrains" />
|
||||||
|
</a>
|
||||||
|
|
52
build.py
Normal file
52
build.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import PyInstaller.__main__
|
||||||
|
|
||||||
|
def clean_build_dirs():
|
||||||
|
"""清理构建目录"""
|
||||||
|
dirs_to_clean = ['build', 'dist']
|
||||||
|
for dir_name in dirs_to_clean:
|
||||||
|
if os.path.exists(dir_name):
|
||||||
|
shutil.rmtree(dir_name)
|
||||||
|
|
||||||
|
def create_required_dirs():
|
||||||
|
"""创建必要的目录"""
|
||||||
|
os.makedirs('dist/data/xhs/json/media', exist_ok=True)
|
||||||
|
|
||||||
|
def copy_required_files():
|
||||||
|
"""复制必要的文件"""
|
||||||
|
# 复制配置文件
|
||||||
|
if os.path.exists('config'):
|
||||||
|
shutil.copytree('config', 'dist/config', dirs_exist_ok=True)
|
||||||
|
|
||||||
|
# 复制其他必要文件
|
||||||
|
files_to_copy = [
|
||||||
|
'main.py',
|
||||||
|
# 添加其他需要复制的文件
|
||||||
|
]
|
||||||
|
|
||||||
|
for file in files_to_copy:
|
||||||
|
if os.path.exists(file):
|
||||||
|
shutil.copy2(file, 'dist/')
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# 清理旧的构建文件
|
||||||
|
clean_build_dirs()
|
||||||
|
|
||||||
|
# 运行PyInstaller
|
||||||
|
PyInstaller.__main__.run([
|
||||||
|
'build_exe.spec',
|
||||||
|
'--clean',
|
||||||
|
'--noconfirm'
|
||||||
|
])
|
||||||
|
|
||||||
|
# 创建必要的目录
|
||||||
|
create_required_dirs()
|
||||||
|
|
||||||
|
# 复制必要的文件
|
||||||
|
copy_required_files()
|
||||||
|
|
||||||
|
print("打包完成!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
159
check_downloads.py
Normal file
159
check_downloads.py
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import os
|
||||||
|
import mysql.connector
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
db_config = {
|
||||||
|
'user': 'root',
|
||||||
|
'password': 'zaq12wsx@9Xin',
|
||||||
|
'host': '183.11.229.79',
|
||||||
|
'port': 3316,
|
||||||
|
'database': '9xin',
|
||||||
|
'auth_plugin': 'mysql_native_password'
|
||||||
|
}
|
||||||
|
|
||||||
|
def download_file(url, save_path):
|
||||||
|
"""下载文件"""
|
||||||
|
try:
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers, stream=True, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
||||||
|
|
||||||
|
with open(save_path, 'wb') as f:
|
||||||
|
for chunk in response.iter_content(chunk_size=8192):
|
||||||
|
if chunk:
|
||||||
|
f.write(chunk)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f'下载文件失败 {url}: {str(e)}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def retry_download(note_id, image_list, video_url):
|
||||||
|
"""重试下载失败的媒体文件"""
|
||||||
|
media_dir = f'./data/xhs/json/media/{note_id}'
|
||||||
|
download_success = True
|
||||||
|
|
||||||
|
# 重试下载图片
|
||||||
|
if image_list:
|
||||||
|
image_urls = image_list.split(',')
|
||||||
|
for i, url in enumerate(image_urls):
|
||||||
|
url = url.strip()
|
||||||
|
if not url:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ext = os.path.splitext(urlparse(url).path)[1] or '.jpg'
|
||||||
|
image_path = os.path.join(media_dir, f'image_{i+1}{ext}')
|
||||||
|
|
||||||
|
if not os.path.exists(image_path) or os.path.getsize(image_path) == 0:
|
||||||
|
print(f'重试下载图片 {note_id} - {i+1}')
|
||||||
|
if not download_file(url, image_path):
|
||||||
|
download_success = False
|
||||||
|
time.sleep(0.5) # 添加延时避免请求过快
|
||||||
|
|
||||||
|
# 重试下载视频
|
||||||
|
if video_url and video_url.strip():
|
||||||
|
video_url = video_url.strip()
|
||||||
|
ext = os.path.splitext(urlparse(video_url).path)[1] or '.mp4'
|
||||||
|
video_path = os.path.join(media_dir, f'video{ext}')
|
||||||
|
|
||||||
|
if not os.path.exists(video_path) or os.path.getsize(video_path) == 0:
|
||||||
|
print(f'重试下载视频 {note_id}')
|
||||||
|
if not download_file(video_url, video_path):
|
||||||
|
download_success = False
|
||||||
|
|
||||||
|
return download_success
|
||||||
|
|
||||||
|
def check_media_files():
|
||||||
|
"""检查媒体文件下载状态并更新数据库,对失败的记录进行重试下载"""
|
||||||
|
try:
|
||||||
|
conn = mysql.connector.connect(**db_config)
|
||||||
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|
||||||
|
# 确保download_flag字段存在
|
||||||
|
try:
|
||||||
|
cursor.execute("""
|
||||||
|
ALTER TABLE xhs_notes
|
||||||
|
ADD COLUMN IF NOT EXISTS download_flag BOOLEAN DEFAULT FALSE
|
||||||
|
""")
|
||||||
|
conn.commit()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"添加download_flag字段时出错: {e}")
|
||||||
|
|
||||||
|
# 获取所有记录
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT note_id, image_list, video_url, download_flag
|
||||||
|
FROM xhs_notes
|
||||||
|
""")
|
||||||
|
records = cursor.fetchall()
|
||||||
|
|
||||||
|
update_query = """
|
||||||
|
UPDATE xhs_notes
|
||||||
|
SET download_flag = %s
|
||||||
|
WHERE note_id = %s
|
||||||
|
"""
|
||||||
|
|
||||||
|
total = len(records)
|
||||||
|
completed = 0
|
||||||
|
|
||||||
|
print(f"开始检查 {total} 条记录的下载状态...")
|
||||||
|
|
||||||
|
for record in records:
|
||||||
|
note_id = record['note_id']
|
||||||
|
is_complete = True
|
||||||
|
media_dir = f'./data/xhs/json/media/{note_id}'
|
||||||
|
|
||||||
|
# 检查图片和视频是否完整
|
||||||
|
if record['image_list']:
|
||||||
|
image_urls = record['image_list'].split(',')
|
||||||
|
for i, url in enumerate(image_urls):
|
||||||
|
if url.strip():
|
||||||
|
ext = os.path.splitext(urlparse(url).path)[1] or '.jpg'
|
||||||
|
image_path = os.path.join(media_dir, f'image_{i+1}{ext}')
|
||||||
|
if not os.path.exists(image_path) or os.path.getsize(image_path) == 0:
|
||||||
|
is_complete = False
|
||||||
|
break
|
||||||
|
|
||||||
|
if record['video_url'] and record['video_url'].strip():
|
||||||
|
url = record['video_url'].strip()
|
||||||
|
ext = os.path.splitext(urlparse(url).path)[1] or '.mp4'
|
||||||
|
video_path = os.path.join(media_dir, f'video{ext}')
|
||||||
|
if not os.path.exists(video_path) or os.path.getsize(video_path) == 0:
|
||||||
|
is_complete = False
|
||||||
|
|
||||||
|
# 如果下载不完整,尝试重新下载
|
||||||
|
if not is_complete:
|
||||||
|
print(f"发现未完成下载的记录: {note_id},开始重试下载...")
|
||||||
|
is_complete = retry_download(
|
||||||
|
note_id,
|
||||||
|
record['image_list'],
|
||||||
|
record['video_url']
|
||||||
|
)
|
||||||
|
|
||||||
|
# 更新数据库状态
|
||||||
|
if is_complete != record['download_flag']:
|
||||||
|
cursor.execute(update_query, (is_complete, note_id))
|
||||||
|
status = "完成" if is_complete else "未完成"
|
||||||
|
print(f"更新记录 {note_id} 的下载状态为: {status}")
|
||||||
|
|
||||||
|
completed += 1
|
||||||
|
if completed % 10 == 0:
|
||||||
|
print(f"进度: {completed}/{total}")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
print("检查和重试下载完成!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"发生错误: {e}")
|
||||||
|
finally:
|
||||||
|
if 'conn' in locals():
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
check_media_files()
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
# 基础配置
|
# 基础配置
|
||||||
PLATFORM = "xhs"
|
PLATFORM = "xhs"
|
||||||
KEYWORDS = "编程副业,编程兼职" # 关键词搜索配置,以英文逗号分隔
|
KEYWORDS = """“宝宝你是一个油痘肌”""" # 关键词搜索配置,以英文逗号分隔
|
||||||
LOGIN_TYPE = "qrcode" # qrcode or phone or cookie
|
LOGIN_TYPE = "qrcode" # qrcode or phone or cookie
|
||||||
COOKIES = ""
|
COOKIES = ""
|
||||||
# 具体值参见media_platform.xxx.field下的枚举值,暂时只支持小红书
|
# 具体值参见media_platform.xxx.field下的枚举值,暂时只支持小红书
|
||||||
@ -35,7 +35,7 @@ IP_PROXY_PROVIDER_NAME = "kuaidaili"
|
|||||||
# 设置False会打开一个浏览器
|
# 设置False会打开一个浏览器
|
||||||
# 小红书如果一直扫码登录不通过,打开浏览器手动过一下滑动验证码
|
# 小红书如果一直扫码登录不通过,打开浏览器手动过一下滑动验证码
|
||||||
# 抖音如果一直提示失败,打开浏览器看下是否扫码登录之后出现了手机号验证,如果出现了手动过一下再试。
|
# 抖音如果一直提示失败,打开浏览器看下是否扫码登录之后出现了手机号验证,如果出现了手动过一下再试。
|
||||||
HEADLESS = False
|
HEADLESS = True
|
||||||
|
|
||||||
# 是否保存登录状态
|
# 是否保存登录状态
|
||||||
SAVE_LOGIN_STATE = True
|
SAVE_LOGIN_STATE = True
|
||||||
@ -50,7 +50,7 @@ USER_DATA_DIR = "%s_user_data_dir" # %s will be replaced by platform name
|
|||||||
START_PAGE = 1
|
START_PAGE = 1
|
||||||
|
|
||||||
# 爬取视频/帖子的数量控制
|
# 爬取视频/帖子的数量控制
|
||||||
CRAWLER_MAX_NOTES_COUNT = 200
|
CRAWLER_MAX_NOTES_COUNT = 1
|
||||||
|
|
||||||
# 并发爬虫数量控制
|
# 并发爬虫数量控制
|
||||||
MAX_CONCURRENCY_NUM = 1
|
MAX_CONCURRENCY_NUM = 1
|
||||||
@ -59,7 +59,7 @@ MAX_CONCURRENCY_NUM = 1
|
|||||||
ENABLE_GET_IMAGES = False
|
ENABLE_GET_IMAGES = False
|
||||||
|
|
||||||
# 是否开启爬评论模式, 默认开启爬评论
|
# 是否开启爬评论模式, 默认开启爬评论
|
||||||
ENABLE_GET_COMMENTS = True
|
ENABLE_GET_COMMENTS = False
|
||||||
|
|
||||||
# 爬取一级评论的数量控制(单视频/帖子)
|
# 爬取一级评论的数量控制(单视频/帖子)
|
||||||
CRAWLER_MAX_COMMENTS_COUNT_SINGLENOTES = 10
|
CRAWLER_MAX_COMMENTS_COUNT_SINGLENOTES = 10
|
||||||
|
3
config/xhs_config.py
Normal file
3
config/xhs_config.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
SEARCH_KEYWORDS = [
|
||||||
|
"熬夜"
|
||||||
|
]
|
141
docs/project_workflow.md
Normal file
141
docs/project_workflow.md
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
# 小红书内容智能分析系统
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
本项目旨在构建一个自动化的小红书内容采集和智能分析系统。通过爬虫采集、多模态内容处理和AI分析,将小红书的图文视频内容转化为结构化的知识输出。
|
||||||
|
|
||||||
|
## 系统架构
|
||||||
|
|
||||||
|
### 1. 数据采集层
|
||||||
|
#### 1.1 内容爬取
|
||||||
|
- 使用 MediaCrawler 爬虫框架
|
||||||
|
- 根据指定关键词抓取小红书笔记
|
||||||
|
- 将原始数据保存为 JSON 格式
|
||||||
|
- 包含笔记文本、图片URL、视频URL等信息
|
||||||
|
|
||||||
|
#### 1.2 数据存储
|
||||||
|
- 将 JSON 数据导入 MySQL 数据库
|
||||||
|
- 建立规范的数据表结构
|
||||||
|
- 实现数据的持久化存储和管理
|
||||||
|
|
||||||
|
#### 1.3 媒体文件下载
|
||||||
|
- 从数据库读取媒体文件URL
|
||||||
|
- 下载笔记关联的图片和视频
|
||||||
|
- 按笔记ID分类存储在本地文件系统
|
||||||
|
|
||||||
|
### 2. 内容处理层
|
||||||
|
#### 2.1 视频处理
|
||||||
|
- 使用 Faster-Whisper 模型
|
||||||
|
- 将视频音频转换为文字
|
||||||
|
- 支持中文语音识别
|
||||||
|
- 保存字幕文本
|
||||||
|
|
||||||
|
#### 2.2 图像处理
|
||||||
|
- 使用 ChatGPT-4-Vision 模型
|
||||||
|
- 分析图片内容
|
||||||
|
- 提取图片中的关键信息
|
||||||
|
- 生成图片描述文本
|
||||||
|
|
||||||
|
### 3. 智能分析层
|
||||||
|
#### 3.1 内容理解
|
||||||
|
- 使用 ChatGPT 处理文本内容
|
||||||
|
- 整合视频字幕和图片描述
|
||||||
|
- 生成内容摘要
|
||||||
|
- 提取关键信息点
|
||||||
|
|
||||||
|
#### 3.2 知识图谱
|
||||||
|
- 基于内容分析生成思维导图
|
||||||
|
- 展示主题间的逻辑关系
|
||||||
|
- 可视化知识结构
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
- 爬虫框架:MediaCrawler
|
||||||
|
- 数据库:MySQL
|
||||||
|
- 音频处理:Faster-Whisper
|
||||||
|
- 图像识别:ChatGPT-4-Vision
|
||||||
|
- 自然语言处理:ChatGPT
|
||||||
|
- 编程语言:Python
|
||||||
|
|
||||||
|
## 工作流程图
|
||||||
|
![工作流程图](static/images/fig1.png)
|
||||||
|
|
||||||
|
|
||||||
|
## 预期成果
|
||||||
|
1. 自动化的内容采集系统
|
||||||
|
2. 结构化的多模态数据存储
|
||||||
|
3. 智能化的内容理解和分析
|
||||||
|
4. 可视化的知识展示
|
||||||
|
|
||||||
|
## 应用场景
|
||||||
|
- 内容创作参考
|
||||||
|
- 市场趋势分析
|
||||||
|
- 用户行为研究
|
||||||
|
- 知识管理系统
|
||||||
|
|
||||||
|
## 后续优化方向
|
||||||
|
1. 提高爬虫效率和稳定性
|
||||||
|
2. 优化媒体文件存储结构
|
||||||
|
3. 提升AI模型处理精度
|
||||||
|
4. 增强可视化展示效果
|
||||||
|
5. 添加用户交互界面
|
||||||
|
|
||||||
|
## 风险分析
|
||||||
|
|
||||||
|
### 1. 法律合规风险
|
||||||
|
|
||||||
|
#### 1.1 违反网络安全法风险
|
||||||
|
- 根据《中华人民共和国网络安全法》第四十四条规定,任何个人和组织不得窃取或者以其他非法方式获取个人信息
|
||||||
|
- 在爬取过程中必须避免收集用户个人隐私信息
|
||||||
|
- 确保数据采集和使用符合相关法律法规
|
||||||
|
|
||||||
|
#### 1.2 侵犯知识产权风险
|
||||||
|
- 需注意平台内容的版权问题
|
||||||
|
- 避免大规模复制和传播他人原创内容
|
||||||
|
- 不得将爬取的内容用于商业牟利
|
||||||
|
|
||||||
|
#### 1.3 违反平台服务条款风险
|
||||||
|
- 违反平台规则可能面临账号封禁
|
||||||
|
- 过度爬取可能导致IP封锁
|
||||||
|
- 严重违规可能引发平台法律诉讼
|
||||||
|
|
||||||
|
### 2. 技术风险
|
||||||
|
|
||||||
|
#### 2.1 反爬虫机制
|
||||||
|
- 平台可能部署各种反爬虫措施
|
||||||
|
- IP被封禁影响采集效率
|
||||||
|
- 需要不断更新技术方案应对
|
||||||
|
|
||||||
|
#### 2.2 数据质量风险
|
||||||
|
- 采集数据可能不完整或有误
|
||||||
|
- 多媒体内容下载失败
|
||||||
|
- 数据格式变化导致解析错误
|
||||||
|
|
||||||
|
### 3. 使用建议
|
||||||
|
|
||||||
|
#### 3.1 合规使用
|
||||||
|
- 仅采集公开可见的内容
|
||||||
|
- 避免采集用户个人信息
|
||||||
|
- 采集频率保持合理范围
|
||||||
|
- 遵守平台的robots.txt规则
|
||||||
|
|
||||||
|
#### 3.2 技术防范
|
||||||
|
- 使用代理IP分散请求
|
||||||
|
- 控制请求频率和并发数
|
||||||
|
- 做好异常处理和日志记录
|
||||||
|
- 定期备份重要数据
|
||||||
|
|
||||||
|
### 4. 案例警示
|
||||||
|
|
||||||
|
根据[GitHub上的中国爬虫违法违规案例汇总](https://github.com/HiddenStrawberry/Crawler_Illegal_Cases_In_China),以下行为可能带来严重法律后果:
|
||||||
|
|
||||||
|
- 爬取和贩卖个人隐私数据
|
||||||
|
- 破解验证码并提供服务
|
||||||
|
- 未经授权爬取并复制商业数据
|
||||||
|
- 大规模爬取导致目标网站服务中断
|
||||||
|
|
||||||
|
### 5. 合规建议
|
||||||
|
|
||||||
|
1. 项目启动前进行法律可行性评估
|
||||||
|
2. 建立数据安全管理制度
|
||||||
|
3. 保留完整的操作日志记录
|
||||||
|
4. 定期进行合规性自查
|
||||||
|
5. 如有必要可咨询法律专家
|
BIN
docs/project_workflow.pdf
Normal file
BIN
docs/project_workflow.pdf
Normal file
Binary file not shown.
BIN
docs/project_workflow_1.pdf
Normal file
BIN
docs/project_workflow_1.pdf
Normal file
Binary file not shown.
BIN
docs/static/images/fig1.png
vendored
Normal file
BIN
docs/static/images/fig1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
docs/static/images/新建 BMP 图像.bmp
vendored
Normal file
BIN
docs/static/images/新建 BMP 图像.bmp
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
98
flv.md
Normal file
98
flv.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
### CAAC无人机飞行执照申报指南
|
||||||
|
|
||||||
|
#### 1. 无人机执照分类
|
||||||
|
根据中国民用航空局(CAAC)规定,无人机飞行执照主要分为以下几种类型:
|
||||||
|
|
||||||
|
1. **超视距驾驶员执照(机长执照)**
|
||||||
|
- 允许持证人在视觉范围之外操作无人机。
|
||||||
|
- 适用于远距离和高难度任务,作业半径通常大于500米或人机相对高度大于120米。
|
||||||
|
|
||||||
|
2. **视距内驾驶员执照**
|
||||||
|
- 允许在视觉范围内操作无人机。
|
||||||
|
- 适用于短距离和低难度任务,作业半径通常小于或等于500米,人机相对高度小于或等于120米。
|
||||||
|
|
||||||
|
3. **教员证**
|
||||||
|
- 具备培训和指导他人学习无人机操作的能力。
|
||||||
|
- 要求丰富的飞行经验和优秀的教学能力。
|
||||||
|
|
||||||
|
此外,根据无人机的类型,执照还可细分为多旋翼无人机执照和固定翼无人机执照等。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2. 申报执照的基本条件
|
||||||
|
|
||||||
|
1. **年龄要求**:申请人需年满16周岁。
|
||||||
|
2. **身体要求**:通过体检,确保身体健康,具备适应无人机飞行的基本身体条件。
|
||||||
|
3. **背景审查**:无重大违法记录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3. 申报执照的具体步骤
|
||||||
|
|
||||||
|
1. **参加培训课程**
|
||||||
|
- 培训内容包括:
|
||||||
|
- **理论知识**:飞行法规、无人机飞行原理、航空气象等。
|
||||||
|
- **实际飞行技能**:无人机起飞、降落、空中控制及应急操作。
|
||||||
|
- 正规的培训课程是执照申报的必要条件。
|
||||||
|
|
||||||
|
2. **完成理论考试**
|
||||||
|
- 由CAAC组织,考试内容涵盖培训所学理论知识。
|
||||||
|
|
||||||
|
3. **完成实际操作考核**
|
||||||
|
- 包括无人机操控技能考核。
|
||||||
|
- 要求达到规定标准。
|
||||||
|
|
||||||
|
4. **申请执照**
|
||||||
|
- 提交相关材料,包括身份证明、体检证明、考试合格证明等。
|
||||||
|
- 通过审核后即可获得CAAC颁发的无人机飞行执照。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4. 是否需要参加培训班?
|
||||||
|
|
||||||
|
是的。申请人必须通过正规培训班,以学习必要的理论知识和操作技能。培训课程的内容通常包括:
|
||||||
|
- 无人机飞行操作
|
||||||
|
- 安全措施与应急处理
|
||||||
|
- 飞行法规与规则
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 5. 机构推荐
|
||||||
|
以下是提供CAAC无人机执照培训的知名机构:
|
||||||
|
|
||||||
|
1. **翼飞鸿天**
|
||||||
|
- 拥有民航局和AOPA认证的教员,学员考试通过率高。
|
||||||
|
|
||||||
|
2. **鲲鹏堂**
|
||||||
|
- 成立于2012年,提供多种无人机类型的培训,实操场地广阔。
|
||||||
|
|
||||||
|
3. **通航无人机**
|
||||||
|
- 提供专业培训,设施先进,适合不同层次学员。
|
||||||
|
|
||||||
|
4. **能飞无人机学院**
|
||||||
|
- 中南地区指定考试中心,课程种类多。
|
||||||
|
|
||||||
|
其他机构包括撼动、华悦、新航道、三足、青华航宇等,均具备资质并提供系统化培训。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 6. 培训费用参考
|
||||||
|
|
||||||
|
- **超视距驾驶员执照**:10,000元–15,800元。
|
||||||
|
- **视距内驾驶员执照**:8,500元–12,800元。
|
||||||
|
- **固定翼与垂直起降固定翼执照**:16,000元–20,000元。
|
||||||
|
- **直升机执照**:16,000元–20,000元。
|
||||||
|
|
||||||
|
> **建议**:选择培训机构时,重点考虑其师资力量、资质和成功案例,确保获得高质量培训。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 7. 注意事项
|
||||||
|
- 确保申请材料真实、完整。
|
||||||
|
- 提前安排体检,避免申请过程中的不必要延误。
|
||||||
|
- 选择正规培训机构,以保证顺利通过考试并获取执照。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
如有进一步问题,可咨询CAAC官网或直接联系相关培训机构获取详细信息。
|
||||||
|
|
BIN
input.xlsx
Normal file
BIN
input.xlsx
Normal file
Binary file not shown.
231
integrate_xhs_crawler.py
Normal file
231
integrate_xhs_crawler.py
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
from data.xhs.json.import_xhs_notes import connect_to_database, create_table, check_record_exists
|
||||||
|
# from check_downloads import check_media_files
|
||||||
|
from mysql.connector import Error
|
||||||
|
import time
|
||||||
|
import asyncio
|
||||||
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
|
import random
|
||||||
|
|
||||||
|
async def _run_crawler(keyword):
|
||||||
|
"""运行爬虫的异步实现"""
|
||||||
|
try:
|
||||||
|
process = await asyncio.create_subprocess_exec(
|
||||||
|
'python', 'main.py',
|
||||||
|
'--platform', 'xhs',
|
||||||
|
'--lt', 'qrcode',
|
||||||
|
'--keywords', keyword,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
limit=1024*1024
|
||||||
|
)
|
||||||
|
|
||||||
|
# 读取输出流
|
||||||
|
async def read_stream(stream):
|
||||||
|
buffer = ""
|
||||||
|
while True:
|
||||||
|
chunk = await stream.read(8192)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
text = chunk.decode('utf-8', errors='ignore')
|
||||||
|
buffer += text
|
||||||
|
|
||||||
|
# 处理输出
|
||||||
|
while '\n' in buffer:
|
||||||
|
line, buffer = buffer.split('\n', 1)
|
||||||
|
if line.strip():
|
||||||
|
print(f"爬虫进度: {line.strip()}")
|
||||||
|
|
||||||
|
# 同时处理标准输出和错误输出
|
||||||
|
await asyncio.gather(
|
||||||
|
read_stream(process.stdout),
|
||||||
|
read_stream(process.stderr)
|
||||||
|
)
|
||||||
|
|
||||||
|
await process.wait()
|
||||||
|
return process.returncode == 0
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"爬虫执行错误: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def load_search_keywords():
|
||||||
|
"""从sheet_notes文件夹加载搜索关键词"""
|
||||||
|
keywords_dict = {}
|
||||||
|
json_dir = './data/xhs/json/sheet_notes'
|
||||||
|
|
||||||
|
for json_file in os.listdir(json_dir):
|
||||||
|
if not json_file.endswith('.json'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
sheet_name = os.path.splitext(json_file)[0]
|
||||||
|
with open(os.path.join(json_dir, json_file), 'r', encoding='utf-8') as f:
|
||||||
|
keywords = json.load(f)
|
||||||
|
|
||||||
|
# 修护.json从第12个元素开始
|
||||||
|
# if sheet_name == '修护':
|
||||||
|
# keywords = keywords[11:]
|
||||||
|
|
||||||
|
keywords_dict[sheet_name] = keywords
|
||||||
|
|
||||||
|
return keywords_dict
|
||||||
|
|
||||||
|
def insert_note_data(connection, data, sheet_name):
|
||||||
|
"""插入笔记数据到数据库"""
|
||||||
|
insert_query = """
|
||||||
|
INSERT INTO xhs_notes (
|
||||||
|
note_id, type, title, description, video_url, time,
|
||||||
|
last_update_time, user_id, nickname, avatar,
|
||||||
|
liked_count, collected_count, comment_count, share_count,
|
||||||
|
ip_location, image_list, tag_list, last_modify_ts,
|
||||||
|
note_url, source_keyword, sheet_name, download_flag
|
||||||
|
) VALUES (
|
||||||
|
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||||
|
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
cursor = connection.cursor()
|
||||||
|
inserted_count = 0
|
||||||
|
skipped_count = 0
|
||||||
|
|
||||||
|
for item in data:
|
||||||
|
note_id = item.get('note_id')
|
||||||
|
|
||||||
|
# 检查记录是否已存在
|
||||||
|
if check_record_exists(cursor, note_id):
|
||||||
|
skipped_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
values = (
|
||||||
|
note_id,
|
||||||
|
item.get('type'),
|
||||||
|
item.get('title'),
|
||||||
|
item.get('desc'),
|
||||||
|
item.get('video_url'),
|
||||||
|
item.get('time'),
|
||||||
|
item.get('last_update_time'),
|
||||||
|
item.get('user_id'),
|
||||||
|
item.get('nickname'),
|
||||||
|
item.get('avatar'),
|
||||||
|
item.get('liked_count'),
|
||||||
|
item.get('collected_count'),
|
||||||
|
item.get('comment_count'),
|
||||||
|
item.get('share_count'),
|
||||||
|
item.get('ip_location'),
|
||||||
|
item.get('image_list'),
|
||||||
|
item.get('tag_list'),
|
||||||
|
item.get('last_modify_ts'),
|
||||||
|
item.get('note_url'),
|
||||||
|
item.get('source_keyword'),
|
||||||
|
sheet_name,
|
||||||
|
False # download_flag 默认为False
|
||||||
|
)
|
||||||
|
cursor.execute(insert_query, values)
|
||||||
|
inserted_count += 1
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
print(f'成功插入 {inserted_count} 条新数据')
|
||||||
|
print(f'跳过 {skipped_count} 条已存在的数据')
|
||||||
|
|
||||||
|
except Error as e:
|
||||||
|
print(f'插入数据时出错: {e}')
|
||||||
|
connection.rollback()
|
||||||
|
|
||||||
|
def search_xhs_notes(keyword):
|
||||||
|
"""搜索小红书笔记"""
|
||||||
|
try:
|
||||||
|
# 创建事件循环
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 运行爬虫
|
||||||
|
success = loop.run_until_complete(_run_crawler(keyword))
|
||||||
|
if not success:
|
||||||
|
print(f"爬虫执行失败: {keyword}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 读取爬虫结果
|
||||||
|
json_path = f'./data/xhs/json/search_contents_{datetime.now().strftime("%Y-%m-%d")}.json'
|
||||||
|
if not os.path.exists(json_path):
|
||||||
|
print(f"找不到爬虫结果文<EFBFBD><EFBFBD>: {json_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
with open(json_path, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
# 为每条记录添加来源关键词
|
||||||
|
for item in data:
|
||||||
|
item['source_keyword'] = keyword
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
finally:
|
||||||
|
loop.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"搜索过程发生错误: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def keyword_exists_in_db(connection, keyword):
|
||||||
|
"""检查关键词是否已存在于数据库中"""
|
||||||
|
query = "SELECT COUNT(*) FROM xhs_notes WHERE source_keyword = %s"
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(query, (keyword,))
|
||||||
|
result = cursor.fetchone()
|
||||||
|
return result[0] > 0
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# 连接数据库
|
||||||
|
connection = connect_to_database()
|
||||||
|
if connection is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 创建表格
|
||||||
|
create_table(connection)
|
||||||
|
|
||||||
|
# 加载搜索关键词
|
||||||
|
keywords_dict = load_search_keywords()
|
||||||
|
|
||||||
|
# 对每个sheet的关键词进行搜索
|
||||||
|
for sheet_name, keywords in keywords_dict.items():
|
||||||
|
print(f'开始处理 {sheet_name} 的关键词...')
|
||||||
|
|
||||||
|
for keyword in keywords:
|
||||||
|
# 检查关键词是否已存在
|
||||||
|
if keyword_exists_in_db(connection, keyword):
|
||||||
|
print(f'关键词已存在,跳过: {keyword}')
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f'搜索关键词: {keyword}')
|
||||||
|
|
||||||
|
# 搜索小红书笔记
|
||||||
|
search_results = search_xhs_notes(keyword)
|
||||||
|
if search_results:
|
||||||
|
# 将搜索结果保存到数据库
|
||||||
|
insert_note_data(connection, search_results, sheet_name)
|
||||||
|
else:
|
||||||
|
print(f"未获取到搜索结果: {keyword}")
|
||||||
|
|
||||||
|
# 添加延时避免请求过快(随机延时10-30秒)
|
||||||
|
time.sleep(random.uniform(10, 30))
|
||||||
|
|
||||||
|
print(f'{sheet_name} 的关键词处理完成')
|
||||||
|
|
||||||
|
# 下载所有媒体文件
|
||||||
|
# print('开始下载媒体文件...')
|
||||||
|
# check_media_files()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'处理过程中出错: {e}')
|
||||||
|
finally:
|
||||||
|
if connection.is_connected():
|
||||||
|
connection.close()
|
||||||
|
print('数据库连接已关闭')
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
3
launcher.bat
Normal file
3
launcher.bat
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d %~dp0
|
||||||
|
start "" "小红书内容采集器.exe"
|
77
playwright.md
Normal file
77
playwright.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Playwright 爬虫技术分析
|
||||||
|
|
||||||
|
## Playwright 简介
|
||||||
|
|
||||||
|
Playwright 是一个由微软开发的自动化浏览器测试工具,它可以:
|
||||||
|
|
||||||
|
1. 自动控制 Chromium、Firefox 和 WebKit 浏览器
|
||||||
|
2. 模拟真实用户操作
|
||||||
|
3. 执行 JavaScript 代码
|
||||||
|
4. 获取浏览器上下文和 Cookie
|
||||||
|
|
||||||
|
## 使用 Playwright 爬取小红书的步骤
|
||||||
|
|
||||||
|
根据代码分析,主要步骤如下:
|
||||||
|
|
||||||
|
1. **初始化浏览器环境**
|
||||||
|
```python
|
||||||
|
async with async_playwright() as playwright:
|
||||||
|
browser_context = await self.launch_browser(
|
||||||
|
playwright.chromium,
|
||||||
|
proxy=None,
|
||||||
|
headless=config.HEADLESS
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **登录获取 Cookie**
|
||||||
|
```python
|
||||||
|
# 扫码登录
|
||||||
|
login_obj = XiaoHongShuLogin(
|
||||||
|
login_type=config.LOGIN_TYPE,
|
||||||
|
browser_context=self.browser_context,
|
||||||
|
context_page=self.context_page
|
||||||
|
)
|
||||||
|
await login_obj.begin()
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **获取加密参数**
|
||||||
|
- 通过执行 JS 获取 X-s 等签名参数
|
||||||
|
- 保留登录成功后的上下文环境
|
||||||
|
- 避免了复杂的 JS 逆向过程
|
||||||
|
|
||||||
|
4. **发送请求获取数据**
|
||||||
|
```python
|
||||||
|
# 搜索笔记
|
||||||
|
await self.xhs_client.search_notes(
|
||||||
|
keyword=keyword,
|
||||||
|
page=page,
|
||||||
|
sort=SearchSortType.GENERAL
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取笔记详情
|
||||||
|
await self.xhs_client.get_note_by_id(note_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **数据存储**
|
||||||
|
- 支持存储到 MySQL
|
||||||
|
- 支持导出为 CSV
|
||||||
|
- 支持导出为 JSON
|
||||||
|
|
||||||
|
## 核心优势
|
||||||
|
|
||||||
|
1. 降低逆向难度
|
||||||
|
- 不需要复现复杂的加密算法
|
||||||
|
- 直接获取浏览器中的参数
|
||||||
|
|
||||||
|
2. 更真实的请求环境
|
||||||
|
- 完整的浏览器环境
|
||||||
|
- 真实的 Cookie 和请求头
|
||||||
|
|
||||||
|
3. 更稳定的爬取
|
||||||
|
- 自动处理反爬验证
|
||||||
|
- 支持 IP 代理池
|
||||||
|
- 支持登录态缓存
|
||||||
|
|
||||||
|
这种方式通过 Playwright 模拟真实浏览器环境,大大降低了爬虫开发难度,是一种非常实用的爬虫技术方案。
|
||||||
|
|
||||||
|
需要注意的是,使用时要遵守平台规则,合理控制爬取频率,仅用于学习研究用途。
|
40
process_xhs_note.py
Normal file
40
process_xhs_note.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
def excel_to_json():
|
||||||
|
# 创建输出文件夹
|
||||||
|
output_dir = 'sheet_notes'
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
|
||||||
|
# 读取Excel文件
|
||||||
|
excel_file = 'input.xlsx'
|
||||||
|
|
||||||
|
# 获取所有sheet名称
|
||||||
|
xl = pd.ExcelFile(excel_file)
|
||||||
|
sheet_names = xl.sheet_names
|
||||||
|
|
||||||
|
# 处理每个sheet
|
||||||
|
for sheet_name in sheet_names:
|
||||||
|
# 读取当前sheet,跳过第一行,使用第二行作为列名
|
||||||
|
df = pd.read_excel(excel_file,
|
||||||
|
sheet_name=sheet_name,
|
||||||
|
header=1)
|
||||||
|
|
||||||
|
# 获取"笔记标题"列的内容
|
||||||
|
if '笔记标题' in df.columns:
|
||||||
|
# 将笔记标题转换为列表,并去除空值
|
||||||
|
notes = df['笔记标题'].dropna().tolist()
|
||||||
|
|
||||||
|
# 保存为JSON文件
|
||||||
|
output_file = os.path.join(output_dir, f'{sheet_name}.json')
|
||||||
|
with open(output_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(notes, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
print(f'已保存 {sheet_name} 的笔记标题到 {output_file}')
|
||||||
|
else:
|
||||||
|
print(f'警告: {sheet_name} 中没有找到"笔记标题"列')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
excel_to_json()
|
81
project.md
Normal file
81
project.md
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# MediaCrawler 项目技术分析
|
||||||
|
|
||||||
|
## 总体架构
|
||||||
|
|
||||||
|
项目使用了 Playwright 作为核心技术来模拟浏览器行为,主要步骤包括:
|
||||||
|
|
||||||
|
1. 使用 Playwright 启动浏览器并保持登录状态
|
||||||
|
2. 通过执行 JS 获取加密参数
|
||||||
|
3. 使用 httpx 发送请求获取数据
|
||||||
|
4. 数据存储到 MySQL/CSV/JSON
|
||||||
|
|
||||||
|
## 各平台实现细节
|
||||||
|
|
||||||
|
### 1. 抖音
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- 使用 Playwright 模拟浏览器环境
|
||||||
|
- 通过执行 JS 获取 X-Bogus 等加密参数
|
||||||
|
- 支持搜索、指定视频、创作者主页爬取
|
||||||
|
- 支持评论和二级评论获取
|
||||||
|
|
||||||
|
### 2. 小红书
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- 使用 Playwright 获取登录态
|
||||||
|
- 通过 JS 注入获取 X-s 等签名参数
|
||||||
|
- 支持笔记搜索、指定笔记、用户主页爬取
|
||||||
|
- 支持评论数据抓取
|
||||||
|
|
||||||
|
### 3. 快手
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- 使用 Playwright 维持登录状态
|
||||||
|
- 通过 JS 执行获取 _signature 等参数
|
||||||
|
- 支持视频搜索和指定视频爬取
|
||||||
|
- 支持评论数据抓取
|
||||||
|
|
||||||
|
### 4. B站
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- Cookie 登录方式
|
||||||
|
- wbi 签名参数构造
|
||||||
|
- 支持视频搜索和指定视频爬取
|
||||||
|
- 支持评论数据抓取
|
||||||
|
|
||||||
|
### 5. 微博
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- 使用 Playwright 维持登录态
|
||||||
|
- 通过 JS 获取加密参数
|
||||||
|
- 支持微博搜索和指定微博爬取
|
||||||
|
- 支持评论数据抓取
|
||||||
|
|
||||||
|
### 6. 贴吧
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- Cookie 登录方式
|
||||||
|
- 通过解析 HTML 获取数据
|
||||||
|
- 支持帖子搜索和指定帖子爬取
|
||||||
|
- 支持评论数据抓取
|
||||||
|
|
||||||
|
### 7. 知乎
|
||||||
|
|
||||||
|
核心技术:
|
||||||
|
- 使用 Playwright 维持登录态
|
||||||
|
- 通过 JS 获取 x-zse-96 等参数
|
||||||
|
- 支持回答搜索和指定回答爬取
|
||||||
|
- 支持评论数据抓取
|
||||||
|
|
||||||
|
## 项目亮点
|
||||||
|
|
||||||
|
1. 使用抽象类设计,代码结构清晰
|
||||||
|
2. 支持 IP 代理池
|
||||||
|
3. 支持多账号登录
|
||||||
|
4. 支持生成评论词云图
|
||||||
|
5. 支持多种数据存储方式
|
||||||
|
6. 使用 Playwright 降低逆向难度
|
||||||
|
|
||||||
|
这个项目通过巧妙使用 Playwright 来获取加密参数,大大降低了爬虫的开发难度,是一个非常实用的自媒体平台数据采集工具。
|
||||||
|
|
||||||
|
#63f85aee0000000013015174
|
BIN
project.pdf
Normal file
BIN
project.pdf
Normal file
Binary file not shown.
@ -1,18 +1,5 @@
|
|||||||
httpx==0.24.0
|
aiohttp
|
||||||
Pillow==9.5.0
|
aiofiles
|
||||||
playwright==1.42.0
|
mysql-connector-python
|
||||||
tenacity==8.2.2
|
PyQt6
|
||||||
opencv-python
|
pyinstaller
|
||||||
aiomysql==0.2.0
|
|
||||||
redis~=4.6.0
|
|
||||||
pydantic==2.5.2
|
|
||||||
aiofiles~=23.2.1
|
|
||||||
fastapi==0.110.2
|
|
||||||
uvicorn==0.29.0
|
|
||||||
python-dotenv==1.0.1
|
|
||||||
jieba==0.42.1
|
|
||||||
wordcloud==1.9.3
|
|
||||||
matplotlib==3.9.0
|
|
||||||
requests==2.32.3
|
|
||||||
parsel==1.9.1
|
|
||||||
pyexecjs==1.5.1
|
|
1121
xhs_crawler_gui.py
Normal file
1121
xhs_crawler_gui.py
Normal file
File diff suppressed because it is too large
Load Diff
116
向量化小红书笔记流程图.md
Normal file
116
向量化小红书笔记流程图.md
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# 向量化小红书笔记流程及注意事项
|
||||||
|
|
||||||
|
## 正向过程(笔记内容向量化)
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[开始] --> B[连接MySQL数据库]
|
||||||
|
B --> C[查询xhs_notes表<br>type='normal'的笔记]
|
||||||
|
C --> D[初始化FAISS向量存储]
|
||||||
|
|
||||||
|
subgraph 笔记处理循环
|
||||||
|
E[获取单条笔记数据<br>note_id, title, description] --> F[合并标题和描述]
|
||||||
|
F --> G[文本分割<br>chunk_size=120<br>overlap=20]
|
||||||
|
G --> H[创建新的向量存储new_vs]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph FAISS向量存储内部结构
|
||||||
|
H --> I1[FAISS索引<br>存储向量数据]
|
||||||
|
H --> I2[DocStore内部字典<br>key: vector_id自动生成<br>value: Document对象]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph 向量存储处理
|
||||||
|
I2 --> J[遍历DocStore字典<br>获取vector_id和文档内容]
|
||||||
|
J --> K[生成content_hash]
|
||||||
|
K --> L{检查content_hash<br>是否存在}
|
||||||
|
L -->|不存在| M[存入vector_store表<br>关联字段:<br>note_id<br>vector_id<br>content<br>content_hash]
|
||||||
|
L -->|存在| N[跳过]
|
||||||
|
M --> O[合并到主向量存储]
|
||||||
|
N --> O
|
||||||
|
end
|
||||||
|
|
||||||
|
O --> P[保存最终向量存储<br>到本地文件]
|
||||||
|
P --> Q[结束]
|
||||||
|
|
||||||
|
subgraph 数据关系说明
|
||||||
|
R[xhs_notes表] -.->|note_id关联| S[vector_store表]
|
||||||
|
S -.->|vector_id关联| T[FAISS DocStore]
|
||||||
|
T -.->|自动生成| U[UUID格式的vector_id]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1. vector_id 的生成过程:
|
||||||
|
- 当使用 FAISS.from_texts() 创建新的向量存储时,FAISS 会自动为每个文本片段生成一个 UUID 格式的 vector_id
|
||||||
|
这个 vector_id 存储在 FAISS 的 DocStore 内部字典中作为 key
|
||||||
|
代码中通过 new_vs.docstore._dict.items() 可以获取这些 vector_id
|
||||||
|
|
||||||
|
2. 数据结构关系:
|
||||||
|
```json
|
||||||
|
new_vs.docstore._dict = {
|
||||||
|
"vector_id_1": Document(page_content="文本内容1"),
|
||||||
|
"vector_id_2": Document(page_content="文本内容2"),
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 存储过程:
|
||||||
|
- FAISS 索引存储实际的向量数据
|
||||||
|
- DocStore 存储 vector_id 和文本内容的映射
|
||||||
|
MySQL 中的 vector_store 表存储 vector_id、note_id 和文本内容的关联关系
|
||||||
|
|
||||||
|
这样,通过 vector_id 就可以:
|
||||||
|
- 在 FAISS 中找到对应的向量
|
||||||
|
- 在 DocStore 中找到原始文本
|
||||||
|
- 在数据库中找到对应的笔记 ID
|
||||||
|
|
||||||
|
|
||||||
|
## 反向过程(通过用户输入的文本,检索出对应的笔记)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[开始] --> B[加载FAISS向量存储]
|
||||||
|
B --> C[向量化用户查询]
|
||||||
|
C --> D[执行相似度搜索<br>k=10条结果]
|
||||||
|
|
||||||
|
subgraph 向量搜索结果处理
|
||||||
|
D --> E[遍历搜索结果<br>doc, score]
|
||||||
|
E --> F[计算文本内容的<br>content_hash]
|
||||||
|
F --> G[查询vector_store表<br>通过content_hash<br>获取note_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph 笔记数据获取
|
||||||
|
G --> H{note_id是否<br>已处理?}
|
||||||
|
H -->|否| I[查询xhs_notes表<br>获取笔记详情]
|
||||||
|
H -->|是| J[跳过]
|
||||||
|
I --> K[获取清洗后的<br>笔记内容]
|
||||||
|
K --> L[构建完整笔记数据]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph 数据整合
|
||||||
|
L --> M[收集上下文内容<br>用于GPT]
|
||||||
|
L --> N[收集完整笔记数据<br>用于前端展示]
|
||||||
|
end
|
||||||
|
|
||||||
|
M --> O[调用GPT生成回答]
|
||||||
|
N --> P[返回GPT回答和笔记数据]
|
||||||
|
P --> Q[结束]
|
||||||
|
|
||||||
|
subgraph 数据结构关系
|
||||||
|
R[FAISS向量库] -.->|相似度搜索| S[文本内容]
|
||||||
|
S -.->|content_hash| T[vector_store表]
|
||||||
|
T -.->|note_id| U[xhs_notes表]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph 笔记数据结构
|
||||||
|
V[完整笔记数据包含:]
|
||||||
|
V --> V1[note_id]
|
||||||
|
V --> V2[标题]
|
||||||
|
V --> V3[描述]
|
||||||
|
V --> V4[收藏数]
|
||||||
|
V --> V5[评论数]
|
||||||
|
V --> V6[分享数]
|
||||||
|
V --> V7[清洗后内容]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue
Block a user