ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

爬虫抓取网页数据实战:从Requests到分布式爬虫与反爬攻防

爬虫抓取网页数据实战:从Requests到分布式爬虫与反爬攻防 简介这是一份基于Scrapy框架抓取BBS论坛数据的Python爬虫项目资源适合初学爬虫的开发者也适合需要批量收集网站结构化数据的数据分析人员主要解决数据挖掘、信息处理及历史数据存储等场景下的网页抓取与字段提取问题。压缩包共14个文件以Python源码为主同时包含编译后的pyc文件、Scrapy项目配置和一份docx说明文档可看到spider逻辑、数据管道、配置项等核心模块的编写方式整体体积仅18KB便于快速部署与二次修改docx文档重点梳理了BBS站点的抓取思路与字段定义配合源码查阅更易上手。目前已有5615人学习使用。通过阅读说明文档并对照源码可以掌握Scrapy项目从建立、配置到运行抓取的基本流程资源还提供了items与pipelines等模块的参考实现适合作为课程设计、毕业设计或兴趣练习的起步模板也能据此扩展到其他网站。 爬虫抓网页数据这事儿说难不难说简单也真不简单。我刚开始接触那会儿觉得爬虫就是模拟浏览器发个请求、拿回HTML再解析一下简直有手就行。可真当自己动手去爬一些目标网站遇到登录、验证码、字体反爬、接口加密之后才发现这里面的水比想象中深得多。这篇就结合我自己的实操经验把爬虫抓取网页数据的完整思路、常用工具、实操步骤、防封策略和工程化演进都捋一遍希望能帮到正准备入坑或者已经在坑里挣扎的朋友。1. 项目整体设计与技术选型思路爬虫项目开始之前我最想劝告各位的是先别急着写代码。接到“抓取网页数据”这个需求时我通常会先花半小时把目标网站的结构、数据格式、反爬机制都摸一遍再做技术选型。这一步的决策直接决定你是5分钟搞定还是被反爬折腾到怀疑人生。1.1 先搞清楚目标对象的“脾气”不同的网站数据的呈现方式完全不一样对应的抓取策略也天差地别。我一般会把目标网站分成三类来看纯静态页面数据直接写在HTML里用requests请求后解析即可最简单的场景。异步动态渲染数据通过JavaScript动态加载HTML源码里看不到关键数据需要分析XHR接口或使用渲染工具。接口加密型请求参数、响应数据都做了加密混淆比如常见的JSON里夹带16进制字符串、参数经过MD5/AES/DES加密等这就需要逆向前端JS逻辑。我第一次爬某个新闻门户时以为就是一个简单的requests加正则就能搞定结果发现HTML源码里除了框架什么都没有数据全是后期异步加载的。后来用开发者工具开了Network面板才在XHR请求里找到了真正的数据接口。那会儿才发现看页面源码还不如直接盯着网络面板来得实在。1.2 技术选型背后的考量逻辑选型的时候不要迷信“工具越强大越好”而是要看自己的目标和场景。我的选择逻辑是这样的几十页的小规模采集直接Python requests BeautifulSoup轻量、可控、排查方便不需要重型框架。中等规模、规则明确且反爬不太强的站点Scrapy框架下载中间件、管道、去重、调度器都内置好了开发效率高。大规模分布式采集Scrapy Scrapy-Redis实现多节点共享调度队列应对几千万级URL的抓取。动态渲染较重或涉及复杂登录Selenium、Playwright这类浏览器自动化工具通过真实浏览器环境规避大部分基础反爬。这里要特别提醒一下requests写起来虽然快但它只负责“拿数据”不负责“解析数据”。很多人误以为requests是爬虫的全部其实它只是第一步。我见过不少新手拿requests把HTML抓下来之后看着一大堆标签手足无措这就是没有提前做好技术认知的规划。1.3 分布式爬虫到底解决了什么问题热词里频繁出现的“分布式爬虫”很多人觉得大而空其实它的核心价值只有两个横向扩展抓取速度和统一管理任务状态。我最早接触分布式爬虫是在做电商比价数据采集的时候。单机跑Scrapy虽然能达到每秒几十个请求但要抓几百个类目、每类好几千个商品仍然需要跑十几个小时。后来引入了Scrapy-Redis把请求队列放在Redis里再用三台服务器同时跑同一个爬虫抓取效率接近线性提升。原理上并没有多玄妙就是多个爬虫进程共同消费同一个URL队列各自把抓取结果写入同一个存储集群核心在“共享状态”。如果你只是抓个几千条数据完全没必要上分布式单机加个协程池就绰绰有余了。技术选择永远是“够用就好适度超前”过早引入复杂架构只会让你陷入运维泥潭。2. 核心细节解析与实操要点很多爬虫教程一上来就甩代码但代码跑完了读者依然不知道怎么应对变化。我在这里把抓取链路里几个核心环节单独拆开讲一讲细节和容易踩坑的点。2.1 HTTP请求的关键Header伪装与Session持久化发请求是爬虫的第一步但直接裸发requests.get(url)十有八九会被拦截。原因很简单服务端可以通过User-Agent、Referer、Cookie等标识判断你不是真实用户。我习惯的做法是建立一个请求头字典把浏览器环境里的UA、Accept、Accept-Language都带上尤其是User-Agent建议直接用真实Chrome版本。而且如果你要维持登录状态、保持会话一定要用requests.Session()而不是每次请求都新建一个requests对象。Session会自动保存Cookie在需要“先登录后抓取”的场景下能免去很多麻烦。import requests session requests.Session() headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://example.com/ } session.headers.update(headers) resp session.get(https://example.com/list, timeout10)这里有个细节很多人忽略很多网站的反爬不仅看UA还会校验Referer。如果你直接从一个页面跳到另一个接口Referer对不上响应就可能是403或者一个假数据页。所以每次请求的Headers一定要结合具体业务场景去伪造别一个UA打天下。2.2 动态页面的“元凶”接口发现与异步加载现在主流的Web应用基本都采用前后端分离架构HTML只是一个空壳数据靠Ajax加载。爬这种站我建议直接抓接口而不是用Selenium去渲染页面因为渲染的效率太低资源占用也大很多。具体做法就是打开Chrome开发者工具切到Network面板刷新页面筛选XHR或Fetch请求找到返回JSON数据的那个接口。比如我爬一个电商网站的商品列表时看到页面上展示了20个商品但HTML里根本没有商品数据Network里有一个/api/product/list?page1的请求响应里直接就是JSON格式的名称、价格、库存信息。那爬虫就变成了简单的HTTP请求加JSON解析。但接口往往伴随着分页参数、签名参数。常见的是page、size、offset往深一点就是sign、token、timestamp这类防伪参数。携程、大众点评这类网站的接口会做请求参数加密签名逻辑通常在前端JS里这时就要用Node.js或者Python的execjs库去执行JS代码拿到真正的请求参数。2.3 解析HTML与JSON的细节差异拿到HTML后常见的解析方案有正则、BeautifulSoup、lxml、XPath和PyQuery。我的个人偏好是静态HTML首选lxml XPathJSON响应直接用json库即可。正则虽然灵活但一旦遇到多层嵌套的HTML结构写出来的正则就是一坨完全不可维护的“天书”出了问题排查起来特别痛苦。BeautifulSoup简单易读适合新手性能也还行。但如果你追求抓取速度XPath的解析性能明显优于BeautifulSoup尤其是在一个页面有几百个列表项要提取的场景下差距非常直观。from lxml import etree parser etree.HTMLParser() tree etree.fromstring(html_content, parser) titles tree.xpath(//div[classitem]/a[classtitle]/text())XPath的写法需要一定经验积累我的一个小技巧是在Chrome的开发者工具里直接右键元素 - Copy - Copy XPath生成一个基础的XPath路径作为起点再手动精简优化。直接复制出来的路径往往很长、性能差、抗页面布局变化的能力弱但作为参考锚点非常实用。3. 实操过程与核心环节实现这一部分我以“从零抓取一个列表页并存储”为例把整个流程完整走一遍代码不算复杂但每一步都有值得注意的细节。3.1 确定目标与准备环境假设我要抓取一个电影资讯网站的“热门电影列表”目标是拿电影名称、评分和简介。这个站点是纯HTML渲染的没有异步加载也没有登录限制用来演示最合适。环境准备只需要三个包pip install requests lxml pandasrequests负责发请求lxml负责解析HTMLpandas用来做最后的表格化输出。我建议你无论做什么爬虫都先把这三个库熟练到条件反射的程度它们是爬虫体系里性价比最高的基础组合。3.2 完整抓取与解析代码import requests import pandas as pd from lxml import etree url https://example.com/movies headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 } resp requests.get(url, headersheaders, timeout10) resp.encoding resp.apparent_encoding # 处理编码防止中文乱码 if resp.status_code 200: tree etree.HTML(resp.text) movie_items tree.xpath(//div[contains(class, movie-item)]) data [] for item in movie_items: title item.xpath(.//span[classtitle]/text()) rating item.xpath(.//span[classrating]/text()) summary item.xpath(.//p[classsummary]/text()) data.append({ 标题: title[0] if title else , 评分: rating[0] if rating else , 简介: summary[0].strip() if summary else }) df pd.DataFrame(data) df.to_csv(movies.csv, indexFalse, encodingutf-8-sig) print(f成功抓取 {len(df)} 条数据) else: print(f请求失败状态码{resp.status_code})这段代码有几个点值得专门说。第一是编码问题。不少中文网站在响应头里根本没有charset或者charset声明和实际内容不一致。你在本地预览时如果看到乱码大概率就是编码没有处理对。我一般用resp.apparent_encoding让requests根据内容自动推断编码大部分场景下比直接指定resp.encodingutf-8靠谱得多。第二是XPath的容错。你看我在提取每个字段时都判断了列表是否为空。因为XPath提取不到元素时返回的是空列表如果你直接title[0]就会抛IndexError。写过爬虫的人都知道反爬和数据缺失造成的异常是家常便饭健壮性永远比一次性跑通更重要。第三是CSV的编码格式。如果直接把DataFrame存成to_csv(movies.csv, indexFalse)默认编码是utf-8。Windows里的Excel打开这个文件时中文会全部乱掉因此我习惯加上encodingutf-8-sig也就是带BOM头的UTF-8格式Excel就能正常识别了。3.3 翻页与循环抓取单页数据量有限真实项目中必须要翻页。常见的翻页方式有两种URL参数翻页和点击加载更多。假如翻页参数就是URL里的page那直接循环就好all_data [] for page in range(1, 11): page_url fhttps://example.com/movies?page{page} # 这里复用前面的请求和解析逻辑提取每页数据 all_data.extend(parse_page(page_url)) time.sleep(1) # 绅士式爬取避免给服务器造成压力这里我故意加了time.sleep(1)。很多新手觉得爬虫快就是本事结果一套循环下去几百个请求秒发出去直接触发服务器限流规则IP被封。节奏控制不是怂是策略。如果你面对的是Boss直聘、携程这类反爬比较严的站点甚至还需要在两次请求之间随机Sleep一个区间比如random.uniform(0.5, 1.5)这才是更贴近真人浏览的节奏。4. 常见问题与排查技巧实录爬虫写完了并不代表万事大吉。我在平时维护爬虫的过程中最常遇到的就是下面这几类问题每一类都曾经让我踩过坑。4.1 请求返回403或302403意味着服务器拒绝你的访问最直接的原因是请求头不完整或者IP被限制。302则说明网站把你重定向到了登录页或验证页面。排查步骤我的习惯是先检查headers的User-Agent是否完整且符合主流浏览器特征。再检查是否缺少Cookie或Referer。确认是否触发了频率限制——试试手动等待几分钟再请求一次。如果IP被封了短时间解封不了只能换代理IP。代理这块我要多说一句很多人热衷于免费代理池但以我的经验公开免费代理的存活率极低稳定性更差有时候花半天时间维护代理池不如直接买付费代理服务来得踏实。如果你只是小规模抓取用自己本地IP加合理节奏就够了没必要在代理上过度投入。4.2 数据解析不出来或解析为空解析结果为空时我建议先从这三步排查页面结构是否变了网站改版是常有的事之前写好的XPath直接失效这时候需要重新用开发者工具检查页面结构。是否JavaScript动态渲染如果你用requests拿到的是空数据去浏览器的Network面板里找XHR接口。记住一句话浏览器里看到的不等于requests能拿到的。是否触发了反爬虫假数据有些网站反爬做得很“友好”——它不是返回403而是返回一个看起来完全正常、实际是假数据的页面。我遇到过返回200但页面里全是随机文章的情况这就需要你写代码时对抓到的数据做合理性校验。4.3 抓取速度慢怎么优化如果单机抓取几千个页面requests串行请求确实偏慢但大多数人不需要立刻上Scrapy。我推荐先用concurrent.futures的线程池简单改造一下就能获得几倍的速度提升。from concurrent.futures import ThreadPoolExecutor, as_completed def fetch_and_parse(url): # 一次完整请求解析 pass urls [fhttps://example.com/page/{i} for i in range(1, 100)] with ThreadPoolExecutor(max_workers8) as executor: futures {executor.submit(fetch_and_parse, url): url for url in urls} for future in as_completed(futures): result future.result() # 处理结果用线程池的时候注意控制并发数。8个线程已经能对单机资源利用得很好了再往上加服务器未必扛得住你的IP也更容易被封。我当时刚开始优化的时候直接把线程开到50个结果爬到一半IP被网站封了整整一天教训非常深刻。4.4 登录后才能看到的数据怎么抓网上热词里有“微信公众号爬虫”“boss直聘爬虫”这类搜索词它们背后都有一个共同难题登录鉴权。微信公众号文章需要登录才能获取历史内容Boss直聘也需要登录后才能查看职位详情。面对登录态我的通用方案是用浏览器手动登录一次打开开发者工具从Network请求里把Cookie复制出来。把Cookie放到Requests的请求头里直接绕过登录流程。如果Cookie过期了重新去浏览器复制一遍。这个方案简单粗暴适合登录态有效期较长的站点。如果是短效Cookie比如每次会话一换那就要考虑自动化的登录流程通过代码提交账号密码、处理验证码。再往上就是Selenium/Playwright模拟真人操作成本逐渐升高你自己要评估投入产出比是否合适。5. 爬虫的工程化与智能化演进方向基础爬虫只是起点真正有价值的系统是能稳定运行、自动维护、持续产出的数据管道。最后这部分聊聊爬虫工程化和行业前沿方向。5.1 从脚本到Scrapy框架的过渡当你发现自己写了大量重复的请求处理、数据清洗、管道存储代码时就该考虑迁移到Scrapy了。Scrapy的架构非常清晰核心是四个组件Spiders业务逻辑所在定义抓取规则和页面解析。Items定义数据字段的数据结构相当于字典的规范化。Pipelines负责数据的清洗、去重、存储。Middlewares处理请求/响应的钩子比如代理切换、UA轮换、Cookie管理。用Scrapy的好处不仅是性能高更关键的是它天然鼓励你写出结构清晰的代码后续维护和扩展都轻松很多。从脚本到框架我认为是爬虫开发者必须跨过的分水岭。5.2 大模型如何改变爬虫技术热词里出现“大模型逆向爬虫”这个词我觉得有必要说道说道。大模型在爬虫领域的应用目前主要是三个方向辅助JS逆向分析面对混淆严重的前端代码用大模型分析加密逻辑、生成解混淆后的伪代码能节省大量人工分析时间。智能解析页面传统爬虫需要手写XPath或选择器而大模型可以结合HTML文本语义自动识别出标题、正文、发布时间等核心字段提高通用爬虫的泛化能力。验证码识别这是老方向了大模型在图形验证码、滑块验证码的识别上目前已经到了可以商用的水平。我身边有团队在做“大模型爬虫”的通用解析引擎他们用GPT类模型来理解网页区块语义替代传统的XPath硬编码。效果在内容型网站新闻、博客、BBS上已经不错了但在强反爬、重交互的平台上还是离不开代码层面的逆向工作。所以如果你要入行爬虫扎实的HTTP知识、JS逆向功底依然是基本功大模型只是辅助工具不是银弹。5.3 关于爬虫合规的几点提醒爬虫领域始终伴随合规的争议。我劝所有做数据采集的朋友从一开始就把“遵守规则”刻在脑子里。我的三个底线原则是尊重Robots协议网站如果明确声明了某些路径禁止抓取尽量避开。控制请求频率不给目标服务器造成明显压力这是技术礼貌也是规避法律责任的重要一环。不采集个人隐私数据涉及姓名、手机号、通讯录等个人信息无论技术难度多大都不应该去碰。这个行业里因为爬虫被请去喝茶的案例并不少见。技术能力越强越应该明白边界在哪里。回到标题本身“爬虫抓取网页数据”表面上是一个技术动作深入下去会涉及HTTP协议、前端解构、JS逆向、分布式系统、数据治理和大模型应用等多个领域。对我而言爬虫最迷人的地方是它能让你用代码把散落在互联网角落里的信息重新组织成有结构、有价值的资产。但这份价值的前提始终是合法合规以及你对技术的敬畏心。希望这篇经验分享能给正在这个方向摸索的你一些实用参考。本文还有配套的精品资源点击获取
返回列表