Skip to content
HsuantPublic

About

本项目旨在构建一个全自动爬虫,用于爬取携程、去哪儿、马蜂窝、美团等平台上的景点、美食和酒店等信息。通过机器学习技术,我们将对这些信息进行情感分析、词云分析、距离热图分析和可视化等深度分析。这将有助于用户、地方更好地了解各类景点、酒店和美食的评价和特点,从而做出更明智的选择和发展决策

Topics

Resources

Stars

41 stars

Watchers

1 watching

Forks

Latest commit

 

History

75 Commits

Folders and files

Repository files navigation

LifeLens

旅游数据爬取与分析系统 —— 从携程、去哪儿等平台采集景点信息、详情与用户评论,为旅行决策提供数据支撑。

免责声明

请以学习与研究为目的使用本项目。禁止将本项目用于商业用途、大规模或高频采集、绕过平台访问控制,以及任何违反法律法规或平台规则的行为。使用者应自行确认采集行为的合规性,并承担因使用本项目产生的一切责任。项目作者不对任何直接或间接损失、数据使用后果或法律纠纷负责。

详细条款见 使用须知 与 License。

功能概览

已实现

  • 全链路采集:携程与去哪儿景点列表、详情、评论一站式爬取
  • ID 自动解析:根据景点名或城市名自动定位 poi_id / district_id,无需手动查询
  • 流水线编排:list → detail → comments 一键串联,单个入口支持 sight / city / poi_id / district_id 四种目标
  • 断点续跑:中断后重新执行自动跳过已完成景点;评论按页 checkpoint,失败页面单独记录
  • 请求防护:随机延迟(默认 1-3 秒)、HTTP 非 200 状态码线性退避重试 3 次
  • 集中配置:API 端点、请求头、超时、分页参数统一管理于 config.py
  • 离线测试:核心单测 mock 网络请求,不依赖真实 API 可用性
  • 统一基础设施:BaseSpider 重试、SpiderLogger 分级日志、storage_layout 统一目录布局与 StorageBackend JSON/CSV 存储

待实现

  • 分析层:情感分析、词云、地理热图(占位模块与依赖已就位)
  • 数据模型接入:Sight / Comment 数据模型替换裸 dict(模型已定义,尚未替换各模块返回值)
  • 代理轮换:RequestOptimizer.get_random_proxy() 已实现,但尚未接入各爬虫的实际请求调用
  • 美团平台:平台目录已预留,尚未接入

环境要求

  • Python >= 3.9
  • 核心依赖仅 requests 与 beautifulsoup4;测试依赖 pytest,分析层依赖见下方 extras

快速开始

安装

git clone https://github.com/Hsuant/LifeLens.git
cd LifeLens
pip install -e ".[dev]"           # 基础功能 + 测试依赖

可选 extras:

extra 用途
analysis pandas / numpy / scikit-learn / matplotlib / seaborn / jieba
geo geopandas(地理热图)
deep torch / transformers(深度模型)

命令行用法

两个平台使用统一的参数名:名称参数为 --sight、--city,ID 参数为 --poi-id、--district-id。

# 按景点名称
python -m lifelens.platforms.ctrip.pipeline --sight "黄鹤楼"

# 按城市名称
python -m lifelens.platforms.ctrip.pipeline --city "杭州" --list-pages 3

# 按景点 POI ID
python -m lifelens.platforms.ctrip.pipeline --poi-id 10568753

# 按地区 ID
python -m lifelens.platforms.ctrip.pipeline --district-id 9 --list-pages 3

# 去哪儿同样使用 --sight、--city、--poi-id
python -m lifelens.platforms.qunar.pipeline --city "北京" --max-sights 10

参数说明(--sight / --city / --poi-id / --district-id 四选一):

参数 说明 默认值
--sight 景点名称,自动解析 POI ID ""
--city 城市名称,自动解析地区 ID ""
--poi-id 景点 POI ID None
--district-id 携程地区 ID —
--list-pages 景点列表爬取页数 None(不限制,自动爬取所有页)
--max-comment-pages 每个景点评论最大爬取页数 None(不限制,爬取所有页)
--output-dir 输出根目录 data

注:Qunar 评论接口暂不支持地区 ID 查询,因此 --district-id 仅适用于 Ctrip;Qunar 请使用 --city。

编程式用法

from lifelens.platforms.ctrip.pipeline import CtripPipeline

pipeline = CtripPipeline(output_dir="data")

# 统一主入口:名称用 sight / city,ID 用 poi_id / district_id
result = pipeline.run(poi_id="10568753")
result = pipeline.run(district_id=9, list_pages=5, max_comment_pages=50)
result = pipeline.run(city="杭州", list_pages=5, max_comment_pages=50)
result = pipeline.run(sight="黄鹤楼", max_comment_pages=50)
print(result)

返回值结构:

// 地区模式
{"total": 20, "completed": 18, "failed": 2, "skipped": 0, "elapsed_seconds": 152.3}

// 名称解析模式:在上述字段外额外附带
{"city": "杭州", "resolved_type": "district", "resolved_info": {...}}

// 景点模式
{"total": 1, "completed": 1, "failed": 0, "skipped": 0,
 "poi_id": "10568753", "poi_name": "千岛湖",
 "details_success": true, "comments_success": true, "elapsed_seconds": 8.4}

// 失败
{"success": false, "error": "未获取到景点列表"}

入口方法对比:

方法 适用场景 关键参数
run() 统一入口,按景点、城市或 ID 选择任务 sight / city / poi_id / district_id 四选一
_run_district() 内部地区流水线 district_id, city, list_pages, max_comment_pages
_run_sight() 内部单景点流水线 poi_id, sight, max_comment_pages

单模块使用

from lifelens.platforms.ctrip.sight_list import CtripAttractionScraper
from lifelens.platforms.ctrip.sight_detail import AttractionDetailFetcher
from lifelens.platforms.ctrip.sight_comments import CtripCommentSpider
from lifelens.platforms.ctrip.sight_locator import SightLocator
from lifelens.core.storage import json_storage

# 自动解析 ID(无需手动查询)
locator = SightLocator()

# 按景点名获取 POI ID 及所属地区
info = locator.locate_sight("黄鹤楼")
# {"type": "sight", "poi_id": "77593", "sight_name": "黄鹤楼",
#  "district_id": 145, "district_name": "武汉", "city_id": ..., "city_name": "..."}

# 按地区名获取地区 ID
info = locator.locate_district("杭州")
# {"type": "district", "district_id": 14, "district_name": "杭州", ...}

# 自动判断关键词类型(流水线内部使用的入口)
info = locator.locate("西湖")

# 获取景点列表
scraper = CtripAttractionScraper()
sights = scraper.get_attractions_with_pagination(district_id=9, pages=2)
json_storage.save(sights, "data/sights.json")

# 获取景点详情(get_detail 返回原始解析结果,get_formatted_detail 返回精简视图)
fetcher = AttractionDetailFetcher()
detail = fetcher.get_detail("10568753")
print(detail["poi_name"], detail["ticket_price"], detail["description"])

# 爬取评论(单景点 / 多景点)
spider = CtripCommentSpider(output_dir="data/comments")
spider.crawl_comments("10568753", "千岛湖", max_pages=10)
spider.crawl_multiple_pois([("10568753", "千岛湖"), ("77593", "黄鹤楼")], max_pages=10)

配置

所有携程 API 参数集中定义在 src/lifelens/config.py 的 CtripConfig dataclass 中,全局目录参数见 GlobalConfig:

配置项 说明 默认值
sight_search_url 关键词搜索 API .../soa2/26872/search
sight_list_url 景点列表 API .../soa2/13342/json/getSightRecreationList
sight_detail_url 景点详情 API .../soa2/18254/json/getPoiMoreDetail
comment_url 评论 API .../soa2/13444/json/getCommentCollapseList
headers 请求头(UA / Content-Type / Referer 等) 见 config.py
head 搜索 / 列表 / 详情 / 评论共用 head 结构 cid=09031065211914680477
comment_cid 评论 API 专用 cid 09031069112760102754
timeout 请求超时(秒) 10
delay_range 随机延迟范围(秒) (1, 3)
list_page_size 景点列表每页条数 20
comment_page_size 评论每页条数 10
全局配置 说明 默认值
GlobalConfig.log_dir 日志目录 logs
GlobalConfig.data_dir 数据目录 data
GlobalConfig.default_timeout 默认超时 10
GlobalConfig.default_delay_range 默认延迟范围 (1, 3)

注意:.env.example 目前是配置模板,代码尚未读取环境变量(未接入 python-dotenv)。需要调整 cid、超时、延迟范围时,请直接编辑 config.py。

数据输出

统一目录结构为:

data/<platform>/<province>/<city>/<sight>_<poi-id>/

省、市优先取平台字段;缺失时从详情地址解析。无法确定的行政区使用 Unknown,不会猜测。

地区任务(_run_district()):

data/
└── ctrip/
    └── 浙江省/
        └── 杭州市/
            ├── sights.json
            ├── summary.json
            ├── pipeline_progress.json
            └── 千岛湖_10568753/
                ├── detail.json
                ├── comments.csv
                ├── comments_progress.json
                ├── failed_pages.json
                └── summary.json

景点任务(_run_sight()):

data/
└── qunar/
    └── 北京市/
        └── 北京市/
            └── 故宫博物院_989946426/
                ├── detail.json
                ├── comments.csv
                ├── comments_progress.json
                ├── failed_pages.json
                └── summary.json

评论 CSV 采用 utf-8-sig 编码(Excel 可直接打开),字段依次为:

序号、景区ID、景区名称、评论ID、用户昵称、总体评分、评论内容、发布时间、有用数、回复数、出行类型、用户所在地、游玩时长、图片数量、图片链接列表、景色评分、趣味评分、性价比评分、推荐项目

断点续跑机制

  • pipeline_progress.json:仅当某景点详情与评论都成功时才写入。只成功一项的景点不会被标记完成,下次运行会重新尝试该景点。
  • comments_progress.json:位于景点目录,按 {poi_id: {last_page, total_pages, status}} 记录评论断点。
  • failed_pages.json:位于景点目录,记录 {poi_id, page, error, timestamp},便于定位与补采。
  • 需要强制重新采集时,删除对应进度文件即可。

日志按平台、组件和日期组织:

logs/
├── ctrip/
│   ├── pipeline_2026-10-24.log
│   └── comment_spider_2026-10-24.log
└── qunar/
    ├── pipeline_2026-10-24.log
    └── comment_spider_2026-10-24.log

测试

# 当前开发环境
D:\Environments\Anaconda\envs\AI\python.exe -m pytest -q

# 或任意可用的 Python >= 3.9
python -m pytest -q

pyproject.toml 已配置 pythonpath = ["src"],无需手动设置 PYTHONPATH。当前离线测试按 core/、platforms/ 与 integration/ 组织,manual/ 仅存放需要手动执行的联网或调试脚本。

测试文件 覆盖内容
core/test_base_spider.py BaseSpider 共享重试封装、CtripBaseSpider JSON POST、继承契约
core/test_logger.py 分级日志格式、URL 脱敏、日志文件分组、请求/延迟统计
core/test_storage_layout.py 行政区解析、安全路径、平台/省市/景点目录布局
integration/test_pipeline_cli.py run() 四种目标分发、城市/景点解析与统一 CLI 参数
integration/test_keyboard_interrupt.py 评论爬虫与流水线 Ctrl+C 中断保留断点/已完成进度
platforms/ctrip/test_sight_locator.py 关键词 → 景点 / 地区 ID 解析、类型自动判断、解析边界条件
platforms/ctrip/test_sight_list.py POI 解析、请求体构建、分页取数
platforms/ctrip/test_comment_storage.py CSV 表头、字段顺序、跨页追加、断点进度
platforms/ctrip/test_comment_pagination.py 总页数向上取整计算
platforms/qunar/test_sight_workflow.py 去哪儿详情、列表、定位、评论与流水线工作流
platforms/qunar/test_comments.py 去哪儿 window.context 评论解析与兜底逻辑
platforms/qunar/test_online.py 去哪儿联网冒烟测试(离线自动跳过)
手动脚本 用途
manual/ctrip_online_smoke.py 携程联网冒烟测试
manual/ctrip_comments_api_debug.py 携程评论 API 响应结构探测
manual/ctrip_sight_detail_debug.py 携程景点详情 API 响应结构探测
manual/logger_smoke.py 手动检查日志各级别输出

除 platforms/qunar/test_online.py 外,其余自动收集的测试均为离线测试(mock 网络),不依赖真实 API。manual/ 下的文件名不匹配 test_*.py,pytest 不会自动收集,需要时手动运行。

项目结构

LifeLens/
├── pyproject.toml                # 依赖管理 + 项目元数据 + pytest 配置
├── .env.example                  # 配置模板(代码暂未读取)
├── src/lifelens/
│   ├── __main__.py               # 顶层 CLI 入口(子命令占位)
│   ├── config.py                 # 集中配置 (URL / headers / 超时 / 分页)
│   ├── core/                     # 基础设施层 (平台无关)
│   │   ├── base_spider.py        #   BaseSpider 抽象基类 + 重试封装
│   │   ├── logger.py             #   SpiderLogger 分级日志 + 任务汇总
│   │   ├── request_optimizer.py  #   随机延迟 + 代理 + 退避参数
│   │   ├── storage_layout.py     #   跨平台数据目录布局 + 行政区解析
│   │   ├── storage.py            #   StorageBackend (JSON / CSV)
│   │   └── pipeline.py           #   BasePipeline + PipelineStats 结果统计
│   ├── platforms/
│   │   ├── ctrip/                # 携程平台
│   │   │   ├── sight_locator.py  #   关键词 → POI ID / 地区 ID (自动解析)
│   │   │   ├── sight_list.py     #   地区 → 景点列表 (分页)
│   │   │   ├── sight_detail.py   #   景点详情 (电话/门票/描述/交通)
│   │   │   ├── sight_comments.py #   评论爬取 (断点续爬 + CSV)
│   │   │   ├── base.py           #   CtripBaseSpider 公共请求/重试基类
│   │   │   └── pipeline.py       #   CtripPipeline 全流程编排 (含 CLI)
│   │   ├── qunar/                # 去哪儿平台
│   │   │   ├── sight_locator.py  #   景点 / 城市 → ID 解析
│   │   │   ├── sight_list.py     #   城市榜单 → 景点列表
│   │   │   ├── sight_detail.py   #   详情页 + 内嵌简介页解析
│   │   │   ├── sight_comments.py #   评论爬取 (window.context + CSV)
│   │   │   ├── base.py           #   QunarBaseSpider 公共 GET / 解析基类
│   │   │   └── pipeline.py       #   QunarPipeline 全流程编排 (含 CLI)
│   │   └── meituan/              # 美团平台 (待实现)
│   ├── models/
│   │   └── sight.py              # Sight / SightDetail / Comment 数据模型
│   └── analysis/                 # 分析层 (待实现)
│       ├── sentiment.py          #   情感分析
│       ├── wordcloud.py          #   词云生成
│       └── heatmap.py            #   地理热图
├── tests/                        # 测试套件
│   ├── core/                     #   核心基础设施测试
│   ├── platforms/                #   平台测试(ctrip / qunar)
│   ├── integration/              #   跨模块与流水线测试
│   └── manual/                   #   手动联网与调试脚本
├── data/                         # 输出目录 (gitignored)
└── logs/                         # 日志目录 (gitignored)

技术栈

层级 技术
网络请求 requests(会话 + 随机延迟 + 3 次退避重试)
HTML 解析 beautifulsoup4
数据模型 dataclasses
存储 标准库 json / csv(utf-8-sig)
测试框架 pytest
分析层 (计划) pandas · scikit-learn · jieba · matplotlib · seaborn · geopandas

路线图

  • 携程景点列表爬取(分页 + 重试)
  • 携程景点详情获取(结构化解析)
  • 携程评论爬取(断点续爬 + CSV 持久化)
  • 去哪儿景点列表 / 详情 / 定位 / 评论爬取
  • 流水线编排(list → detail → comments)
  • 集中配置(config.py 统一管理)
  • ID 自动解析(SightLocator:关键词 → poi_id / district_id)
  • 流水线 CLI(携程 / 去哪儿模块入口)
  • 统一平台参数(sight / city / poi_id / district_id)
  • 分级日志与任务汇总(SpiderLogger / PipelineStats)
  • 统一数据目录布局(data/<platform>/<province>/<city>/<sight>_<poi-id>)
  • BaseSpider 继承复用(消除各模块重复的重试逻辑)
  • StorageBackend 接入(统一 JSON/CSV 存储)
  • 数据模型接入(Sight / Comment 替换裸 dict)
  • 代理轮换接入实际请求(get_random_proxy() 已实现)
  • 顶层 CLI 子命令接入(ctrip-list / ctrip-detail / ctrip-comments)
  • 分析层:情感分析、词云生成、地理热图
  • 美团平台爬虫

使用须知

使用本项目即表示你已阅读并同意以下条款。如不同意,请停止使用并删除本项目及相关数据。

1. 项目定位

本项目仅用于个人学习、技术研究与数据分析练习,不提供任何形式的数据采集服务,也不构成对任何平台数据的授权。

2. 合规使用

  • 使用前请自行确认目标平台的服务条款、robots 协议、用户协议以及所在地法律法规;
  • 不得采集、存储或传播涉及国家安全、商业秘密、个人隐私或其他受法律保护的信息;
  • 不得绕过登录验证、验证码、访问控制、反爬机制或其他技术保护措施;
  • 不得将本项目用于大规模、高频次或影响目标平台正常运行的采集活动;
  • 如需采集个人信息,应取得合法授权,并遵循最小必要原则。

3. 使用限制

  • 禁止将本项目及其衍生代码用于任何商业用途,包括但不限于销售、付费服务、数据转售或商业数据产品;
  • 禁止将采集结果用于骚扰、画像、精准营销、欺诈或其他侵害他人权益的行为;
  • 禁止删除、隐藏或篡改本项目中的版权声明与许可信息。

4. 数据与隐私

  • 采集数据归原始权利人或相关平台所有,本项目不授予你对第三方数据的任何权利;
  • 评论、用户昵称、IP 归属地等字段可能涉及个人信息,请谨慎存储、脱敏处理,并在使用后及时删除;
  • 请勿将采集数据上传至公开仓库、云盘或其他可被未授权访问的位置。

5. 请求频率与平台影响

  • 默认随机延迟为 1-3 秒,请根据实际情况适当调大,避免对目标平台造成压力;
  • 出现限流、封禁或异常响应时应立即停止采集;
  • 本项目不提供绕过限流、验证码或封禁的能力。

6. 账号与凭证

  • 请勿将 Cookie、Token、账号密码等敏感凭证提交至版本库;
  • 建议将凭证保存在本地未跟踪文件中,并定期轮换;
  • 因凭证泄露造成的损失由使用者自行承担。

7. 风险与责任

  • 本项目按“现状”提供,不保证功能完整性、稳定性或适用性;
  • 因使用或无法使用本项目导致的任何直接或间接损失、数据丢失、账号封禁或法律纠纷,作者不承担责任;
  • 使用者应自行评估并承担全部使用风险。

8. 条款变更

作者保留随时修改本使用须知的权利,修改后的条款自发布之日起生效。

License

本项目采用 CC BY-NC 4.0(知识共享 署名-非商业性使用 4.0 国际) 许可协议,完整条款见 LICENSE。

在遵守以下条件的前提下,你可以复制、修改、分发和以非商业目的使用本项目:

  • 署名:必须注明原作者及本项目链接,并说明是否作出修改;
  • 非商业性使用:不得将本项目用于商业目的,包括销售、付费服务、数据转售或其他直接或间接获利行为;
  • 无附加限制:不得通过法律条款或技术手段限制他人行使许可证允许的权利。

如需学术授权、 商业授权或其他用途,请联系 hsuantx@163.com。

注意:本项目许可证仅覆盖本项目代码与文档,不覆盖通过本项目采集的第三方数据。第三方数据的版权、使用权与合规责任由原始权利人或使用者自行承担。

About

本项目旨在构建一个全自动爬虫,用于爬取携程、去哪儿、马蜂窝、美团等平台上的景点、美食和酒店等信息。通过机器学习技术,我们将对这些信息进行情感分析、词云分析、距离热图分析和可视化等深度分析。这将有助于用户、地方更好地了解各类景点、酒店和美食的评价和特点,从而做出更明智的选择和发展决策

Topics

Resources

Stars

41 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages