资讯动态

Python爬虫与数据分析实战:requests到Pyecharts的完整数据管道构建

发布时间:2026/9/15 5:31:03 来源:尧图企业网站定制
简介这是一套基于 Python 爬虫与数据分析的实战项目压缩包面向计算机相关专业学生、毕业设计或课程设计者也适合想从数据采集走向可视化分析的小白进阶学习。资源共包含17个文件以 Jupyter Notebook 分析文档、CSV 数据表、ZIP 数据集和 Python 爬虫脚本为主另有 YAML 配置文件、字体、图片和 Markdown 说明压缩包整体仅7.07MB目录划分清晰方便按案例快速定位。内容覆盖多个可复现的场景泰坦尼克号生存率预测、星巴克门店数据探索、微信好友可视化、京东图书信息爬取、斗鱼直播间数据抓取以及拉勾网职位数据分析每个案例均提供可直接运行的 notebook 或脚本帮助读者理解数据清洗、特征观察、可视化呈现和结果输出。项目文档与资料齐全代码经过运行验证已有116人浏览学习既可以作为从爬虫到数据分析的完整练习也便于在现有代码上二次改造直接用于课程设计、项目演示或毕业设计参考。1. 从“项目文档.zip”到能跑通的数据管道中间只差这套拆解拿到一份标题带“python爬虫 数据分析 实战项目文档详解”的压缩包第一反应往往不是解压而是犹豫里面到底是能直接跑的完整代码还是只配了截图和思路说明的课程资料实际经验是这类包质量参差不齐但真正值钱的部分从来不是代码本身而是它能不能帮你形成一套“从请求到洞察”的完整链路。这篇文章不猜包里的内容只讲一个从业者拿到“爬虫数据分析”这个组合后会做的标准工作先设计可控的采集方案再建干净的分析环境最后用几个必须回看的指标判断项目是否真的“跑通”。第一件事是拆解依赖关系——爬虫阶段的技术选型决定数据质量数据质量直接决定后续分析能不能做而大多数人栽在第 2 章就要讲的并发设计上根本不是不会写 requests。我会把请求库、解析方案、存储结构、分析可视化到防封与排错一路讲完。你能带着这份文档独立复现一个最小闭环用 requests 与 lxml 抓取公开数据用 MySQL 保存增量结果再交给 pandas 清理并用 Pyecharts 出图。整个过程不需要分布式爬虫也不需要 GPU一台普通 Windows 或 Ubuntu 机器足够。2. 爬虫技术选型与最小闭环requests、并发设计还是 Scrapy2.1 并发设计到底哪个好先搞懂阻塞在哪热词里挂着“爬虫 并发设计 到底哪个好”这问题的答案取决于你的瓶颈是等待响应还是解析 HTML。单线程爬虫的事故现场永远长一个样time.sleep(1) 之后用 requests.get() 拉十个页面每页花 0.8 秒在等待服务器响应CPU 全程打盹一小时也跑不完一千条数据。这里的核心矛盾是 I/O 等待不是计算密集。解决思路有两条threading requests把请求丢进线程池每个线程独立阻塞在 recv 上线程切换由操作系统调度写起来最接近同步代码逻辑。Scrapy Asyncio框架内置异步引擎同一线程内用事件循环切换协程理论上吞吐量远高于线程方案但学习曲线陡峭自定义配置项多。针对“爬虫数据分析”的项目包我一般建议优先做线程池方案。理由是分析侧还要花大量时间在数据清洗上爬虫只是数据获取工具不值得为它引入整套 Scrapy 中间件体系。若目标是每小时采集十万级页面且需要调度扩展才切换到 Scrapy 的 CrawlSpider 分布式布隆过滤器。2.2 requests 库的最小请求模板与参数说明先将 requests 爬虫的核心骨架写出来这段代码作为所有采集任务的起点直接复用即可。import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session requests.Session() # 重试策略连接失败或返回5xx时最多重试3次每次间隔1秒 retry Retry( total3, backoff_factor1, status_forcelist[500, 502, 503, 504], ) adapter HTTPAdapter(max_retriesretry) session.mount(http://, adapter) session.mount(https://, adapter) headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept-Language: zh-CN,zh;q0.9, } def fetch(url: str, timeout: int 10) - requests.Response: resp session.get(url, headersheaders, timeouttimeout) resp.raise_for_status() return resp参数说明与踩坑点timeout 必须给数值不能省略。缺省时 requests 会无限等待线程池方案下会造成线程泄漏。Retry 里的 status_forcelist 必须包含 500/502/503/504否则遇到服务器临时故障直接抛异常前功尽弃。headers 中 User-Agent 必须补全浏览器内核标识知乎和豆瓣的默认反爬检查会直接拦截缺失 UA 的请求。Session 复用 TCP 连接比逐个 requests.get() 快 30%连接池对象在 Session 内部维护不要每轮新建。2.3 lxml 与 XPath 解析比正则健壮得多的字段抽取方案数据解析采用 lxml XPath 而不是正则是爬虫实战项目的分水岭。正则匹配无结构文本极其脆弱一份 HTML 换一行空白或属性顺序调整匹配逻辑就崩掉XPath 按 DOM 层级定位能容忍大部分细微格式变化。from lxml import html def parse_listing(page_text: str): doc html.fromstring(page_text) items doc.xpath(//div[contains(class, list-item)]) for item in items: title item.xpath(.//h3/text())[0].strip() price item.xpath(.//span[contains(class, price)]/text()) price price[0].strip() if price else None yield {title: title, price: price}XPath 地图说明//div[contains(class, list-item)]匹配所有 class 属性含 list-item 的 div 节点内层.//h3的圆点表示从当前 item 节点向下寻找避免全文档误匹配。多级标签下 text() 可能返回空列表所以代码里先取 [0] 再赋 None 兜底防止出现 IndexError 中断整个采集流程。如果目标页面数据是 JSON 接口而非完整 HTML则跳过解析直接用 response.json() 提取字段。实战里越来越常见的方式是数据埋点在 XHR 响应中直接抓接口比解析页面稳定得多。2.4 存储入库CSV 临时落盘还是 MySQL 增量更新采集脚本跑完不能直接关掉数据必须先落盘。项目文档里的资料通常是 CSV 或 SQL 转储而真实工程里我倾向混合存储策略中间态原始响应存 JSONL每行一条记录方便失败重跑时做断点续采。清洗后的结构化数据存 MySQL InnoDB 表主键必须包含来源 ID 或 URL 的哈希值用于去重。建表语句如下CREATE TABLE IF NOT EXISTS listing ( id VARCHAR(64) PRIMARY KEY, title VARCHAR(255) NOT NULL, price DECIMAL(10,2), url VARCHAR(1024), crawled_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY idx_url_hash (url(255)) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段注释与用途id 字段存放 URL 的 md5 或 sha1 前缀天然去重重复推送同一 URL 时直接报主键冲突程序捕获后跳过即可。DECIMAL(10,2) 用于价格字段不要用 FLOAT/DOUBLE浮点精度在聚合统计时会造成对不上的账目。crawled_at 记录采集时间后续分析任务需要按时间窗口过滤数据时就不必解析字段外的时间信息。utf8mb4 字符集支持表情符号大众点评等页面中出现 emoji 时不会写入报错。采集侧与存储侧的连接池合并后写入采用 executemany 批量插入不要一条条 commit。批量提交能减少事务日志刷盘次数实测在 10 万行级别能节省 70% 的写入时间。3. 数据分析与可视化环境pandas 清洗、聚合和 Pyecharts 出图3.1 数据质量检查三步缺失值、去重、类型转换爬到的数据永远比预期脏。即使采集阶段已经做了字段抽取仍会存在空标题、重复行、价格字段带“元/月”等噪声。进入分析前先跑一遍数据体检脚本。import pandas as pd df pd.read_csv(listing.csv, encodingutf-8-sig) # 1. 去重基于业务主键判断 df df.drop_duplicates(subset[title, price], keepfirst) # 2. 缺失值按列查看比例 miss df.isna().sum() print(miss[miss 0]) # 3. 价格字段清洗去除货币符号、英文逗号、单位 df[price_num] ( df[price] .astype(str) .str.replace(r[¥,元/月], , regexTrue) .astype(float) ) # 4. 异常值过滤低于10或高于100000的价格视为解析错误 df df[(df[price_num] 10) (df[price_num] 100000)]顺序有讲究先去掉完全重复的行再做缺失值统计否则重复行会污染缺失率类型转换放最后因为正则替换只对字符串有效。encodingutf-8-sig是 Windows 环境下的保命参数Excel 导出的 CSV 常带 BOM 头不指定这个编码首列列名会变成\ufeff字段。3.2 特征聚合GroupBy 与时间窗口的正确姿势爬虫数据带有时间戳适合按小时或天聚合观察变化趋势。以房价爬虫为例分析目标可能是“各区域近 30 天挂牌价走势”核心操作是日期截断与分组中位数聚合。import pandas as pd df[crawled_at] pd.to_datetime(df[crawled_at]) df[date] df[crawled_at].dt.date agg ( df.groupby([region, date])[price_num] .median() .reset_index() ) # 计算每个区域环比变化率 agg[prev_median] agg.groupby(region)[price_num].shift(1) agg[mom] (agg[price_num] - agg[prev_median]) / agg[prev_median]GroupBy 之后必须 reset_index否则 date 和 region 被塞进 MultiIndex后续 merge/plot 都会踩坑。shift(1) 是环比计算的标准口子它取前一行同组的数值做除法若某区域某日没有采集数据shift 结果为 NaN直接体现为环比缺失而不是错误结果。还有一个高频坑.dt.date是把时间降到日期层级用于画横轴分类但 GroupBy 对 datetime 分组时默认按时间戳精度分不截断会导致每小时一条记录图表横坐标密集到无法阅读。这点正是热词里“python画图横坐标太密集”的主要成因。3.3 Pyecharts 可视化K线、折线与地图组件的接入分析完成后必须可视化才能交付。Pyecharts 是对 Apache ECharts 的 Python 封装输出 HTML 可自由缩放图表交互比 Matplotlib 更适合放到数据报告里。最小示例如下from pyecharts.charts import Line from pyecharts import options as opts def render_trend(agg_df, region_name: str): sub agg_df[agg_df[region] region_name] line ( Line() .add_xaxis(sub[date].astype(str).tolist()) .add_yaxis( series_name挂牌中位数价格, y_axissub[price_num].round(2).tolist(), is_smoothTrue, markpoint_optsopts.MarkPointOpts( data[opts.MarkPointItem(type_max)] ), ) .set_global_opts( title_optsopts.TitleOpts(titlef{region_name}价格走势), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate45)), ) ) line.render(f{region_name}_trend.html)图表参数里最容易出问题的是日期轴。sub[date].astype(str)这一步必须做ECharts 的类目轴默认按传入顺序显示而 datetime 对象序列化后不易控制格式转字符串后还能保证横轴顺序与 df 排序一致。rotate45 是横坐标太密集时的通用解法配合 is_smoothTrue 让折线更易读。对于空间维度的展示Pyecharts 提供 Map 地图组件只需构造 [省/市名, 数值] 列表传进去地理编码函数会直接匹配国内标准行政区划不需要自己维护经纬度映射表。这一块非常适合“爬虫数据分析”项目做最终汇报页。3.4 类 ChatGPT 分析链条为什么 AI 适合辅助清洗而非抓取热词里有“AI是爬虫技术的更深层次运用吗”这里给出个人技术判断AI 更适合辅助数据解释而不是替代请求与解析。原因是爬虫获取数据的本质是确定性的网络 I/O 行为大模型无法解决登录态、频率限制和 JS 渲染这类工程问题但拿到清理后的表格后用 LLM 描述列名和样例值它能快速生成 pandas 聚合代码或 SQL 查询语句尤其擅长把“想表达什么业务问题”转换成聚合指标。常见做法是把清洗后的 CSV 头几行贴给一个带代码执行能力的分析工具让它输出探索性统计图表这一步骤能节省人工写透视表的 80% 时间。用好 LLM 的边界是给出明确的数据字典和业务目标而不是复述“给我分析一下这个 CSV”这种无约束请求。4. IP 代理与反爬检测并发频率控制的五个必调参数4.1 反爬识别维度与应对策略很多项目文档的“反爬”部分只写了 headers 伪装但真实防护会检查以下六个维度请求频率分布同一 session 的请求间隔过于规律直接判定为爬虫。浏览事件指纹鼠标轨迹、页面聚焦、滚动行为缺失。请求头字段顺序浏览器发出 Accept-Encoding 与 Sec-Fetch-* 的组合关系。TLS 指纹requests 库默认的 TLS 握手特征与 Chrome 差异明显。前端埋点 Token页面 JS 动态生成请求签名参数。IP 维度同 IP 并发量、ASN 分布、数据中心 IP 黑名单。应对前四项的常规手段是随机 User-Agent 池、随机化延时、补全 Sec-Fetch 头以及使用 curl_cffi 替代 requests 模拟浏览器 TLS 指纹。应对 IP 封禁则引入代理池这是下一节重点。4.2 免费代理池配置与质量验证方法不要贪便宜直接用免费接口返回的 IP连通率和速度都无法保障。一个稳的做法是自建代理池以下是采集代理、验证匿名度、写入可用队列的核心环节import requests from concurrent.futures import ThreadPoolExecutor test_url https://httpbin.org/ip proxy_candidates [...] # 从免费代理源接口获取 def verify(proxy: str): proxies {http: fhttp://{proxy}, https: fhttp://{proxy}} try: resp requests.get(test_url, proxiesproxies, timeout5) if resp.status_code 200: return proxy except Exception: return None with ThreadPoolExecutor(max_workers20) as pool: valid list(filter(None, pool.map(verify, proxy_candidates)))关键点是验证目标必须选 httpbin.org/ip它会回显请求的真实出口 IP。只有响应的 JSON 与代理服务器声称的地域匹配才说明请求确实走了代理且未暴露本机 IP。若响应值是你自己的家宽 IP说明该代理是透明代理禁用。4.3 动态切换代理与限速设计拿到可用代理后为每个请求动态轮换代理同时加随机延时避免引发频率特征聚类。import time import random proxy_pool valid # 上一节验证通过的列表 proxy_index 0 def get_proxy(): global proxy_index proxy_index (proxy_index 1) % len(proxy_pool) return {http: fhttp://{proxy_pool[proxy_index]}, https: fhttp://{proxy_pool[proxy_index]}} def fetch_with_proxy(url): resp requests.get(url, headersheaders, proxiesget_proxy(), timeout10) time.sleep(random.uniform(1.2, 3.5)) return resp参数设计逻辑时间上下界 1.2~3.5 秒避免固定 sleep(2) 造成准周期特征下界必须大于单请求耗时方差否则线程池中饥饿请求堆积。代理池轮换是顺序取模不随机抽样随机抽样会导致同一代理可能连续命中两次触发连接频率惩罚。失败重试时禁止直接重发原请求因为高概率原代理已失效应重新取一个新代理。这种“请求频率控制方案”唯一缺点是效率低于异步并发但一个中型项目 5000 条数据在小时代内完成且账号安全等级明显高于盲目高并发。5. 分布式爬虫与规模化什么时候上消息队列和 Scrapy 集群5.1 单机瓶颈评估CPU、内存还是带宽如果你的采集目标扩大单机跑不动了不要直接上分布式框架。先用压测确认瓶颈到底在哪一环用 py-spy dump 查看进程占用状态若大量时间在 recv说明带宽未跑满但 I/O 等待高并发线程数不足。查看内存占用解析大 HTML 时 lxml 树占内存约是文本大小 5~10 倍单机内存耗尽才会导致 swap 抖动。若 CPU 一直 100% 但请求速率毫无提升瓶颈在解析阶段需要换更快的 lxml 或取消 html 清洗。只有带宽与 CPU 都无明显压力但队尾延迟持续上涨才值得引入多机分布式架构。5.2 基于 Redis 与 Scrapy 的最小分布式设计通用架构是 Scrapy 作为抓取器Redis 作为任务队列与请求调度中心。Scrapy-Redis 通过重写调度器让多台机器消费同一个 Redis 中的请求Request队列指纹集合存储在 Redis Set 中做去重。# settings.py 关键配置 SCHEDULER scrapy_redis.scheduler.Scheduler DUPEFILTER_CLASS scrapy_redis.dupefilter.RFPDupeFilter REDIS_URL redis://redis-node:6379/0 SCHEDULER_PERSIST True参数含义与启动顺序SCHEDULER_PERSIST 设为 True爬虫关闭后 Redis 中未消费请求不清空下次启动自动续跑。但此模式下若代码更新旧请求与指纹可能永远无法刷新需要主动清空键开发期常误配导致数据重复或缺失。Redis 键名的前缀默认是 spidername:requests 与 spidername:dupefilter运维时需要按 spider 区分监控和清空。5.3 增量采集与断点续爬的双保险方案分布式架构解决了横向扩容但真正让项目长期稳定的是增量去重机制。除 Redis 指纹外我在数据入库前会额外查一次表主键def is_duplicate(url_hash: str, cursor) - bool: sql SELECT 1 FROM listing WHERE id %s LIMIT 1 cursor.execute(sql, (url_hash,)) return cursor.fetchone() is not NoneRedis 指纹去重会因宕机丢数据数据库主键去重是最终兜底。两层去重并行采集层跳过抓取入库层过滤脏数据任何一层误判都不会造成线上数据重复。6. 校验结果与控制风险用数据完整性验证爬虫闭环成功6.1 三条必须每天看的巡检指标架构搭完了真正决定项目成败的是“有没有跑偏”。我长期用三条指标校验请求成功率 状态码 200 的次数 / 总请求次数低于 98% 需要检查是否触发了验证码或 IP 封禁。入库有效率 成功入库的行数 / 解析成功的记录数若长期低于 90%多半是抽取逻辑与页面结构不匹配。字段缺失率 含空关键字段的记录数 / 总记录数比如价格字段缺失超过 5%需要关注页面是否有懒加载。# 统计日志里的状态码分布 grep -o status: [0-9]* spider.log | sort | uniq -c | sort -rn # 查看 SQL 误删与写入情况 mysql -u root -p analytics -e SELECT date(crawled_at), count(*) FROM listing GROUP BY date(crawled_at);命令只看不处理适合放在定时任务里。一旦发现采集量为 0 的日期段立刻回滚到最近快照数据而不是重新抓全量因为原始网页可能早已改版。6.2 验证码与人机校验的处理边界验证码出现时不要第一时间接入打码平台或 OCR 模型先反查你的请求频率与 IP 质量。大多数中小站点的目的是限速而非彻底封禁把平均请求间隔翻倍并更换代理池后验证码出现概率会大幅下降。若目标站点确实有滑块或点选工程造价会呈指数级上升此时考虑调整采集范围或寻找官方 API不要盲目对抗。6.3 工程中最省心的技巧把分析结果输出为可校验的断言最后分享一个压箱底的经验给数据管道每个阶段加断言不是给测试工程师看而是给未来接手的人一条可执行的验收线assert len(df) 0, 采集结果为空回查解析逻辑 assert df[url].nunique() df[url].count(), 存在 URL 重复检查去重规则 assert df[price_num].between(0, 100000).all(), 价格字段含异常区间数据这三个断言分别对应空数据、重复数据和脏数据三类最常见的线上事故。把它们写入 CI 流水线每周跑一次比人工盯日志高效得多。当断言失败时报文足够具体回溯问题链路的时间能从两小时降到十分钟。这也是为什么我反复强调爬虫项目的最终交付物不是能跑通的脚本而是一套可校验、可重放、可解释的数据管道。学习资料再多不如把这套闭环在本地完整走一遍你才能说真正“会了”爬虫加数据分析。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价