Python 爬虫 3 大核心库深度解析:从原理到实战,覆盖 90% 爬取场景

Python 爬虫的高效性,依赖于 "请求 - 解析 - 工程化" 的工具链协同。RequestsBeautiful SoupScrapy 三者分别对应爬虫流程的核心环节,不仅要会用,更要理解 "为何用""何时用"。以下从核心原理、进阶功能、实战案例、避坑技巧四维度,带你彻底掌握这三大库。

一、Requests:爬虫的 "HTTP 请求瑞士军刀"

Requests 基于 urllib3 封装,核心是 "简化 HTTP 协议交互"------ 无需手动拼接请求头、处理编码异常,让开发者专注于 "要爬什么",而非 "怎么发请求"。

1. 核心原理:模拟浏览器与服务器通信

当你用 requests.get(url) 时,底层发生了 3 件事:

  1. 构建符合 HTTP 协议的请求头(如User-AgentCookie);
  2. 向目标服务器发送 TCP 连接,传递请求信息;
  3. 接收服务器响应,自动解析响应状态码(如 200 = 成功、403 = 禁止访问)和响应体(HTML/JSON)。

2. 进阶功能:应对 90% 基础反爬

(1)请求头伪装:突破 "浏览器检测"

服务器常通过 User-Agent 判断请求是否来自浏览器,直接发送请求会被识别为 "爬虫",返回 403。解决方案 :添加真实浏览器的User-Agent,甚至补充Referer(表明请求来源页面)。

python

运行

复制代码
import requests

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "Referer": "https://www.example.com/"  # 模拟从example.com跳转过来的请求
}
response = requests.get("https://www.example.com/target", headers=headers)
(2)Session 维持:模拟 "登录状态"

爬取需要登录的页面(如个人账号数据)时,单独的get请求会丢失登录 Cookie。requests.Session() 可维持会话,自动保存 Cookie。

python

运行

复制代码
# 1. 创建Session对象(自动管理Cookie)
s = requests.Session()

# 2. 先发送登录请求(传递账号密码,获取登录Cookie)
login_data = {"username": "your_id", "password": "your_pwd"}
s.post("https://www.example.com/login", data=login_data, headers=headers)

# 3. 再访问需要登录的页面(已携带登录Cookie,可正常获取数据)
user_data = s.get("https://www.example.com/my-data", headers=headers)
print(user_data.text)
(3)代理 IP 配置:突破 "IP 封禁"

频繁请求同一 IP 会被服务器封禁,需用代理 IP 切换请求来源。

python

运行

复制代码
# 代理IP格式:{协议: 代理地址}
proxies = {
    "http": "http://123.45.67.89:8080",
    "https": "https://123.45.67.89:8443"
}
# 发送请求时指定代理
response = requests.get("https://www.example.com", headers=headers, proxies=proxies)

3. 避坑技巧

  • 编码乱码 :服务器返回的 HTML 可能是gbk编码(如部分中文网站),用response.encoding = "gbk"手动指定,而非默认的utf-8
  • 超时设置 :避免请求卡在无响应的服务器,添加timeout=5(5 秒内无响应则报错);
  • SSL 证书错误 :爬取https网站时若提示证书错误,添加verify=False(仅用于测试,生产环境需配置证书)。

二、Beautiful Soup:爬虫的 "HTML 解析手术刀"

Beautiful Soup 核心是 "将非结构化的 HTML 字符串,转为结构化的 DOM 树对象",支持通过 "标签、属性、文本" 精准定位数据,无需写复杂正则。

1. 核心原理:DOM 树遍历与查询

当你用 BeautifulSoup(html, "lxml") 时,工具会:

  1. 解析 HTML 字符串,生成类似浏览器的 DOM 树(每个标签都是一个 "节点");
  2. 提供find()/find_all()等方法,按 "标签名 + 属性" 查询节点;
  3. 从节点中提取文本(get_text())或属性值(['href'])。

2. 进阶功能:精准提取复杂数据

(1)多条件查询:定位唯一节点

当页面有多个相同标签时,通过 "标签名 + class+id" 组合查询,避免提取错误数据。

python

运行

复制代码
from bs4 import BeautifulSoup
import requests

html = requests.get("https://www.example.com/product", headers=headers).text
soup = BeautifulSoup(html, "lxml")  # 推荐用lxml解析器(速度比默认html.parser快3倍)

# 提取:class为"product-price"且id为"current-price"的span标签(商品当前价格)
price = soup.find("span", class_="product-price", id="current-price")  # class_加下划线避免与关键字冲突
print(price.get_text())  # 输出价格文本,如"¥999"

# 提取:所有class为"product-item"的div标签下的a标签(商品链接)
product_links = soup.find_all("div", class_="product-item")
for item in product_links:
    link = item.find("a")["href"]  # 获取a标签的href属性(商品链接)
    print(link)
(2)CSS 选择器:更灵活的定位

若习惯前端 CSS 选择器(如.class#id),可用soup.select(),语法更简洁。

python

运行

复制代码
# 1. 用CSS选择器提取:id为"current-price"的标签(#表示id)
price = soup.select("#current-price")[0].get_text()  # select返回列表,取第1个元素

# 2. 用CSS选择器提取:class为"product-item"下的a标签(.表示class)
product_links = soup.select(".product-item a")
for link in product_links:
    print(link["href"])
(3)处理嵌套标签:提取深层数据

面对多层嵌套的 HTML(如 "商品列表→商品项→商品名称"),通过 "父节点→子节点" 逐层定位,避免干扰。

html

预览

复制代码
<!-- 页面HTML结构 -->
<div class="product-list">
    <div class="product-item">
        <h3 class="product-name">手机A</h3>
    </div>
    <div class="product-item">
        <h3 class="product-name">手机B</h3>
    </div>
</div>

python

运行

复制代码
# 1. 先定位父节点(商品列表)
product_list = soup.find("div", class_="product-list")

# 2. 在父节点内提取所有子节点(商品名称)
product_names = product_list.find_all("h3", class_="product-name")
for name in product_names:
    print(name.get_text())  # 输出"手机A"、"手机B"

3. 避坑技巧

  • 解析器选择 :优先用lxml(需提前安装:pip install lxml),速度快且支持容错(能解析不规范的 HTML);
  • 空值处理 :若find()未找到节点,会返回None,直接调用get_text()会报错,需先判断:if price: print(price.get_text())
  • 动态内容 :Beautiful Soup 只能解析 "静态 HTML",若数据是 JavaScript 动态加载(如滚动加载的列表),需搭配Selenium或抓包工具获取 API 接口。

三、Scrapy:爬虫的 "工程化作战系统"

Scrapy 不是单一库,而是 "请求调度 + 数据解析 + 存储 + 反爬" 的完整框架,核心是 "用组件化思想,实现高并发、可维护的爬虫项目"。

1. 核心原理:组件化工作流

Scrapy 的工作流由 5 个核心组件协同完成:

  1. 爬虫(Spider):定义爬取 URL、解析数据的逻辑(开发者主要编写这部分);
  2. 调度器(Scheduler):管理待爬 URL 队列,避免重复爬取,支持优先级排序;
  3. 下载器(Downloader) :发送 HTTP 请求,获取响应(类似Requests,但支持并发);
  4. 管道(Item Pipeline):处理爬取到的数据(如清洗、去重、存入数据库);
  5. 中间件(Middleware):拦截请求 / 响应,添加代理、修改请求头(应对反爬)。

2. 进阶功能:从 "能爬" 到 "爬得好"

(1)XPath 解析:比 CSS 选择器更强大

Scrapy 内置Selector,支持 XPath(XML 路径语言),能更灵活地定位深层数据,尤其适合复杂 HTML。

python

运行

复制代码
# 爬虫文件(example_spider.py)
import scrapy
from scrapy.http import Request

class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["example.com"]  # 限制爬取域名,避免爬到其他网站
    start_urls = ["https://www.example.com/product-list"]  # 起始URL

    def parse(self, response):
        # 1. 用XPath提取所有商品链接(//表示全局查找,@href获取属性)
        product_urls = response.xpath('//div[@class="product-item"]/a/@href').getall()
        for url in product_urls:
            # 2. 发送请求爬取商品详情页(callback指定解析详情页的函数)
            yield Request(url=response.urljoin(url), callback=self.parse_detail)

        # 3. 爬取下一页(提取下一页链接,继续发送请求)
        next_page = response.xpath('//a[@class="next-page"]/@href').get()
        if next_page:
            yield Request(url=response.urljoin(next_page), callback=self.parse)

    # 解析商品详情页的函数
    def parse_detail(self, response):
        # 用XPath提取商品名称、价格、描述
        item = {}  # 存储数据的字典(或定义Item类)
        item["name"] = response.xpath('//h1[@class="product-name"]/text()').get().strip()
        item["price"] = response.xpath('//span[@id="current-price"]/text()').get()
        item["desc"] = response.xpath('//div[@class="product-desc"]/p/text()').getall()  # getall()获取所有文本
        yield item  # 将数据传递给Item Pipeline
(2)Item Pipeline:数据清洗与存储

爬取到的数据常需清洗(如去除空格、去重),再存入数据库。在pipelines.py中定义处理逻辑:

python

运行

复制代码
# pipelines.py
import pymongo  # 需安装:pip install pymongo

class ExamplePipeline:
    # 爬虫启动时执行(初始化数据库连接)
    def open_spider(self, spider):
        self.client = pymongo.MongoClient("mongodb://localhost:27017/")
        self.db = self.client["spider_db"]  # 数据库名
        self.col = self.db["product_data"]  # 集合名(类似表)

    # 处理每一条爬取到的数据
    def process_item(self, item, spider):
        # 1. 数据清洗:去除商品名称的空格
        item["name"] = item["name"].strip()
        # 2. 数据去重:根据商品名称判断是否已存在,不存在则插入
        if not self.col.find_one({"name": item["name"]}):
            self.col.insert_one(dict(item))
        return item

    # 爬虫关闭时执行(关闭数据库连接)
    def close_spider(self, spider):
        self.client.close()

之后在settings.py中启用 Pipeline:ITEM_PIPELINES = {"example.pipelines.ExamplePipeline": 300}(300 是优先级,数字越小越先执行)。

(3)中间件:应对中高级反爬

middlewares.py中添加 "请求头随机化""代理 IP 切换" 逻辑,突破 IP 封禁和请求头检测:

python

运行

复制代码
# middlewares.py
import random

class RandomUserAgentMiddleware:
    # 随机User-Agent列表
    USER_AGENTS = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/125.0.0.0 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Firefox/126.0"
    ]

    # 拦截请求,添加随机User-Agent
    def process_request(self, request, spider):
        request.headers["User-Agent"] = random.choice(self.USER_AGENTS)

class RandomProxyMiddleware:
    # 代理IP列表
    PROXIES = [
        "http://123.45.67.89:8080",
        "https://98.76.54.32:8443"
    ]

    # 拦截请求,添加随机代理
    def process_request(self, request, spider):
        proxy = random.choice(self.PROXIES)
        request.meta["proxy"] = proxy

settings.py中启用中间件:

python

运行

复制代码
DOWNLOADER_MIDDLEWARES = {
    "example.middlewares.RandomUserAgentMiddleware": 543,
    "example.middlewares.RandomProxyMiddleware": 544,
}

3. 避坑技巧

  • 并发控制 :默认并发数较高,易被服务器检测,在settings.py中设置CONCURRENT_REQUESTS = 5(5 个并发请求);
  • 下载延迟 :添加DOWNLOAD_DELAY = 2(每个请求间隔 2 秒),模拟人类浏览速度;
  • 日志查看 :启用日志(LOG_LEVEL = "INFO"),通过日志排查 "请求失败""数据提取为空" 的原因。

三大库对比与选择指南

维度 Requests Beautiful Soup Scrapy
核心定位 发送 HTTP 请求 解析 HTML 数据 工程化爬虫框架
学习成本 低(1 小时上手) 低(2 小时上手) 中(1-2 天掌握核心)
并发能力 弱(需手动实现多线程) 无(仅解析) 强(内置高并发)
适用场景 单页面 / 接口爬取 静态 HTML 解析 多页面 / 整站 / 分布式爬取
典型搭配 单独使用或 + Beautiful Soup 必须搭配 Requests/Scrapy 单独使用(内置解析)

选择逻辑

  1. 快速验证需求 (如爬取 1 个接口数据):直接用Requests
  2. 静态页面数据提取 (如爬取新闻标题 + 内容):Requests + Beautiful Soup
  3. 长期维护 / 大量数据 (如爬取整站商品、定时爬取):Scrapy
相关推荐
深蓝电商API7 小时前
数据清洗标准化:构建可复用的爬虫数据清洗管道(Pipeline)
爬虫·数据清洗
深蓝电商API9 小时前
“监狱”风云:如何设计爬虫的自动降级与熔断机制?
爬虫
励志成为糕手11 小时前
VSCode+Cline部署本地爬虫fetch-mcp实战
ide·vscode·爬虫·ai·mcp
APIshop11 小时前
代码实战:PHP爬虫抓取信息及反爬虫API接口
开发语言·爬虫·php
咋吃都不胖lyh12 小时前
比较两个excel文件的指定列是否一致
爬虫·python·pandas
小白学大数据1 天前
构建1688店铺商品数据集:Python爬虫数据采集与格式化实践
开发语言·爬虫·python
AI分享猿1 天前
免费WAF天花板!雷池WAF护跨境电商:企业级CC攻击防御,Apache无缝适配
爬虫·web安全
雪碧聊技术1 天前
手刃一个爬虫小案例
爬虫·第一个爬虫案例
野生工程师1 天前
【Python爬虫基础-1】爬虫开发基础
开发语言·爬虫·python