尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python网络爬虫实战:抓包、解析、反爬与IP代理防封策略详解

Python网络爬虫实战:抓包、解析、反爬与IP代理防封策略详解 Python 网络爬虫全套实战抓包请求、数据解析、反爬应对、IP 代理与防封策略详解这次我们直接说结论Python 网络爬虫的完整技术栈不外乎五件事——抓包请求怎么发、响应数据怎么解析、常见反爬机制怎么识别、IP 代理怎么用、批量抓取怎么防封。把这五件事拆开练熟再复杂的爬虫项目也能拆成模块逐个击破。这篇文章不是零散的知识点罗列而是一条从入门到实战的完整学习路径。内容覆盖 Requests 请求构造、Fiddler/Charles 抓包、BeautifulSoup 与 XPath 数据解析、常见反爬机制分析、IP 代理池搭建、请求频率控制、断点续爬与失败重试最后用一个商品评论采集项目把这些能力串起来。适合哪种读者刚接触爬虫、停留在“复制别人代码但改不动”阶段的初学者以及已经有基础、想系统补齐抓包和反爬应对能力的开发者。文章里的代码都按可直接运行的标准写环境用的也是常规 Python 3.8 配置普通电脑即可完成验证。1. 核心能力速览先给一张整体技术清单方便你对照自己的缺口。能力项说明技术主线抓包请求 → 数据解析 → 反爬识别 → 代理池 → 防封策略 → 实战项目主要语言Python 3.8依赖 requests、lxml、beautifulsoup4、pandas抓包工具浏览器开发者工具F12、Fiddler Classic、Charles数据解析方式BeautifulSoup、lxml 的 XPath、re 正则、JSON 自动解析反爬应对User-Agent 轮换、请求头补全、Cookie 处理、JS 渲染页面识别、验证码策略判断IP 代理免费代理源采集、requests 代理参数、代理池可用性检测防封思路随机延迟、请求限速、失败重试、断点续爬、任务日志适合场景公开数据采集、舆情监控、价格对比、市场调研、学术研究合规边界仅限合法授权、公开数据、测试环境使用禁止绕过平台安全机制盗取数据从材料可以确定这套内容围绕“零基础到实战”组织覆盖面广但每块都能单独验证。显存、GPU 这类概念不涉及爬虫主要吃网络带宽和内存普通开发机即可。2. 适用场景与使用边界爬虫能力强但不代表能乱用。先说清楚适合做什么、不适合做什么。适合的场景采集公开商品信息做比价分析。抓取公开新闻、公告做舆情监控和数据分析。获取学术论文元数据、开源社区项目信息。对自己有权限的数据源做自动化备份。在测试环境练习爬虫技术数据仅用于学习。不适合的场景采集需要登录才能查看的非公开数据且未经授权。绕过平台的安全校验、验证码或访问控制策略。高频请求导致目标服务器压力过大。将抓取的数据用于商业用途而未经数据方授权。涉及个人隐私信息手机号、身份证、地址等的采集和存储。这里有一条必须强调的边界学习“识别反爬机制”的目的是理解技术原理、合理规避误封而不是攻破平台安全防线。做任何爬虫项目前先过一遍 robots.txt先确认数据是否公开先评估请求频率是否会造成服务器负担。合规和授权永远排在技术前面。3. 环境准备与前置条件开始写代码之前先把环境配置好。整套教程不需要 GPU不需要高内存服务器一台普通电脑就行。3.1 安装 Python推荐 Python 3.8 以上版本。下载安装时勾选“Add Python to PATH”避免命令行找不到 python 命令。python --version输出类似Python 3.10.11即表示安装成功。3.2 创建虚拟环境虚拟环境可以把项目依赖隔离避免多个项目之间的包版本冲突。mkdir python-spider-course cd python-spider-course python -m venv venvWindows 激活方式venv\Scripts\activatemacOS / Linux 激活方式source venv/bin/activate激活后命令行前面会出现(venv)标识。3.3 安装核心依赖pip install requests beautifulsoup4 lxml pandas说明一下每个库的用途requests发 HTTP 请求获取网页响应。beautifulsoup4解析 HTML 文档提供 find/find_all 等便捷方法。lxml解析引擎配合 BeautifulSoup 或直接使用 XPath 定位节点。pandas把清洗后的数据整理成表格导出 CSV 和 Excel。3.4 抓包工具准备抓包工具推荐两个浏览器自带开发者工具F12日常调试最方便Network 面板直接看请求和响应。Fiddler Classic适合分析移动端 App 请求需要配置 HTTPS 证书。Fiddler 的配置步骤下载安装 Fiddler Classic。打开菜单 Tools → Options → HTTPS。勾选 Decrypt HTTPS traffic。按提示安装根证书。设置移动端代理为本机 IP 加 8888 端口即可抓取手机上的 HTTPS 请求。需要说明的是抓包工具只是观察和分析 HTTP 流量用于理解接口结构和参数来源。不要用它去拦截、篡改不属于自己权限范围内的请求。4. 抓包请求基础从 URL 到响应写爬虫的第一步不是写代码而是先搞明白目标数据是怎么加载出来的。4.1 HTTP 请求的五个要素一个完整请求由五部分构成要素说明示例请求方法GET 或 POST 等GETURL资源定位地址https://example.com/api/list请求头携带浏览器环境信息User-Agent、Cookie、Referer请求体POST 请求携带的数据form data、JSON响应内容服务器返回的数据HTML、JSON、图片二进制用 requests 发起一个最简单的 GET 请求import requests url https://httpbin.org/get headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(url, headersheaders, timeout10) print(response.status_code) print(response.text)这里httpbin.org是一个 HTTP 请求测试服务返回的 JSON 会回显你的请求头适合验证代理和请求头是否生效。4.2 用浏览器开发者工具抓包打开目标网页按 F12切到 Network 面板刷新页面。这时能看到所有网络请求重点关注Doc类型HTML 文档本身。XHR/Fetch类型异步加载的接口往往返回 JSON。JS/CSS静态资源一般不需要爬。判断数据是直接写在 HTML 里还是异步接口返回决定了后续用数据解析还是直接解析 JSON。4.3 从 HTML 页面到接口请求很多网站首屏数据是服务端渲染的直接通过 HTML 解析即可。但更多现代站点使用前后端分离页面只是空壳真实数据通过 XHR 请求拉取。以列表页为例抓包时先在页面操作一次翻页观察 Network 面板中新增了哪些 XHR 请求。找到返回 JSON 的接口后分析它的 URL 参数规律import requests # 假设翻页时 URL 的 page 参数从 1 变为 2 # 实际调试时用浏览器抓包确认参数名 url https://example.com/api/list params { page: 1, page_size: 20 } headers { User-Agent: Mozilla/5.0, Referer: https://example.com/ } response requests.get(url, paramsparams, headersheaders, timeout10) data response.json() print(data)抓包的关键就是确认三件事接口地址、请求参数、返回的数据结构。这三个确认了爬虫就成功了一半。4.4 携带 Cookie 保持会话如果目标页面需要登录可以用requests.Session()保持会话状态。Session 对象会自动保存服务器返回的 Cookie并在后续请求中带上。import requests session requests.Session() # 先访问登录页获取必要的 Cookie login_page session.get(https://example.com/login, timeout10) # 提交登录表单实际参数以抓包结果为准 login_data { username: your_account, password: your_password } response session.post(https://example.com/api/login, datalogin_data, timeout10) # 之后用同一个 session 发请求自动携带登录态 data_response session.get(https://example.com/api/user_info, timeout10) print(data_response.json())注意这里演示的是正常登录流程。对于没有权限的数据接口不要尝试伪造请求获取。5. 数据解析实战HTML 与 JSON 双线处理请求拿到响应后按内容格式分成两类处理HTML 文档和 JSON 数据。5.1 BeautifulSoup 解析 HTML假设响应内容是静态 HTML需要提取其中的标题和链接from bs4 import BeautifulSoup import requests url https://example.com/news headers {User-Agent: Mozilla/5.0} response requests.get(url, headersheaders, timeout10) soup BeautifulSoup(response.text, html.parser) # 获取页面标题 title soup.find(h1).get_text(stripTrue) print(标题:, title) # 获取所有链接 links soup.find_all(a, hrefTrue) for link in links[:5]: print(link.get(href), link.get_text(stripTrue))核心方法有三个find()匹配第一个符合条件的节点。find_all()匹配所有符合条件的节点返回列表。select()支持 CSS 选择器如soup.select(div.item a)。5.2 XPath 定位节点lxml 的 XPath 在处理复杂嵌套结构时更直接。from lxml import etree html div classitem span classtitle商品A/span span classprice99.00/span /div root etree.HTML(html) title root.xpath(//div[classitem]/span[classtitle]/text()) price root.xpath(//div[classitem]/span[classprice]/text()) print(title[0] if title else ) print(price[0] if price else )XPath 常用语法表达式含义//div选取所有 div 节点//div[classitem]选取 class 为 item 的 div//span/text()获取 span 的文本内容//a/href获取 a 节点的 href 属性值(//div)[1]选取第一个 div5.3 正则表达式补充正则适合处理文本片段提取比如从 HTML 变量中取出特定格式的数据。import re text var json_data {name: python, version: 3.10}; match re.search(r\{.*?\}, text) if match: print(match.group())爬虫中正则可作为辅助不建议单独用正则处理复杂 HTML。结构复杂的解析场景优先选择 XPath 或 BeautifulSoup。5.4 JSON 数据解析异步接口返回的 JSON 最省事直接用response.json()解析。import requests import json url https://example.com/api/list headers {User-Agent: Mozilla/5.0} resp requests.get(url, headersheaders, timeout10) data resp.json() # 假设返回结构为 {data: {items: [{id: 1, name: x}]}} items data.get(data, {}).get(items, []) for item in items: print(item.get(id), item.get(name))实际项目中接口返回的 JSON 结构通常一层套一层。建议拿到响应后先打印出来人工确认层级再用get()逐层取数不要直接索引避免 KeyError 中断程序。5.5 数据存储解析出来的数据建议统一存成结构化格式方便后续分析。import csv import json data_list [ {title: 标题1, price: 99.00}, {title: 标题2, price: 129.00} ] # 写入 CSV with open(data.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[title, price]) writer.writeheader() writer.writerows(data_list) # 写入 JSON with open(data.json, w, encodingutf-8) as f: json.dump(data_list, f, ensure_asciiFalse, indent2)CSV 加utf-8-sig编码可以在 Excel 中直接打开中文不乱码。6. 防封避坑与请求策略让爬虫更稳爬虫被限制绝大多数原因是请求行为不像真人。解决思路不是绕过安全机制而是把请求频率、请求头、访问路径调整到合理范围。6.1 User-Agent 轮换很多服务器会检查 User-Agent如果整个爬虫一直用一个 Python 默认 UA很容易被识别。准备一组常见浏览器的 UA每次请求随机选择。import random import requests user_agents [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15, Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 ] def get_headers(): return { User-Agent: random.choice(user_agents), Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8 } response requests.get(https://httpbin.org/headers, headersget_headers(), timeout10) print(response.text)6.2 请求间隔与随机延迟连续高频请求是最容易触发限流的行为。相邻请求之间加随机延迟模拟真人阅读节奏。import time import random def random_delay(min_seconds1.0, max_seconds3.0): time.sleep(random.uniform(min_seconds, max_seconds))使用方式for page in range(1, 11): url fhttps://example.com/list?page{page} response requests.get(url, headersget_headers(), timeout10) print(f第 {page} 页状态码:, response.status_code) random_delay(1.5, 4.0)注意延迟时间要根据目标网站的承受能力调整不要恶意高频请求。6.3 请求头补全浏览器发请求时会带很多请求头有的服务器会检查 Referer、Origin 等字段。抓包时把浏览器请求头完整复制过来去掉隐私字段后作为模板。headers { User-Agent: Mozilla/5.0, Referer: https://example.com/list, Accept: application/json, text/plain, */*, Accept-Language: zh-CN,zh;q0.9, Connection: keep-alive }6.4 失败重试与状态码处理网络请求不稳定必须做重试。注意区别临时错误和永久错误200成功。403拒绝访问可能是请求头不全、频率过高或 IP 被封。404资源不存在。429请求过多需要等待。500/502/503服务器异常可以稍后重试。import time import requests from requests.adapters import HTTPAdapter def request_with_retry(session, url, headers, retries3, **kwargs): for attempt in range(retries): try: resp session.get(url, headersheaders, timeout10, **kwargs) if resp.status_code 200: return resp elif resp.status_code 429: wait_time 10 * (attempt 1) print(f触发限流等待 {wait_time} 秒) time.sleep(wait_time) else: print(f状态码异常: {resp.status_code}, 第 {attempt 1} 次重试) except requests.RequestException as e: print(f请求异常: {e}, 第 {attempt 1} 次重试) time.sleep(2 * (attempt 1)) return None6.5 断点续爬批量任务最怕跑到一半中断。把已完成的页码或 ID 记录到本地文件下次启动时跳过已完成部分。import os import json def load_progress(filename): if os.path.exists(filename): with open(filename, r, encodingutf-8) as f: return set(json.load(f)) return set() def save_progress(filename, done_pages): with open(filename, w, encodingutf-8) as f: json.dump(list(done_pages), f, ensure_asciiFalse) done_pages load_progress(progress.json) for page in range(1, 101): if page in done_pages: continue print(f正在抓取第 {page} 页) # 执行请求和解析 done_pages.add(page) save_progress(progress.json, done_pages) random_delay(1, 3)这一步在实战中非常有用能避免网络抖动导致整个项目重跑。7. IP 代理与代理池应用当目标网站对单个 IP 的请求频率做限制时可以考虑使用代理。代理的本质是换一个出口 IP让请求看起来来自不同地区、不同设备。7.1 requests 使用代理import requests proxies { http: http://127.0.0.1:7890, https: http://127.0.0.1:7890 } response requests.get( https://httpbin.org/ip, proxiesproxies, headers{User-Agent: Mozilla/5.0}, timeout10 ) print(response.text)验证代理是否生效最简单的方式就是访问https://httpbin.org/ip看返回的 IP 是否与本地公网 IP 不同。7.2 代理池设计代理池是一个动态维护可用代理的服务通常包含三个模块模块职责采集模块从公开代理源获取代理 IP检测模块定时验证代理的连通性和匿名度存储模块把可用代理存到数据库或内存一个简化的代理池检测逻辑如下import requests from concurrent.futures import ThreadPoolExecutor proxy_list [ http://127.0.0.1:8000, http://127.0.0.1:8001, http://127.0.0.1:8002 ] def check_proxy(proxy): test_url https://httpbin.org/ip proxies {http: proxy, https: proxy} try: resp requests.get(test_url, proxiesproxies, timeout5) if resp.status_code 200: return proxy, True except requests.RequestException: pass return proxy, False with ThreadPoolExecutor(max_workers3) as executor: results executor.map(check_proxy, proxy_list) valid_proxies [proxy for proxy, ok in results if ok] print(可用代理:, valid_proxies)7.3 轮询代理批量任务中为每个请求轮流使用不同的代理避免单代理连续请求。import itertools import requests valid_proxies [ http://127.0.0.1:8000, http://127.0.0.1:8001 ] proxy_cycle itertools.cycle(valid_proxies) for page in range(1, 6): proxy next(proxy_cycle) proxies {http: proxy, https: proxy} url fhttps://example.com/list?page{page} try: resp requests.get(url, proxiesproxies, timeout10) print(f第 {page} 页代理 {proxy}状态码 {resp.status_code}) except requests.RequestException as e: print(f代理失败: {proxy}, 错误: {e})使用代理时必须注意优先选择合法的代理服务商。免费代理稳定性差随时可能失效要做好失败重试。不要用代理去攻击目标服务器或绕过平台安全限制。8. 防封避坑与风控识别经验防封的核心不是找漏洞而是让请求行为控制在合理范围。总结几条实战中容易踩的坑8.1 踩坑清单坑点表现处理方式请求头不完整刚发几个请求就被 403对照浏览器补齐 Referer、Accept、Accept-Language请求频率过快出现 429 或验证码加随机延迟控制 QPS单 IP 请求量过大IP 被临时封禁停止请求等待解封必要时降低频率未处理 Cookie登录态丢失返回登录页使用 Session 保持会话未处理重定向拿到 301/302 后的页面而非目标内容设置 allow_redirectsTrue未知错误信息目标页面内容被替换为验证页先检查响应文本确认是否被拦截8.2 识别验证码和风控页面有些网站在检测到异常请求后不会直接拒绝而是返回一个验证页面。判断方式很简单打印 response.text 搜索关键字比如“验证”“captcha”“滑动”等。def is_blocked(response_text): keywords [验证码, captcha, 滑块, 访问过于频繁, 请稍后再试] return any(keyword in response_text for keyword in keywords)如果检测到被风控不要继续硬采集应该停止任务、降低频率或者间隔较长时间再继续。9. 实战项目列表页 详情页二次解析把前面所有模块整合起来做一个完整的实战项目采集一个公开文章列表页的标题、链接和摘要再逐个进入详情页获取正文内容。这个项目模拟的是真实场景中常见的“列表页 详情页”两层结构整体代码可以按模块拆分。9.1 数据模型import csv import random import time import requests from bs4 import BeautifulSoup from requests.adapters import HTTPAdapter class ArticleSpider: def __init__(self, base_url): self.base_url base_url self.session requests.Session() self.session.mount(https://, HTTPAdapter(max_retries3)) self.user_agents [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15 ] def get_headers(self): return { User-Agent: random.choice(self.user_agents), Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8 } def fetch(self, url): resp self.session.get(url, headersself.get_headers(), timeout10) resp.raise_for_status() return resp def parse_list(self, html): soup BeautifulSoup(html, html.parser) articles [] for item in soup.select(.article-item): title_node item.select_one(.article-title a) summary_node item.select_one(.article-summary) if title_node: articles.append({ title: title_node.get_text(stripTrue), link: title_node.get(href), summary: summary_node.get_text(stripTrue) if summary_node else }) return articles def parse_detail(self, html): soup BeautifulSoup(html, html.parser) content_node soup.select_one(.article-content) return content_node.get_text(stripTrue) if content_node else def crawl(self, start_page, end_page, output_file): # 示例方法按页抓取列表再抓详情 # 实际运行时根据目标站点结构调整选择器 pass9.2 抓取流程def main(): spider ArticleSpider(https://example.com) all_data [] for page in range(1, 6): list_url f{spider.base_url}/articles?page{page} try: list_resp spider.fetch(list_url) articles spider.parse_list(list_resp.text) print(f第 {page} 页发现 {len(articles)} 篇文章) for article in articles: if article[link].startswith(http): detail_url article[link] else: detail_url spider.base_url article[link] try: detail_resp spider.fetch(detail_url) article[content] spider.parse_detail(detail_resp.text) except requests.RequestException as e: article[content] print(f详情页抓取失败: {detail_url}, 错误: {e}) all_data.append(article) time.sleep(random.uniform(1.0, 2.5)) except requests.RequestException as e: print(f列表页抓取失败: {list_url}, 错误: {e}) # 写入 CSV if all_data: with open(articles.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[title, link, summary, content]) writer.writeheader() writer.writerows(all_data) print(f完成共抓取 {len(all_data)} 篇文章) if __name__ __main__: main()这个项目的价值在于它把请求、解析、延迟、异常处理、结果导出全部串在一起。第一次跑的时候先用 1 到 2 页测试确认选择器正确再扩大范围。10. 常见问题与排查方法爬虫项目跑不动时按下面的顺序排查。问题现象可能原因排查方式解决方案请求返回 403请求头缺少 User-Agent 或 Cookie打印响应文本看是否返回验证页补齐浏览器请求头使用浏览器 UA返回 404URL 构造错误或参数缺失在浏览器中打开拼接后的 URL对照抓包结果修正 URL 和参数返回 429请求频率过高查看响应头 Retry-After增加随机延迟降低并发解析结果为空CSS 选择器不匹配用浏览器复制元素选择器逐一验证改用 XPath或检查页面是否为动态渲染中文乱码编码识别错误打印响应头的 charset指定response.encoding utf-8或根据页面声明设置代理不生效代理格式错误或失效访问 httpbin.org/ip 看出口 IP重新检测代理更换可用代理程序跑到一半崩了网络异常或数据结构变化查看异常堆栈确认报错行加 try/except使用断点续爬页面是 JS 渲染数据通过异步接口加载抓包找 XHR 接口直接请求接口必要时使用 Selenium 或 Playwright11. 最佳实践与使用建议最后的工程化建议也是爬虫项目能不能长期稳定运行的关键。先在测试环境小范围验证。不要一上来就抓全站先用一页、一个分类、一个接口测试确认选择器和字段解析正确再逐步扩大范围。请求模块要独立封装。把get_headers()、fetch_with_retry()、random_delay()这类公共方法抽成独立模块多个爬虫项目复用减少重复代码。日志必须记录。每个请求的成功失败、状态码、耗时都要写日志。推荐使用 Python 内置的logging模块把日志输出到文件方便排查。import logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(spider.log, encodingutf-8), logging.StreamHandler() ] ) logger logging.getLogger(__name__) logger.info(爬虫开始运行)数据文件做好版本管理。CSV 和 JSON 输出不要直接覆盖按日期命名或分批次存放。接口服务要注意访问范围。如果爬虫结果以 API 的形式提供给内部系统服务要加访问控制不要暴露在公网。合规红线必须清楚。涉及人脸、声音、个人信息、版权内容的数据没有得到明确授权就不抓不存。抓到的数据如果用于商业用途先确认数据归属和授权范围。12. 总结与下一步Python 网络爬虫的完整链路就是请求、解析、策略、代理、防封、存储这六件事。这篇文章把每一块都单独拆开讲清楚了也给出了可直接运行的代码示例和真实项目中最容易踩的坑。建议第一次接触时先按顺序做三件事用 requests 请求 httpbin.org确认请求头和代理参数能生效。找一个公开网站用 F12 抓包找到接口尝试直接请求 JSON 数据。把文章里的列表页 详情页实战代码本地跑起来替换成自己熟悉的目标站点做测试。最容易踩的坑是忽略请求头和频率控制。很多爬虫写出来一运行就被封不是代码逻辑问题而是行为特征太明显。只要把请求头补全、延迟加上、重试做好大部分问题都能规避。后续可以继续深入的方向包括Scrapy 分布式爬虫、Playwright 处理 JS 渲染页面、RabbitMQ 或 Redis 构建任务队列、爬虫数据的清洗和分析。这套基础打扎实了这些进阶方向都能平滑承接。建议先收藏这篇文章按步骤操作一遍遇到问题再翻到“常见问题与排查方法”对照处理。
返回列表