Python爬虫技术
前言「爬虫技术」听起来像一个独立学科拆开看其实就是三件事发出 HTTP 请求拿到响应、从响应里抽出结构化数据、把数据存下来并决定下一次抓哪里。Python 之所以成了爬虫的主流语言不是语言本身有什么魔法而是标准库把这三件事的零件都备齐了urllib.request负责发请求urllib.parse负责拼 URL 与编码参数html.parser负责解析 HTMLjson与csv负责落盘urllib.robotparser甚至帮你读 robots.txt。第三方库requests、BeautifulSoup、lxml、Scrapy、aiohttp 等只是把这些零件包装得更顺手。最常见的误解有两个。第一个是「爬虫就是写个for循环只要不被封 IP 就行」——把工程问题当成了对抗问题。实际上大多数抓取失败的原因不是被封而是编码没处理对、翻页逻辑写错、把None当成字符串拼接。第二个是「数据在网页上显示出来就说明可以抓」——法律与服务条款不这么认为。动手前先看目标站的 robots.txt 与使用条款遵守它给对方留出带宽这是本文反复强调的前提。本文讲的是通用技术骨架示例只用 Python 标准库让你在没装任何第三方包的环境里也能把流程跑通。所有代码以 Python 3 为基准Python 2.7 已于 2020 年 1 月 1 日停止维护老教程里的print语句、dict.iteritems()、xrange现在都跑不起来本文一律用 Python 3 写法。一、请求层一次 HTTP GET 到底发生了什么用urllib.request发一个请求最短的写法是urllib.request.urlopen(url)。它的签名是urlopen(url, dataNone, [timeout, ]*, contextNone)url既可以是字符串也可以是一个Request对象data不为None时请求方法变为 POST且必须是已经编码好的字节串timeout是位置参数单位秒。只要你不是只抓一次给自己看就应该用Request对象因为要设置 User-Agent用户代理。Request的签名是Request(url, dataNone, headers{}, origin_req_hostNone, unverifiableFalse, methodNone)headers里的每一项都等价于调用一次add_header(key, val)。设置 UA 的目的不是伪装成浏览器去骗过服务器而是让服务器能从日志里认出你、找得到你、并决定是否给你开白名单。urllib 若不设置默认会把自己标成Python-urllib/3.x这样的字符串。拿到响应后几个高频属性要认清resp.status是整数状态码resp.headers是http.client.HTTPMessage对象可以像字典一样.get(Content-Type)取头resp.read()返回字节串而不是字符串。字节串要解码成str才能做文本处理而解码用的字符集应该从响应头里的Content-Type取而不是想当然写utf-8。二、编码层乱码的根源「爬下来的中文是乱码」几乎总是同一个原因把字节串按错误的字符集解码。正确做法是从Content-Type头里读 charset读不到再回退到utf-8。HTTPMessage继承自email.message.Message提供了get_content_charset(failobjNone)方法专门干这件事。另一个容易忽略的点是响应可能是压缩的。urllib默认不会发送Accept-Encoding头所以服务器通常不压缩但如果你手动加了Accept-Encoding: gzip就必须自己用gzip.decompress()解压resp.read()的结果否则拿到的是二进制乱码。官方文档给出的就是这个模式先看Content-Encoding是不是gzip是则解压。三、解析层标准库能做到什么程度html.parser.HTMLParser是一个基于事件的解析器你继承它重写handle_starttag(tag, attrs)、handle_endtag(tag)、handle_data(data)等方法然后调用feed(text)把文档喂进去最后close()收尾。attrs是「(名字, 值) 二元组」组成的列表注意是列表不是字典同一个属性理论上可以出现多次。它的定位要摆正HTMLParser只做词法层面的切分不做容错修复官方文档明确说它不检查结束标签是否与开始标签匹配。所以拿它写「某类新闻页正文抽取」可行拿它当通用浏览器级 DOM 解析器会失望。要更方便的选择器语法才轮到第三方库出场——但具体 API 请以各库官方文档为准本文不给出记不准的调用。环节标准库模块职责发请求urllib.request构造 Request、发出去、拿响应拼 URL / 编码参数urllib.parseurlencode、quote、urljoin读 robots.txturllib.robotparserRobotFileParser判断某 URL 能不能抓管理 Cookiehttp.cookiejarHTTPCookieProcessor维持会话解析 HTMLhtml.parser事件式解析提取数据解压gzip处理 gzip 压缩的响应体落盘json、csv结构化存储四、合规层先问能不能抓再问怎么抓urllib.robotparser.RobotFileParser(url)是标准库里的 robots.txt 解析器。用法是set_url(robots_url)设定地址read()抓取并解析然后can_fetch(useragent, url)返回布尔值。它还有crawl_delay(useragent)返回 Crawl-delay 的秒数或None和site_maps()等方法。有一个容易搞错的细节服务器上根本没有 robots.txt 文件和服务器拒绝提供 robots.txt是两回事。标准库内部的read()已经按 RFC 9309 区分了这些情况——4xx401、403 除外表示「没有规则」结果是允许访问一切401、403 表示「整站禁止」5xx 表示「服务器出错」结果是必须假定完全禁止。真正会让read()抛异常的是网络层错误你的代码遇到它时按保守策略当作「不允许」是稳妥的。此外无论 robots.txt 怎么写都应该在两次请求之间留出间隔time.sleep并且不要用能瞬间打满对方带宽的并发去压一个小站。实战一个纯标准库的最小爬虫下面这个例子抓的是quotes.toscrape.com——它是专门为练习爬虫搭建的站点页面结构稳定且明确用于教学比拿真实商业网站开刀合适得多。# 适用于 Python 3.8import gzipimport timeimport urllib.parseimport urllib.requestimport urllib.robotparserfrom html.parser import HTMLParserUA stdlib-tech-demo/0.1 (contact: techexample.com)DELAY 1.0 # 两次请求之间的间隔秒class QuoteTextExtractor(HTMLParser):从列表页里抽出每条名言的正文。def __init__(self):super().__init__()self._in_quote Falseself._depth 0 # 卡片内 div 的嵌套深度self._in_text Falseself._buf []self.quotes []def handle_starttag(self, tag, attrs):classes dict(attrs).get(class, ).split()if tag div:if not self._in_quote and quote in classes:self._in_quote Trueself._depth 1elif self._in_quote:self._depth 1elif tag span and text in classes and self._in_quote:self._in_text Trueself._buf []def handle_data(self, data):if self._in_text:self._buf.append(data)def handle_endtag(self, tag):if tag span and self._in_text:self._in_text Falseself.quotes.append(.join(self._buf).strip())elif tag div and self._in_quote:self._depth - 1if self._depth 0:self._in_quote Falsedef fetch(url):req urllib.request.Request(url, headers{User-Agent: UA})with urllib.request.urlopen(req, timeout15) as resp:raw resp.read()if resp.headers.get(Content-Encoding) gzip:raw gzip.decompress(raw)charset resp.headers.get_content_charset() or utf-8return raw.decode(charset, errorsreplace)def robots_allow(url, user_agent):parts urllib.parse.urlsplit(url)robots_url urllib.parse.urlunsplit((parts.scheme, parts.netloc, /robots.txt, , ))parser urllib.robotparser.RobotFileParser()parser.set_url(robots_url)try:parser.read()except Exception:return False # 保守策略读不到就当不允许稍后重试return parser.can_fetch(user_agent, url)def main():index https://quotes.toscrape.com/if not robots_allow(index, UA):print(robots.txt 不允许抓取退出)returnhtml fetch(index)parser QuoteTextExtractor()parser.feed(html)parser.close()for i, quote in enumerate(parser.quotes[:3], 1):print(i, quote[:40])time.sleep(DELAY) # 下一次请求前先等一会儿if __name__ __main__:main()这段代码把前面四层都串了一遍先问 robots 能不能抓再发请求按 charset 解码用事件解析器抽数据最后 sleep 限速。它没有翻页、没有并发、没有存储因为那些是后续要补的工程细节这里只要保证骨架正确。常见坑点1. 把resp.read()的返回值直接当字符串用❌html resp.read(); if 关键词 in html:—— 字节串里不能直接和str比较要么TypeError要么判断永远为假。 ✅html resp.read().decode(utf-8)或者按Content-Type里的 charset 解码。2. 忽略Content-Encoding直接 decode❌ 手动加了Accept-Encoding: gzip然后对resp.read()直接 decode得到一屏乱码。 ✅ 先判断resp.headers.get(Content-Encoding) gzip是则gzip.decompress()再解码。3.HTMLParser.attrs当字典用❌self.attrs[class]—— 它其实是「(名字, 值) 元组」的列表下标是整数TypeError。 ✅attrs dict(attrs)之后再.get(class, )注意一个属性名可能重复出现。4. 忘了调用feed()之后还要close()❌ 只parser.feed(html)就取结果 —— 文档末尾若有未闭合的结构数据还缓冲在内部没吐出来。 ✅parser.feed(html)之后补一句parser.close()。5.time.sleep写成了sleep❌sleep(1)——sleep不在内置命名空间里直接NameError。 ✅import time后写time.sleep(1)或from time import sleep再sleep(1)。6. 抓不到 robots.txt 就默认「随便抓」❌except Exception: pass之后继续猛抓目标站。 ✅ 取不到时按保守策略暂停并在日志里记下来下次重试成功再继续。7. 用 Python 2 的写法解码❌print html、for k, v in d.iteritems()—— Python 2.7 已于 2020 年 1 月 1 日停止维护print语句、iteritems、xrange在 Python 3 里全部不可用。 ✅print(html)、d.items()、range(...)。总结你要做的事标准库方案关键点发请求urllib.request.urlopen/Request设 UA、设 timeout编码参数urllib.parse.urlencode/quotedata必须是 bytes判断能否抓urllib.robotparser.RobotFileParser先set_url再read再can_fetch解析 HTMLhtml.parser.HTMLParser事件式不修复标签处理乱码get_content_charset()回退utf-8限速time.sleep(seconds, /)两次请求之间留间隔落盘json/csv文本文件记得指定encoding爬虫技术的地基就是「请求—解析—存储」这三块标准库已经把零件给齐把每一块的边界和错误处理弄清楚比急着上手第三方框架更划算。最后一句仍然是老话先读目标站的 robots.txt 与条款再动手写代码。

相关新闻

OpenLayers v7.4.0 UMD离线环境搭建与地图渲染排障指南

OpenLayers v7.4.0 UMD离线环境搭建与地图渲染排障指南

简介:本资源为 OpenLayers 地图开发必备的前端基础文件包,面向 WebGIS 初学者、前端开发者及地理信息相关课程学习者,解决快速集成开源地图能力时缺少核心依赖的问题。压缩包共 3 个文件(152KB),含核心 Jav…

2026/10/17 15:15:52 阅读更多 →
AI助手Skill技能包实战:将通用大模型调教成专业分析师

AI助手Skill技能包实战:将通用大模型调教成专业分析师

前阵子我把一个叫"小龙虾"的内部AI助手调教了一通,结果它从"什么都聊得来但什么都落不了地"的通用聊天对象,变成了一个能拆指标、查数据、出结论的分析师。整个过程没有改模型、没有换底座,只是给它加了几个 Skill——也…

2026/10/17 15:15:52 阅读更多 →
AI辅助学术专著写作:从结构化生成到质量把关

AI辅助学术专著写作:从结构化生成到质量把关

1. 学术专著写作的三大痛点:AI工具到底解决了哪一环很多人以为,写完博士毕业论文就能顺手攒出一本学术专著。真正动笔之后才会发现,这完全是两码事。论文是回答一个具体问题,专著是构建一个完整的知识体系;论文的读者是…

2026/10/17 15:15:52 阅读更多 →

最新新闻

Vim+GCC+库文件:打通Linux开发工具链的完整闭环

Vim+GCC+库文件:打通Linux开发工具链的完整闭环

我见过太多刚切到 Linux 的开发者,第一周就被劝退。倒不是 C 语言难,而是卡在了工作流上:在终端里不知道怎么快速改代码,写完程序不知道怎么编译,编译完了遇到各种链接报错又一头雾水。说白了,就是 Vim 操作…

2026/10/17 16:14:27 阅读更多 →
大漠插件7.2213 + Python:DmHelper注册调用与桌面自动化避坑指南

大漠插件7.2213 + Python:DmHelper注册调用与桌面自动化避坑指南

简介:面向大漠插件7.2213的Python注册示例包,内含作者自制的DmHelper脚本,用于演示如何通过Python语言调用大漠插件接口,完成注册、激活以及基本功能调用。大漠插件在界面自动化、软件测试、网页数据抓取等日常开发场景中应用广泛…

2026/10/17 16:14:27 阅读更多 →
5 分钟上手 North-Micro-Vision-Instruct-bf16:在 Apple Silicon 上本地跑通图像描述的完整指南

5 分钟上手 North-Micro-Vision-Instruct-bf16:在 Apple Silicon 上本地跑通图像描述的完整指南

【免费下载链接】North-Micro-Vision-Instruct-bf16 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/North-Micro-Vision-Instruct-bf16 点击查看 免费下载 North-Micro-Vision-Instruct-bf16 是一个专为 Apple Silicon(M 系列芯片&#x…

2026/10/17 16:14:27 阅读更多 →
鸿蒙下Flutter测试框架反射装载适配与规模化分发

鸿蒙下Flutter测试框架反射装载适配与规模化分发

test_reflective_loader 这个名字,很多 Flutter 开发者可能只在跑测试时瞥见过一眼,但真正能说清它底层在干嘛的人不多。这次我们团队在把一套针对鸿蒙 HarmonyOS 的 Flutter 测试基建落地时,在这个组件上扎扎实实折腾了几周,踩了…

2026/10/17 16:14:27 阅读更多 →
XERJ零配置自动索引教程:一条命令让PDF、CSV、SQLite和日志全部可搜索

XERJ零配置自动索引教程:一条命令让PDF、CSV、SQLite和日志全部可搜索

XERJ零配置自动索引教程:一条命令让PDF、CSV、SQLite和日志全部可搜索 【免费下载链接】xerj XERJ is the new way for AI to search data. Its autoindex capability activates agents to know your data without the token waste of grep and sed. One command in…

2026/10/17 16:14:27 阅读更多 →
Qt飞机大战飞机类设计:QGraphicsScene、状态机与碰撞检测

Qt飞机大战飞机类设计:QGraphicsScene、状态机与碰撞检测

1. 飞机类挂在 QGraphics 场景里,是我试出来的最优解1.1 一开始我也用过 QWidget 硬拼飞机大战在 Qt 里算一个很经典的练手项目,但大多数教程会把重点放在"怎么把窗口搭出来""怎么加背景图",真到自己动手写飞机类的时候&…

2026/10/17 16:13:26 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →