
简介这份PDF电子书《Python网络数据挖掘实战》面向希望用Python入门网络数据挖掘的高校学生、开发者和研究人员内容从网络挖掘的基本概念延伸到内容挖掘、结构挖掘与使用挖掘并讨论个性化客户服务、网络搜索、网络跟踪和过程挖掘等应用场景。压缩包内仅含1个PDF文件大小约39.57MB便于在电脑或平板上直接查阅。全书在理论之外还铺开Python编程基础、HTML标签与常用库、网络爬虫的工作原理与合法性、数据提取与预处理以及网络意见挖掘中的数据处理、分词、特征提取和社交网络分析实践。已有94人学习下载适合作为从概念梳理到代码实现的系统读本也便于读者按章节查漏补缺、建立网络数据挖掘的知识框架。1. 先别急着写爬虫这套 Python 网络数据挖掘实战资料解决什么问题刚拿到这套 Python 网络数据挖掘实战资料的人常会先翻网页抓取那一章结果卡在环境、编码和字段设计上。它真正值钱的地方不是教你多写几行请求而是把网络内容挖掘、网络结构挖掘、网络使用挖掘三条线拧成一条可执行的数据链路先判断任务属于哪类挖掘再选 Python 工具最后落到数据提取、意见挖掘和社交网络分析。适合刚转数据岗、需要把网页数据变成表格和图结构的人也适合已有爬虫经验、想补全分析与验证环节的从业者。它不承诺一键出结果但能把每一步的输入输出、参数和排错点讲清楚。2. 网络挖掘三分法怎么落地内容、结构、使用挖掘的任务拆解2.1 三类挖掘的输入输出与选型判断网络挖掘常被误解成“会写请求就行”实际拆开看内容挖掘、结构挖掘、使用挖掘面对的数据形态完全不同。内容挖掘处理网页正文、评论、商品描述、问答文本输出通常是带字段的表格结构挖掘处理超链接、关注关系、回复关系输出是节点和边使用挖掘处理访问日志、点击流、会话序列输出偏向行为路径和频次统计。选型时先问一句最终要交付的是表格、图还是行为序列。这个问题答不清后面抓多少页都是白费。任务类型典型输入输出形态Python 侧常用工具选型判断网络内容挖掘正文、评论、标题、摘要结构化表格requests、BeautifulSoup、pandas字段能否从页面稳定定位网络结构挖掘超链接、关注、回复、引用节点表、边表networkx、pandas关系是否有方向和时间网络使用挖掘访问日志、点击流、会话路径、频次、停留时长pandas、datetime是否有 session 和时间戳选型理由不复杂内容挖掘怕字段漂移结构挖掘怕方向搞反使用挖掘怕会话切分错误。某模拟项目 X 要做评论情感汇总第一层其实是内容挖掘字段重点是评论正文、发布时间、评分要做账号影响力第一层是结构挖掘字段重点是 source、target、互动时间要做页面路径优化第一层才是使用挖掘字段重点是 session_id、url、timestamp。三条线的数据提取脚本长得像但字段表和校验规则完全不同。我一般按四步定任务先列出最终输出字段再反推需要哪些页面或日志然后确定抓取范围和分页深度最后选解析方式。输出字段里如果有“情感极性”就要提前保留原始文本和分词后文本如果有“中心性”就要提前保留边的方向和权重。不要等抓完才补字段补字段往往意味着重跑。2.2 Python 与 HTML 前置知识怎么筛读这套资料从 Python 基础、HTML 标签和常用库讲起容易读成语言教材。更有效的读法是按任务反查先知道自己要解析列表页还是详情页再回头补对应的语法和选择器。Python 侧必须掌握列表、字典、函数、文件读写、异常处理和虚拟环境HTML 侧必须掌握标签属性、CSS 选择器、表格/列表/分页结构库侧先掌握 requests、BeautifulSoup、pandas再做意见挖掘时补 jieba做社交网络分析时补 networkx。装饰器、多线程、完整爬虫框架可以后置不影响第一条链路跑通。知识块必须掌握可以后置用在什么任务Python 基础列表、字典、函数、文件读写、异常装饰器、元类所有数据提取脚本HTML 结构标签、属性、class/id、表格、列表前端框架细节字段定位与解析请求与解析超时、状态码、编码、CSS 选择器复杂反爬对抗列表页、详情页数据分析DataFrame 筛选、去重、分组大数据集群清洗与汇总文本与图分词、停用词、节点边表深度模型意见挖掘、社交网络分析HTML 只学能定位字段的部分就够了class、id、href、>import requests from bs4 import BeautifulSoup import pandas as pd BASE_URL https://example.com/list?page{page} HEADERS {User-Agent: Mozilla/5.0 (compatible; DataMiningLab/1.0)} FIELDS [title, url, publish_time, summary] def parse_page(page: int) - list[dict]: resp requests.get(BASE_URL.format(pagepage), headersHEADERS, timeout10) resp.raise_for_status() resp.encoding resp.apparent_encoding # 显式处理编码避免中文乱码 soup BeautifulSoup(resp.text, html.parser) rows [] for item in soup.select(.item): title_node item.select_one(.title a) time_node item.select_one(.time) summary_node item.select_one(.summary) rows.append({ title: title_node.get_text(stripTrue) if title_node else , url: title_node.get(href, ) if title_node else , publish_time: time_node.get_text(stripTrue) if time_node else , summary: summary_node.get_text(stripTrue) if summary_node else , }) return rows all_rows [] for p in range(1, 4): all_rows.extend(parse_page(p)) df pd.DataFrame(all_rows, columnsFIELDS) df df.drop_duplicates(subset[url]).query(title ! ) df.to_csv(mining_sample.csv, indexFalse, encodingutf-8-sig) print(df.shape)逻辑说明先请求列表页以.item为容器逐条解析标题节点同时取文本和href时间和摘要做空值兜底分页先用 1 到 3 页试跑去重按url空标题过滤掉CSV 用utf-8-sig方便表格软件直接打开。参数说明timeout10控制单请求等待时间避免脚本挂死headers里的 UA 用来标识用途不要伪装成浏览器做高频请求select选择器必须跟页面结构一致页面改版时优先改这里page范围先小后大确认字段完整率后再扩。注意先保存一份静态 HTML 调试解析逻辑再对线上页面小页数试跑不要把分页范围写死到生产脚本里也不要在字段没定清前扩抓取量。3. 数据提取层怎么搭请求、解析、清洗、入库的四个参数位3.1 请求与解析的最小闭环请求层解决“稳定拿到 HTML”解析层解决“稳定定位字段”。请求侧最容易被忽略的是超时、重试、状态码和编码没有超时一个慢请求会拖住整批任务没有重试偶发 5xx 会让数据缺口不看状态码404 页面也会被当正文解析不显式处理编码中文乱码会一路带到 CSV。解析侧则要先选解析器html.parser不依赖额外组件适合起步结构复杂、速度要求高时再换更快的解析器。CSS 选择器适合按 class 定位XPath 适合按层级和文本条件定位选一种能维护的即可。import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry from bs4 import BeautifulSoup session requests.Session() retry Retry( total3, backoff_factor0.8, status_forcelist[429, 500, 502, 503, 504], allowed_methods[GET], ) session.mount(https://, HTTPAdapter(max_retriesretry)) session.headers.update({User-Agent: Mozilla/5.0 (compatible; DataMiningLab/1.0)}) def fetch_html(url: str) - str: resp session.get(url, timeout12) resp.raise_for_status() if not resp.encoding or resp.encoding.lower() iso-8859-1: resp.encoding resp.apparent_encoding return resp.text html fetch_html(https://example.com/list?page1) soup BeautifulSoup(html, html.parser) print(soup.title.get_text(stripTrue) if soup.title else no-title)逻辑说明用Session复用连接和请求头用Retry处理偶发状态码fetch_html统一做状态码检查和编码兜底解析器先用html.parser跑通。参数说明total3表示最多重试 3 次backoff_factor0.8控制退避间隔status_forcelist只对可重试状态码生效timeout12是连接和读取的总等待上限。不要把重试开得太大否则站点响应慢时会放大压力。参数位建议做法失败时先看什么超时单请求 10 到 15 秒是否连接超时还是读取超时重试只重试 429、5xx重试次数是否打满编码显式设置或 apparent_encoding 兜底响应头与实际字节是否一致解析器起步 html.parser复杂页面再换选择器是否命中、HTML 是否截断3.2 字段规范与清洗规则数据提取不是把页面文本原样塞进 CSV。字段规范要提前定哪些字段是主键哪些允许空时间统一成什么格式文本要不要去 HTML 实体URL 要不要去追踪参数。主键不稳定后面去重和增量更新都会翻车时间格式不统一按天聚合就会错文本不去空白分词会把空格当词边界。常见做法是先落一份原始表再落一份清洗表原始表保留现场清洗表供分析用。import pandas as pd import re df pd.read_csv(mining_sample.csv) def clean_text(value: str) - str: value if pd.isna(value) else str(value) value re.sub(r[^], , value) # 去残留标签 value re.sub(r\s, , value).strip() # 压缩空白 return value df[title] df[title].map(clean_text) df[summary] df[summary].map(clean_text) df[publish_time] pd.to_datetime(df[publish_time], errorscoerce) df[url] df[url].str.split(?).str[0] # 去追踪参数保留主路径 df[content_length] df[summary].str.len() df df[df[content_length] 10].copy() df.to_csv(mining_clean.csv, indexFalse, encodingutf-8-sig) print(df[[title, publish_time, content_length]].head())逻辑说明先读原始表文本字段做去标签、压缩空白时间字段用errorscoerce把无法解析的值转成空值URL 去掉查询参数保留主路径最后按摘要长度过滤过短记录。参数说明errorscoerce适合脏数据较多的起步阶段后续可以改成严格校验content_length 10是经验阈值按业务调整utf-8-sig只影响导出编码不影响内存中的字符串。提示原始表和清洗表分开放字段名保持一致每次改清洗规则都保留一列rule_version后面排查数据差异时能省很多时间。3.3 站点规则与抓取节流抓取层要有边界先看站点使用条款和 robots 规则不抓禁止路径不绕过登录、验证码和访问控制对同一域名控制并发设置请求间隔和失败队列把请求日志记下来包括 URL、状态码、耗时、重试次数。节流不是礼貌问题是稳定性问题并发一高响应变慢重试变多数据缺口反而更大。我一般先单线程小批量跑确认字段完整率后再逐步加并发每次只改一个参数。import time import random import logging logging.basicConfig(levellogging.INFO, format%(asctime)s %(levelname)s %(message)s) def polite_get(session, url: str, min_sleep: float 1.2, max_sleep: float 2.0): time.sleep(random.uniform(min_sleep, max_sleep)) # 请求间隔加随机抖动 start time.time() resp session.get(url, timeout12) cost time.time() - start logging.info(url%s status%s cost%.2fs, url, resp.status_code, cost) if resp.status_code in (403, 429): time.sleep(5) # 遇到限流先降速再检查站点规则 resp.raise_for_status() return resp逻辑说明请求前先等待一个随机区间降低固定频率带来的压力记录 URL、状态码和耗时遇到 403 或 429 先降速再回头检查是否触碰了站点规则。参数说明min_sleep和max_sleep按站点响应调整起步可以 1 到 2 秒timeout12与前面的请求层保持一致日志级别用 INFO 就够生产环境再落文件。4. 从文本到关系意见挖掘与社交网络分析的实现路径4.1 意见挖掘的标签体系与分词参数意见挖掘不是“分个正负就完事”。先定标签体系正向、负向、中性是基本盘再按业务加方面词比如价格、质量、服务、物流。标签规则要能落地正向是明确推荐或满意表达负向是明确抱怨或不满中性是陈述事实或无法判断。不要用模糊词做标签名后面人工复核会对不上。分词参数也要先定cut_allFalse用精确模式HMM 处理未登录词自定义词典补领域词停用词表去高频虚词否定词表单独维护。标签判定规则虚构示例正向含推荐、满意、超出预期等表达“这次体验很稳会再用”负向含失望、延迟、破损等表达“等了很久包装也破了”中性只陈述事实无明显情绪“下午三点到的”方面词价格、质量、服务、物流“价格还行物流偏慢”import jieba text 价格还行物流偏慢包装有破损 stopwords {的, 了, 还, 有, 很} user_words [物流, 包装, 破损, 偏慢] for word in user_words: jieba.add_word(word) tokens [w for w in jieba.cut(text, cut_allFalse, HMMTrue) if w.strip() and w not in stopwords] print(tokens)逻辑说明用精确模式分词HMM 处理未登录词自定义词典把领域词固定成完整词停用词过滤虚词。参数说明cut_allFalse避免全模式切出过多碎片HMMTrue对未登录词更友好但领域词多时仍要加词典停用词不要一刀切否定词和程度副词必须保留。4.2 特征提取与极性判断的朴素基线特征提取先做词袋和 TF-IDF再看是否上词典法。词典法的优点是解释性强适合做第一版基线缺点是遇到反讽、双重否定和领域新词容易错。否定词窗口要单独处理否定词后面两到三个词内出现正向词极性要翻转程度副词要加权“非常满意”和“满意”不能同权。评估不要只看准确率负向样本少时准确率高但召回率会很难看混淆矩阵和 F1 一起看。positive {满意, 推荐, 稳, 快, 好} negative {失望, 破损, 慢, 差, 贵} negation {不, 没, 没有, 并不} degree {非常: 1.5, 很: 1.2, 有点: 0.7} def polarity(tokens: list[str]) - int: score 0.0 for i, token in enumerate(tokens): weight 1.0 if i 0 and tokens[i - 1] in degree: weight degree[tokens[i - 1]] if token in positive: score weight elif token in negative: score - weight if i 0 and tokens[i - 1] in negation: score * -1 # 简化否定处理生产环境用窗口 return 1 if score 0 else -1 if score 0 else 0 sample [物流, 慢, 但, 包装, 没有, 破损] print(polarity(sample))逻辑说明逐词查情感词典程度副词给权重否定词简化翻转极性。参数说明degree权重按业务调不要拍脑袋设太大否定词用窗口比逐词翻转稳尤其是“不是不满意”这种结构词典要按领域补不要直接拿通用词表硬套。这个基线适合先跑通流程再拿人工标注集做小样本评估。4.3 对称/非对称网络与连通性指标社交网络分析先把关系说清对称网络是双向关系边没有方向非对称网络是关注、回复、引用这类有方向的关系。方向搞反入度和出度的解释就全反了。节点表至少要有node_id和属性边表至少要有source、target、weight、timestamp。重复边要先聚合否则密度和中心性会被放大。连通性指标里连通分量看群体分裂密度看整体连接程度度中心性看局部活跃接近中心性看路径位置聚类系数看局部抱团。import networkx as nx import pandas as pd edges pd.DataFrame([ {source: A, target: B, weight: 3}, {source: B, target: A, weight: 2}, {source: A, target: C, weight: 1}, {source: D, target: C, weight: 5}, ]) G nx.DiGraph() for _, row in edges.iterrows(): G.add_edge(row[source], row[target], weightrow[weight]) print(density:, nx.density(G)) print(in_degree:, dict(G.in_degree(weightweight))) print(components:, list(nx.weakly_connected_components(G))) print(pagerank:, nx.pagerank(G, weightweight))逻辑说明用有向图保留关系方向边权重视为互动强度密度看整体连接入度看被指向程度弱连通分量看群体是否分裂PageRank 看节点在网络中的相对重要性。参数说明weightweight让指标按权重计算弱连通分量适合有向图整体分组强连通分量更适合看互惠关系孤立点要不要保留取决于分析目标算密度前要先说明。指标含义适用场景注意点密度实际边数占可能边数比例整体连接程度有向图和无向图分母不同入度/出度指向/发出的边权和影响力、活跃度方向不能反连通分量可互达的节点组群体分裂弱连通和强连通含义不同聚类系数邻居之间互连程度局部抱团有向图要用对应版本5. 避坑与排查五个翻车现场及修复顺序5.1 编码与选择器漂移现象昨天还能跑出中文标题今天 CSV 里全是乱码或者标题字段突然全空脚本不报错但数据没了。原因通常是响应编码没有显式处理页面改版后选择器不再命中或者页面从服务端渲染变成动态加载。解决顺序是先保存原始 HTML确认字节和响应头编码再用apparent_encoding兜底选择器不要只写一个容器选择器和字段选择器分开字段缺失时记录空值而不是直接跳过动态加载的页面先看数据是否在接口里不要硬解析空壳 HTML。resp session.get(url, timeout12) resp.raise_for_status() raw resp.content html raw.decode(resp.apparent_encoding or utf-8, errorsreplace) with open(debug_page.html, w, encodingutf-8) as f: f.write(html)逻辑说明先拿字节内容再用推断编码解码保存一份调试 HTML 供选择器复核。参数说明errorsreplace避免解码失败中断脚本调试文件只保留最近一页防止磁盘堆满编码确定后改成显式指定不要长期依赖推断。5.2 分页、去重与增量更新现象抓了十页只有前两页是新数据或者明明有二十页却只抓到十九页。原因常见于分页参数从 0 开始还是从 1 开始没确认、排序规则变化导致页间重复、主键用了会变的字段。解决是把分页起点、每页条数、排序字段写进配置去重主键优先用稳定 URL 或业务 ID不要用标题增量更新用“最后抓取时间 唯一键”做断点失败队列单独落盘下次先补失败再跑新页。问题先检查修复动作漏页起始页码、总页数解析手动翻到最后一页对照重复排序是否稳定、主键是否唯一换稳定主键落原始页号增量错时间字段时区、更新频率统一时区记录抓取批次5.3 分词、停用词与否定词现象情感判断把“不推荐”判成正向或者“物流不慢”被判成负向。原因多半是否定词被停用词表删掉、否定窗口太短、领域词被切碎。解决是把否定词和程度副词从停用词表里拿出来否定词用前后两到三个词的窗口处理领域词加自定义词典。分词后先人工看二十条样本确认切词结果再跑全量不要直接拿准确率糊弄自己。negation {不, 没, 没有, 并非} tokens [物流, 不, 慢] for i, token in enumerate(tokens): if token in positive or token in negative: window tokens[max(0, i - 2):i] if any(w in negation for w in window): print(flip:, token)逻辑说明在情感词前两个词窗口里找否定词命中则翻转极性。参数说明窗口大小按句式调整中文里“并不是很满意”需要更长窗口否定词表要按语料补不要只放“不”和“没”翻转后仍要保留原词方便人工复核。5.4 网络图方向性与孤立点现象算出某个节点入度很高但直觉上它只是发消息多或者密度很低原因是大量孤立点被算进分母。原因是有向边被当无向边、重复边没有聚合、孤立点没有按分析目标处理。解决是先明确边的方向语义重复边按 source、target 聚合权重算密度前决定是否保留孤立点并在报告里写清楚。社交网络分析里方向一错后面所有中心性都不可信。现象原因解决入度和直觉相反有向边当无向边建图时明确 DiGraph/Graph密度异常低孤立点进入分母先过滤或单独说明中心性虚高重复边未聚合按节点对聚合权重5.5 环境与依赖锁现象本机跑得好好的脚本换一台机器就报缺少模块、词典文件找不到、CSV 编码不一致。原因是依赖没有锁版本、路径用了绝对路径、词典和停用词表没有随项目走。解决是建虚拟环境导出依赖清单所有资源文件用相对路径随机种子固定入口脚本只做参数解析。换机器先跑一条最小样例确认环境和数据路径都对再跑全量。python -m venv .venv source .venv/bin/activate pip install requests beautifulsoup4 pandas jieba networkx pip freeze requirements.txt python -m pytest tests/test_parse.py -q逻辑说明虚拟环境隔离依赖依赖清单固定当前组合测试脚本先验证解析函数。参数说明requirements.txt要跟代码一起归档测试用例用本地静态 HTML不要依赖线上页面路径统一从项目根目录拼不要写死用户目录。注意换机器后先跑最小样例不要直接跑全量依赖清单和词典文件缺一个排查时间可能比写脚本还长。6. 把资料变成可复现实验一套三日验证清单与长期习惯6.1 三日验证清单拿到资料后不要从头读到尾按三天做验证更稳。第一天只跑通内容挖掘最小链路定四个字段抓三页存原始表和清洗表检查字段完整率。第二天做意见挖掘小样本抽两百条文本人工标五十条跑分词和词典基线看混淆矩阵。第三天做社交网络分析小图用一百个节点以内的模拟边表算密度、入度、连通分量确认方向没有搞反。每天只改一个参数改完记录结果。天数目标输入产出通过标准第一天跑通数据提取列表页三页原始表、清洗表标题和 URL 完整率可接受第二天跑通意见挖掘两百条文本标签表、混淆矩阵负向召回不低于基线第三天跑通网络分析模拟边表指标表、图摘要方向与指标解释一致6.2 结果校验的四个指标结果校验不要只看“跑完了”。字段完整率看解析是否稳定去重后唯一率看主键是否可靠分词后有效词比例看停用词和词典是否合适图连通分量数看关系分组是否符合直觉。下面这段校验代码可以直接接在清洗表后面先看数再看图。import pandas as pd df pd.read_csv(mining_clean.csv) print(字段完整率:, df[[title, url]].notna().mean().to_dict()) print(唯一 URL 率:, df[url].nunique() / len(df)) print(平均文本长度:, df[summary].str.len().mean()) print(时间空值率:, df[publish_time].isna().mean())逻辑说明完整率看关键字段是否缺失唯一率看主键是否重复文本长度看清洗是否过度时间空值率看解析是否稳定。参数说明notna().mean()得到的是非空比例唯一率低于预期先查分页和主键文本长度突然变短先查选择器和清洗规则。从那以后我每接一个网络数据挖掘任务都先强制走一遍三日清单先定挖掘类型再锁定字段最后跑校验指标。没有这一步后面写再多代码都像在黑匣子里猜。希望帮到你。本文还有配套的精品资源点击获取