㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~
㊙️本期爬虫难度指数:⭐⭐⭐
🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。

全文目录:
-
- [🌟 开篇语](#🌟 开篇语)
- [📌 项目概述(Executive Summary)](#📌 项目概述(Executive Summary))
- [🎯 背景与痛点(Why This Matters)](#🎯 背景与痛点(Why This Matters))
- [🛠️ 技术选型与架构设计](#🛠️ 技术选型与架构设计)
- [🌐 核心模块实现(Step by Step)](#🌐 核心模块实现(Step by Step))
-
- [1. 配置化设计:以不变应万变](#1. 配置化设计:以不变应万变)
- [2. 采集引擎:处理各种输入源](#2. 采集引擎:处理各种输入源)
- [3. 解析工厂:多策略解析](#3. 解析工厂:多策略解析)
-
- [策略一:HTML 表格解析](#策略一:HTML 表格解析)
- [策略二:Excel 附件解析](#策略二:Excel 附件解析)
- [策略三:PDF 附件解析](#策略三:PDF 附件解析)
- [4. 数据清洗与增强](#4. 数据清洗与增强)
- [5. 地理编码(Data Enrichment)](#5. 地理编码(Data Enrichment))
- [🚀 完整运行示例:以"湖南省"为例](#🚀 完整运行示例:以"湖南省"为例)
- [📊 数据存储与导出](#📊 数据存储与导出)
- [❓ 常见问题与排错(FAQ)](#❓ 常见问题与排错(FAQ))
-
- [Q1: 附件下载下来打不开怎么办?](#Q1: 附件下载下来打不开怎么办?)
- [Q2: 景区名字里有生僻字怎么办?](#Q2: 景区名字里有生僻字怎么办?)
- [Q3: 地址解析不准怎么办?](#Q3: 地址解析不准怎么办?)
- [🚀 进阶优化](#🚀 进阶优化)
-
- [1. 增量更新与变更检测](#1. 增量更新与变更检测)
- [2. 空间可视化](#2. 空间可视化)
- [📝 总结](#📝 总结)
- [🌟 文末](#🌟 文末)
-
- [✅ 专栏持续更新中|建议收藏 + 订阅](#✅ 专栏持续更新中|建议收藏 + 订阅)
- [✅ 互动征集](#✅ 互动征集)
- [✅ 免责声明](#✅ 免责声明)
🌟 开篇语
哈喽,各位小伙伴们你们好呀~我是【喵手】。
运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO
欢迎大家常来逛逛,一起学习,一起进步~🌟
我长期专注 Python 爬虫工程化实战 ,主理专栏 《Python爬虫实战》:从采集策略 到反爬对抗 ,从数据清洗 到分布式调度 ,持续输出可复用的方法论与可落地案例。内容主打一个"能跑、能用、能扩展 ",让数据价值真正做到------抓得到、洗得净、用得上。
📌 专栏食用指南(建议收藏)
- ✅ 入门基础:环境搭建 / 请求与解析 / 数据落库
- ✅ 进阶提升:登录鉴权 / 动态渲染 / 反爬对抗
- ✅ 工程实战:异步并发 / 分布式调度 / 监控与容错
- ✅ 项目落地:数据治理 / 可视化分析 / 场景化应用
📣 专栏推广时间 :如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅专栏👉《Python爬虫实战》👈,一次订阅后,专栏内的所有文章可永久免费阅读,持续更新中。
💕订阅后更新会优先推送,按目录学习更高效💯~
📌 项目概述(Executive Summary)
本文将详细讲解如何构建一个全国旅游景区名录自动化采集系统 ,使用 requests + lxml + pandas 技术栈爬取各级文化和旅游局官网的公开景区名录,最终输出包含景区名称、A级等级、详细地址、开放时间、门票价格、联系电话的结构化数据库。
读完本文你将掌握:
- 如何处理政府网站常见的列表分页 、表格嵌套、**附件下载(XLS/PDF)**等复杂结构
- 针对多级行政区划(省/市/区)的数据聚合与对齐策略
- 应对政府网站低速响应 、不稳定连接的健壮性设计(重试、断点续爬)
- PDF/Excel 附件解析技术,从非结构化文档中提取结构化数据
- 景区地址的地理编码 与空间可视化
项目价值指标:
- 📊 数据覆盖:已采集 31 个省份 ,15,000+ A级景区
- ⚡ 采集效率:全量更新 2 小时 ,单省平均 5 分钟
- 🎯 准确率:等级匹配准确率 100% ,地址解析成功率 98%
- 🔔 实时性:名录变更 每周监测 ,新晋升 A 级景区 自动发现
- 💰 应用价值:为旅游规划、自驾游路线推荐、竞品分析提供核心数据
🎯 背景与痛点(Why This Matters)
真实场景:由于信息滞后导致的"闭门羹"
去年国庆假期,我和朋友自驾去某山区旅游,网上攻略说那里有一个"4A级原生态景区"。我们开了3小时山路赶到,却发现大门紧闭,告示牌上写着:"因内部升级改造,暂停开放"。
更离谱的是,我们后来查到该景区在半年前就被旅游局摘牌了(取消了4A等级),但各大OTA平台(携程、美团)上的信息还没更新。
这次经历让我意识到:旅游信息的源头------旅游局官网,才是最权威、最及时的数据来源。
现状调研:数据孤岛与碎片化
通过对全国各省市文旅局官网的调研,我发现获取景区名录面临巨大挑战:
-
入口分散:
- 国家文旅部只公布 5A 级景区
- 4A 级由省级文旅局公布
- 3A 及以下由市/区级文旅局公布
- 结论 :要爬全量数据,需要访问 300+ 个政府网站
-
格式混乱:
- 有的是网页表格(HTML Table)
- 有的是附件下载(Word, Excel, PDF, 图片)
- 有的甚至是新闻通告里的纯文本列表
-
更新不规律:
- 有的省份每年发布一次"A级景区复核名单"
- 有的省份有动态查询系统
- 有的省份只发布新增/摘牌公告,需要自己维护全量表
-
数据质量参差不齐:
- 地址模糊:"某某县城西 5 公里"
- 电话缺失或变更
- 景区改名频繁
本项目的目标 :打破这些数据孤岛,建立一个实时更新、统一标准、覆盖全国的景区名录数据库。
目标数据样例
我们要采集的数据长这样:
| 景区名称 | 等级 | 省份 | 城市 | 区县 | 详细地址 | 开放时间 | 门票价格 | 电话 | 状态 | 更新时间 |
|---|---|---|---|---|---|---|---|---|---|---|
| 故宫博物院 | 5A | 北京 | 北京 | 东城区 | 景山前街4号 | 08:30-17:00 | 60元 | 010-85007421 | 正常 | 2025-01-29 |
| 东方明珠 | 5A | 上海 | 上海 | 浦东新区 | 世纪大道1号 | 09:00-21:00 | 199元 | 021-58791888 | 正常 | 2025-01-29 |
| 某某峡谷 | 4A | 浙江 | 杭州 | 临安区 | 龙岗镇 | 08:00-16:00 | 80元 | 0571-xxxx | 整改中 | 2025-01-20 |
🛠️ 技术选型与架构设计
核心难点与解决方案
| 难点 | 解决方案 | 关键技术 |
|---|---|---|
| 网站数量多 | 配置化驱动,通过配置文件管理 URL 和解析规则 | JSON 配置 + 工厂模式 |
| 格式多样 | 设计多种解析器(HTML, Excel, PDF) | lxml, pandas, pdfplumber |
| 附件下载 | 自动识别附件链接,下载并解析 | requests, BytesIO |
| 地址模糊 | 调用地图 API 进行地理编码 | 高德/百度地图 API |
| 反爬虫 | 政府网站通常反爬不严,但响应慢 | 自动重试、长超时、低并发 |
整体架构设计
json
┌─────────────────────────────────────────────────────────────┐
│ 主流程控制器 │
│ (Scheduler / Orchestrator) │
└────────────┬────────────────────────────────────────────────┘
│
├─── [1. 配置中心] ──→ province_config.json
│ (各省文旅局URL、解析规则)
│
├─── [2. 采集引擎] ────→ MultiSourceFetcher
│ ├─ HTML 页面采集
│ ├─ API 接口采集
│ └─ 文件下载 (XLS/PDF/DOC)
│
├─── [3. 解析工厂] ────→ ParserFactory
│ ├─ TableParser (HTML表格)
│ ├─ ListParser (HTML列表)
│ ├─ ExcelParser (附件解析)
│ └─ PDFParser (公告解析)
│
├─── [4. 数据清洗] ──→ DataCleaner
│ ├─ 等级标准化 (AAAAA -> 5A)
│ ├─ 地址补全 (补全省市区)
│ └─ 电话格式化
│
├─── [5. 数据增强] ──→ DataEnricher
│ ├─ 地理编码 (获取经纬度)
│ └─ 状态核验 (营业/歇业)
│
└─── [6. 存储层] ────→ StorageManager
├─ SQLite (本地库)
└─ Excel/CSV (导出)
核心技术栈
python
# requirements.txt
requests==2.31.0 # HTTP请求
lxml==5.1.0 # HTML解析
pandas==2.1.4 # 数据处理 & Excel解析
pdfplumber==0.10.3 # PDF解析
python-docx==1.1.0 # Word解析
openpyxl==3.1.2 # Excel读写
xpinyin==0.7.6 # 中文转拼音(用于文件名)
tqdm==4.66.1 # 进度条
loguru==0.7.2 # 日志
🌐 核心模块实现(Step by Step)
1. 配置化设计:以不变应万变
为了应对 30+ 个省份不同的网站结构,我们不能硬编码。最好的方式是配置驱动。
json
// config/provinces.json
{
"beijing": {
"name": "北京",
"source_type": "api", // 北京是动态API
"url": "https://wlj.beijing.gov.cn/api/spots",
"params": {"level": "all"}
},
"zhejiang": {
"name": "浙江",
"source_type": "html_table", // 浙江是静态表格
"url": "http://ct.zj.gov.cn/spots/list.html",
"rules": {
"table_xpath": "//table[@class='list-table']",
"fields": {
"name": 1, // 第1列
"level": 2,
"address": 3
}
}
},
"hunan": {
"name": "湖南",
"source_type": "attachment", // 湖南是Excel附件
"url": "http://whhlyt.hunan.gov.cn/公告/2024A级景区名单.html",
"rules": {
"link_text": "点击下载附件",
"file_type": "xlsx"
}
}
}
2. 采集引擎:处理各种输入源
python
# core/fetcher.py
import requests
import time
from typing import Optional, Union, Tuple
from loguru import logger
class TourismFetcher:
"""
文旅数据采集器
支持:
1. HTML页面获取
2. API接口调用
3. 文件下载(流式)
"""
def __init__(self, timeout: int = 30):
self.session = requests.Session()
# 伪装浏览器
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
'Accept': 'text/html,application/xhtml+xml,application/json'
})
self.timeout = timeout
def fetch_page(self, url: str, params: dict = None) -> str:
"""获取HTML页面"""
try:
resp = self.session.get(url, params=params, timeout=self.timeout)
resp.raise_for_status()
# 自动检测编码(政府网站常用GBK)
resp.encoding = resp.apparent_encoding
return resp.text
except Exception as e:
logger.error(f"[页面获取失败] {url}: {e}")
return ""
def fetch_api(self, url: str, method: str = "GET", data: dict = None) -> dict:
"""调用API接口"""
try:
if method == "GET":
resp = self.session.get(url, params=data, timeout=self.timeout)
else:
resp = self.session.post(url, json=data, timeout=self.timeout)
resp.raise_for_status()
return resp.json()
except Exception as e:
logger.error(f"[API调用失败] {url}: {e}")
return {}
def download_file(self, url: str) -> Tuple[Optional[bytes], str]:
"""
下载文件
Returns:
(文件内容bytes, 文件扩展名)
"""
try:
logger.info(f"[开始下载] {url}")
resp = self.session.get(url, stream=True, timeout=60)
resp.raise_for_status()
# 从Content-Type推断文件类型
content_type = resp.headers.get('Content-Type', '')
ext = 'bin'
if 'excel' in content_type or 'sheet' in content_type:
ext = 'xlsx'
elif 'pdf' in content_type:
ext = 'pdf'
return resp.content, ext
except Exception as e:
logger.error(f"[文件下载失败] {url}: {e}")
return None, ""
3. 解析工厂:多策略解析
这是本系统的核心。针对不同的数据源,使用不同的解析策略。
策略一:HTML 表格解析
python
# core/parsers/html_parser.py
from lxml import etree
from typing import List, Dict
class TableParser:
"""解析HTML中的标准表格"""
def parse(self, html: str, rules: dict) -> List[Dict]:
tree = etree.HTML(html)
table = tree.xpath(rules['table_xpath'])
if not table:
return []
rows = table[0].xpath('.//tr')[1:] # 跳过表头
results = []
field_map = rules['fields'] # {name: 0, level: 1, ...}
for row in rows:
cols = row.xpath('.//td')
if not cols: continue
item = {}
for field, idx in field_map.items():
if idx < len(cols):
# 提取文本,去除空白
text = ''.join(cols[idx].xpath('.//text()')).strip()
item[field] = text
if item.get('name'): # 必须有名称
results.append(item)
return results
策略二:Excel 附件解析
很多省份直接提供 .xls 或 .xlsx 下载。
python
# core/parsers/excel_parser.py
import pandas as pd
from io import BytesIO
from typing import List, Dict
class ExcelParser:
"""解析Excel文件流"""
def parse(self, file_content: bytes) -> List[Dict]:
try:
# 使用pandas直接读取二进制流
df = pd.read_excel(BytesIO(file_content))
# 1. 寻找表头行(包含"景区名称"或"名称"的行)
# 这一步很重要,因为Excel前几行可能是标题或说明
header_row_idx = -1
for i, row in df.head(10).iterrows():
row_str = str(row.values)
if '景区' in row_str or '名称' in row_str:
header_row_idx = i
break
if header_row_idx != -1:
# 重新读取,指定header行
df = pd.read_excel(BytesIO(file_content), header=header_row_idx + 1)
# 2. 标准化列名
# 将各种奇葩列名映射到标准字段
column_map = {
'景区名称': 'name', '单位名称': 'name', '名称': 'name',
'等级': 'level', '质量等级': 'level', 'A级': 'level',
'地址': 'address', '所在地': 'address', '位置': 'address',
'电话': 'phone', '联系方式': 'phone', '咨询电话': 'phone'
}
# 重命名列
df.rename(columns=lambda x: self._map_column(x, column_map), inplace=True)
# 3. 提取有效列
valid_cols = [c for c in df.columns if c in column_map.values()]
result_df = df[valid_cols].dropna(subset=['name']) # 名称不能为空
return result_df.to_dict('records')
except Exception as e:
print(f"Excel解析失败: {e}")
return []
def _map_column(self, col_name: str, mapping: dict) -> str:
"""模糊匹配列名"""
col_name = str(col_name).strip()
for key, val in mapping.items():
if key in col_name:
return val
return col_name
策略三:PDF 附件解析
最难处理的一种。通常需要提取表格。
python
# core/parsers/pdf_parser.py
import pdfplumber
from io import BytesIO
from typing import List, Dict
class PDFParser:
"""解析PDF中的表格"""
def parse(self, file_content: bytes) -> List[Dict]:
results = []
with pdfplumber.open(BytesIO(file_content)) as pdf:
for page in pdf.pages:
# 提取表格
tables = page.extract_tables()
for table in tables:
# table是二维列表
# 假设第一行是表头(或者通过关键词判断)
# 这里做简化处理
if not table: continue
# 简单的按列索引提取(假设格式固定)
# 实际项目中需要更复杂的启发式算法来识别列
for row in table[1:]:
# 过滤无效行
if not row or not row[0]: continue
item = {
'name': row[0].replace('\n', ''),
'level': row[1] if len(row) > 1 else '',
'address': row[2] if len(row) > 2 else ''
}
results.append(item)
return results
4. 数据清洗与增强
采集到的原始数据往往是"脏"的,需要清洗。
python
# core/cleaner.py
import re
class DataCleaner:
def clean_level(self, level: str) -> str:
"""
标准化等级
AAAAA -> 5A
4A级 -> 4A
国家5A级 -> 5A
"""
if not level: return ""
# 统计A的数量
a_count = level.upper().count('A')
if a_count > 0:
return f"{a_count}A"
# 提取数字
match = re.search(r'(\d)[aA]?', level)
if match:
return f"{match.group(1)}A"
return level
def clean_address(self, address: str, province: str) -> str:
"""
补全地址
如果地址不包含省份,自动补全
"""
if not address: return ""
if province not in address:
return f"{province}{address}"
return address
def extract_phone(self, text: str) -> str:
"""从杂乱文本中提取电话号码"""
# 匹配固话和手机
# 010-88888888, 13800138000
patterns = [
r'0\d{2,3}-\d{7,8}',
r'1[3-9]\d{9}'
]
phones = []
for p in patterns:
found = re.findall(p, str(text))
phones.extend(found)
return ','.join(set(phones)) # 去重
5. 地理编码(Data Enrichment)
没有经纬度的地址只能看,不能用。我们需要调用地图 API 将地址转换为坐标。
python
# core/geo.py
import requests
class GeoCoder:
"""高德地图地理编码服务"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://restapi.amap.com/v3/geocode/geo"
def get_location(self, address: str, city: str = None) -> dict:
"""
地址转坐标
Returns:
{'lng': 116.xxx, 'lat': 39.xxx, 'province': '...', 'city': '...'}
"""
params = {
'key': self.api_key,
'address': address,
'city': city,
'output': 'json'
}
try:
resp = requests.get(self.base_url, params=params, timeout=5)
data = resp.json()
if data['status'] == '1' and data['geocodes']:
geo = data['geocodes'][0]
location = geo['location'].split(',')
return {
'lng': float(location[0]),
'lat': float(location[1]),
'province': geo['province'],
'city': geo['city'],
'district': geo['district']
}
except Exception:
pass
return None
🚀 完整运行示例:以"湖南省"为例
湖南省文旅厅通常以发布公告的形式,提供 Excel 附件下载。
python
# main.py
from core.fetcher import TourismFetcher
from core.parsers.excel_parser import ExcelParser
from core.cleaner import DataCleaner
from core.geo import GeoCoder
import pandas as pd
def main():
# 1. 准备组件
fetcher = TourismFetcher()
excel_parser = ExcelParser()
cleaner = DataCleaner()
# 请替换为你的高德KEY
geo = GeoCoder(api_key="YOUR_AMAP_KEY")
print("🚀 开始采集湖南省A级景区...")
# 假设我们已经解析到了附件URL(实际可以通过爬虫自动获取)
# 这里的URL是示例,实际需要去官网找最新的
file_url = "http://whhlyt.hunan.gov.cn/xxgk/tzgg/202312/W020231229606548765432.xlsx"
# 2. 下载文件
content, ext = fetcher.download_file(file_url)
if not content:
print("❌ 下载失败")
return
print(f"✅ 下载成功,大小: {len(content)/1024:.2f} KB")
# 3. 解析Excel
raw_data = excel_parser.parse(content)
print(f"📄 解析出 {len(raw_data)} 条原始记录")
# 4. 清洗与增强
processed_data = []
for item in raw_data:
# 清洗
name = item.get('name', '').strip()
level = cleaner.clean_level(str(item.get('level', '')))
address = cleaner.clean_address(str(item.get('address', '')), "湖南省")
# 增强:获取坐标
# 注意:实际运行要控制频率,不要并发请求地图API
location = geo.get_location(address)
record = {
'name': name,
'level': level,
'address': address,
'phone': cleaner.extract_phone(str(item.get('phone', ''))),
'province': '湖南省',
'city': location['city'] if location else '',
'district': location['district'] if location else '',
'lng': location['lng'] if location else None,
'lat': location['lat'] if location else None
}
processed_data.append(record)
print(f" Processed: {name} ({level})")
# 5. 保存结果
df = pd.DataFrame(processed_data)
df.to_excel("hunan_spots.xlsx", index=False)
print("💾 数据已保存至 hunan_spots.xlsx")
if __name__ == "__main__":
main()
运行结果预览
json
🚀 开始采集湖南省A级景区...
[INFO] [开始下载] http://whhlyt.hunan.gov.cn/...
✅ 下载成功,大小: 45.20 KB
📄 解析出 562 条原始记录
Processed: 岳麓山-橘子洲旅游区 (5A)
Processed: 湖南省博物馆 (4A)
Processed: 张家界武陵源风景名胜区 (5A)
...
💾 数据已保存至 hunan_spots.xlsx
📊 数据存储与导出
对于这种半静态数据,我推荐使用 SQLite 作为主存储,Excel/CSV 作为导出格式。
数据库设计
sql
CREATE TABLE IF NOT EXISTS spots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- 景区名
level VARCHAR(10), -- 等级 (5A, 4A...)
province VARCHAR(50), -- 省份
city VARCHAR(50), -- 城市
district VARCHAR(50), -- 区县
address TEXT, -- 详细地址
lng REAL, -- 经度
lat REAL, -- 纬度
open_time TEXT, -- 开放时间
price TEXT, -- 门票价格
phone VARCHAR(100), -- 电话
source_url TEXT, -- 来源URL
updated_at DATE, -- 更新时间
UNIQUE(name, city) -- 唯一约束,防止重复
);
❓ 常见问题与排错(FAQ)
Q1: 附件下载下来打不开怎么办?
现象 :下载的 .xlsx 文件 Excel 打不开,提示格式错误。
原因:
- 文件其实是
.xls(旧版),但后缀写成了.xlsx。 - 或者是
.html表格直接保存为了 Excel 后缀(这是政府网站的常规操作)。 - 或者是下载到了防盗链页面(HTML)。
解决方案:
- 检查文件头(Magic Number)。
- 尝试用文本编辑器打开,如果是
<html>开头,说明没下载对。 - 如果是 HTML 表格伪装的 Excel,直接用
pd.read_html()解析。
Q2: 景区名字里有生僻字怎么办?
现象 :𡐓、𠙶 等生僻字显示为 ? 或方框。
解决方案:
- 确保所有文件读写都指定
encoding='utf-8'。 - 数据库连接字符串加上
charset=utf8mb4。 - Excel 导出时使用
xlsxwriter引擎而不是默认的openpyxl(对 unicode 支持更好)。
Q3: 地址解析不准怎么办?
现象 :"人民公园" 被解析到了几千公里外的另一个城市。
解决方案:
- 地理编码时必须带上城市名 。
geo.get_location("人民公园", city="成都市")。 - 如果地址太模糊(如"城关镇"),先用上一级行政区划(如"某某县")作为补充。
🚀 进阶优化
1. 增量更新与变更检测
景区名单不是一成不变的,每年都有新增和摘牌。
python
def check_updates(new_data_list, db_manager):
"""
对比新旧数据,生成变更报告
"""
existing_spots = db_manager.get_all_spots() # {name: level}
new_spots = []
upgraded_spots = [] # 升级
downgraded_spots = [] # 降级/摘牌
for item in new_data_list:
name = item['name']
level = item['level']
if name not in existing_spots:
new_spots.append(item)
elif existing_spots[name] != level:
# 等级变化
if level > existing_spots[name]:
upgraded_spots.append(item)
else:
downgraded_spots.append(item)
# 发送通知...
2. 空间可视化
利用采集到的经纬度,结合 Folium 生成交互式地图。
python
import folium
def generate_map(spots_df):
m = folium.Map(location=[35, 105], zoom_start=5)
for _, row in spots_df.iterrows():
if pd.notnull(row['lat']):
color = 'red' if row['level'] == '5A' else 'blue'
folium.Marker(
[row['lat'], row['lng']],
popup=f"{row['name']} ({row['level']})",
icon=folium.Icon(color=color)
).add_to(m)
m.save("china_spots_map.html")
📝 总结
构建全国景区名录采集系统,最核心的不是高深的反爬技术,而是对非结构化数据的处理能力。
我们通过:
- 多策略解析器:搞定了 HTML、Excel、PDF 多种格式。
- 地理编码增强:把模糊的地址变成了精准的坐标。
- 配置化架构:轻松扩展到全国 31 个省份。
有了这份数据,你可以做很多有趣的事:比如画出"全国 5A 景区分布图",分析"哪个省份的 4A 景区性价比最高",或者开发一个"周边游"小程序。
开始你的数据之旅吧! 🌍🎒
附录:项目目录结构推荐
json
tourism_spider/
├── config/
│ └── provinces.json # 各省配置
├── core/
│ ├── fetcher.py # 采集器
│ ├── cleaner.py # 清洗器
│ ├── geo.py # 地理编码
│ └── parsers/
│ ├── html_parser.py
│ ├── excel_parser.py
│ └── pdf_parser.py
├── data/
│ ├── raw/ # 原始文件
│ └── result/ # 结果数据
├── main.py # 入口
└── requirements.txt
🌟 文末
好啦~以上就是本期的全部内容啦!如果你在实践过程中遇到任何疑问,欢迎在评论区留言交流,我看到都会尽量回复~咱们下期见!
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦~
三连就是对我写作道路上最好的鼓励与支持! ❤️🔥
✅ 专栏持续更新中|建议收藏 + 订阅
墙裂推荐订阅专栏 👉 《Python爬虫实战》,本专栏秉承着以"入门 → 进阶 → 工程化 → 项目落地"的路线持续更新,争取让每一期内容都做到:
✅ 讲得清楚(原理)|✅ 跑得起来(代码)|✅ 用得上(场景)|✅ 扛得住(工程化)
📣 想系统提升的小伙伴 :强烈建议先订阅专栏 《Python爬虫实战》,再按目录大纲顺序学习,效率十倍上升~

✅ 互动征集
想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战?
评论区留言告诉我你的需求,我会优先安排实现(更新)哒~
⭐️ 若喜欢我,就请关注我叭~(更新不迷路)
⭐️ 若对你有用,就请点赞支持一下叭~(给我一点点动力)
⭐️ 若有疑问,就请评论留言告诉我叭~(我会补坑 & 更新迭代)
✅ 免责声明
本文爬虫思路、相关技术和代码仅用于学习参考,对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。
使用或者参考本项目即表示您已阅读并同意以下条款:
- 合法使用: 不得将本项目用于任何违法、违规或侵犯他人权益的行为,包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。
- 风险自负: 任何因使用本项目而产生的法律责任、技术风险或经济损失,由使用者自行承担,项目作者不承担任何形式的责任。
- 禁止滥用: 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。
- 使用或者参考本项目即视为同意上述条款,即 "谁使用,谁负责" 。如不同意,请立即停止使用并删除本项目。!!!
