用 Python 写你的第一个爬虫:小白也能轻松搞定数据抓取(超详细包含最新所有Python爬虫库的教程)

摘要

本文是一篇面向爬虫爱好者的超详细 Python 爬虫入门教程,涵盖了从基础到进阶的所有关键技术点:使用 Requests 与 BeautifulSoup 实现静态网页数据抓取,运用 lxml、XPath、CSS 选择器等高效解析技术,深入 Scrapy 框架搭建分布式爬虫项目,掌握 Selenium 和 Playwright 浏览器自动化处理 JS 动态渲染,探索 aiohttp、HTTPX 异步爬虫提升并发性能,并结合代理 IP 池、User-Agent 伪装、验证码识别等反爬虫策略应对电商数据抓取、新闻数据爬取、社交媒体采集等场景。快速上手大规模爬虫项目,打造可扩展、高效稳定的数据抓取解决方案。


用 Python 写你的第一个爬虫:小白也能轻松搞定数据抓取(超详细包含最新所有Python爬虫库的教程)

目录

  1. 前言

  2. 爬虫基础知识

    • 2.1 什么是爬虫?
    • 2.2 爬虫的应用场景
    • 2.3 爬虫基本流程
    • 2.4 需要注意的法律与伦理问题
  3. 开发环境准备

    • 3.1 安装 Python(建议 3.8 及以上)
    • 3.2 创建虚拟环境并激活
    • 3.3 常用开发工具推荐
  4. 基础篇:用 Requests + BeautifulSoup 做简单爬虫

    • 4.1 安装必要库
    • 4.2 认识 HTTP 请求与响应
    • 4.3 编写第一个爬虫:抓取网页标题
    • 4.4 解析HTML:BeautifulSoup 用法详解
    • 4.5 文件存储:将抓到的数据保存为 CSV/JSON
    • 4.6 常见反爬措施及应对策略
  5. 进阶篇:更强大的解析工具

    • 5.1 lxml (XPath)
    • 5.2 parsel(Scrapy 内置的解析器)
    • 5.3 PyQuery(类似 jQuery 的解析方式)
    • 5.4 正则表达式在爬虫中的应用
  6. 框架篇:Scrapy 全面入门

    • 6.1 Scrapy 简介
    • 6.2 安装与项目结构
    • 6.3 编写第一个 Scrapy 爬虫 Spider
    • 6.4 Item、Pipeline、Settings 详解
    • 6.5 Scrapy Shell 在线调试
    • 6.6 分布式与多线程:Scrapy 爬虫并发配置
    • 6.7 Scrapy 中间件与扩展(Downloader Middleware、Downloader Handler)
  7. 动态内容爬取:Selenium 与 Playwright

    • 7.1 为什么需要浏览器自动化?
    • 7.2 Selenium 基础用法
    • 7.3 Playwright for Python(更快更轻量)
    • 7.4 无头浏览器(headless)模式及性能优化
    • 7.5 结合 Selenium/Playwright 与 BeautifulSoup 解析
  8. 异步爬虫:aiohttp + asyncio 与 HTTPX

    • 8.1 同步 vs 异步:性能原理简述
    • 8.2 aiohttp 入门示例
    • 8.3 使用 asyncio 协程池提高并发
    • 8.4 HTTPX:Requests 的异步升级版
    • 8.5 异步下使用解析库示例(aiohttp + lxml)
  9. 数据存储与去重

    • 9.1 本地文件:CSV、JSON、SQLite
    • 9.2 MySQL/PostgreSQL 等关系型数据库
    • 9.3 MongoDB 等 NoSQL 存储
    • 9.4 Redis 用作去重与短期缓存
    • 9.5 去重策略:指纹、哈希、Bloom Filter
  10. 分布式爬虫:Scrapy-Redis 与分布式调度

    • 10.1 为什么要做分布式?
    • 10.2 Scrapy-Redis 简介与安装
    • 10.3 分布式去重队列与调度
    • 10.4 多机协作示例
  11. 常见反爬与反制策略

    • 11.1 频率限制与请求头伪装
    • 11.2 登录验证与 Cookie 管理
    • 11.3 验证码识别(简单介绍)
    • 11.4 代理 IP 池的搭建与旋转
  12. 完整案例:爬取某新闻网站并存入数据库

    • 12.1 需求分析
    • 12.2 使用 Scrapy + MySQL 完整实现
    • 12.3 代码详解与常见 Q&A
  13. Python 爬虫相关的常用第三方库一览(截至 2024 年底)

    • 13.1 基础请求与解析
    • 13.2 浏览器自动化
    • 13.3 异步爬取
    • 13.4 登录模拟与验证码处理
    • 13.5 反爬与代理
    • 13.6 分布式调度
    • 13.7 其它有用工具
  14. 附录

    • 14.1 常见报错及解决方案
    • 14.2 常用 HTTP 状态码速查
    • 14.3 学习资源与进阶指南
  15. 总结


1. 前言

在信息爆炸的时代,互联网早已成为最丰富、最便捷的数据来源。从电商平台的商品价格到新闻网站的最新动态,从社交媒体的热门话题到招聘网站的职位信息,只要你想得到,几乎都能通过爬虫从网页里“扒”出来。对于初学者而言,爬虫其实并不神秘:只要理解 HTTP、HTML 及基本的 Python 编程,就能快速入门。本教程面向“零基础”“小白”用户,讲解从最基本的抓取到进阶框架、异步、分布式再到反爬策略,逐步深入,手把手指导你搭建完整爬虫,并总结截至 2025 年最常用的 Python 爬虫库。

本教程特色

  • 循序渐进:从最简单的 requests + BeautifulSoup 开始,到 Scrapy、Selenium、Playwright、异步爬虫,一步步掌握。
  • 超详细示例:每个工具/框架都配有完整可运行的示例代码,你可以直接复制、运行、观察。
  • 最新库盘点:整理并介绍了截至 2025 年所见的常用爬虫生态中的主流库,助你选对最合适的工具。
  • 反爬与实战:从简单的 User-Agent 伪装到代理 IP 池、验证码识别、分布式部署,多角度应对目标网站的各种反爬机制。

温馨提示

  1. 本教程示例均基于 Python 3.8+,强烈建议使用 Python 3.10 或更高版本来获得更好的兼容性与性能。
  2. 爬取网站数据时,请务必遵守目标网站的 robots.txt 以及相关法律法规,避免给他人服务器带来不必要的压力。
  3. 本文所列“最新库”信息截止到 2024 年底,2025 年及以后的新库、新特性请结合官方文档或社区资源进行补充。

2. 爬虫基础知识

2.1 什么是爬虫?

  • 定义:爬虫(Web Crawler,也称 Spider、Bot)是一种通过程序自动访问网页,并将其中有用信息提取下来存储的数据采集工具。
  • 原理简述:爬虫首先向指定 URL 发起 HTTP 请求,获取网页源代码(HTML、JSON、图片等),再通过解析技术(如 XPath、CSS 选择器、正则)从源码中提取所需数据,最后将数据保存到文件或数据库中。

2.2 爬虫的应用场景

  1. 数据分析:电商价格监控、商品评论分析、竞品调研。
  2. 舆情监控:社交媒体热搜、论坛帖子、新闻资讯统计。
  3. 搜索引擎:Google、Bing、Baidu 等搜索引擎通过爬虫定期抓取网页进行索引。
  4. 招聘信息采集:自动抓取招聘网站的岗位、薪资、公司信息。
  5. 学术研究:论文元数据爬取、知识图谱构建等。
  6. 内容聚合:如各类聚合网站把分散站点的文章集中到一个平台。

2.3 爬虫基本流程

  1. 确定目标 URL:明确要爬取的网页地址,可能是静态页面,也可能是动态加载。
  2. 发送 HTTP 请求:通常使用 requestshttpxaiohttp 等库向目标 URL 发送 GET、POST 请求,并获取响应。
  3. 解析响应内容:响应可能是 HTML、JSON、XML、图片等,常用解析工具有 BeautifulSoup、lxml、parsel、PyQuery、正则表达式等。
  4. 提取数据:根据标签名、属性、XPath、CSS Selector 等定位到目标内容,抽取文本或属性。
  5. 数据处理与存储:将提取到的内容清洗、去重,然后保存到 CSV、JSON、SQLite、MySQL、MongoDB 等介质中。
  6. 翻页/递归:如果需要多个页面的数据,就要分析翻页逻辑(URL 模板、Ajax 请求),循环执行请求与解析。
  7. 异常处理与反爬对策:设置代理、随机 User-Agent、限速、IP 轮换,处理 HTTP 403、验证码、重定向等。

2.4 需要注意的法律与伦理问题

  • 请求前务必查看目标站点的 robots.txt(通常在 https://example.com/robots.txt),遵从抓取规则;
  • 有些站点禁止大量抓取、禁止商业用途,在爬取前请阅读并遵守版权与隐私政策;
  • 不要对目标站点造成过大压力,建议设置合适的延时(time.sleep)、并发数限制;
  • 遵守爬虫与爬取数据后续处理相关法律法规,切勿用于违法用途。

3. 开发环境准备

3.1 安装 Python(建议 3.8 及以上)

  1. Windows

    • 前往 https://www.python.org/downloads 下载对应 3.8+ 的安装包,默认选中“Add Python 3.x to PATH”,点击“Install Now”。

    • 安装完成后,打开命令行(Win + R → 输入 cmd → 回车),执行:

      python --version
      pip --version
      

      确认 Python 与 pip 已成功安装。

  2. macOS

    • 建议使用 Homebrew 安装:

      brew install python@3.10
      
    • 安装完成后,执行:

      python3 --version
      pip3 --version
      

      确认无误后即可。

  3. Linux (Ubuntu/Debian 系)

    sudo apt update
    sudo apt install python3 python3-pip python3-venv -y
    

    执行:

    python3 --version
    pip3 --version
    

    即可确认。

提示:如果你机器上同时安装了 Python 2.x 和 Python 3.x,可能需要使用 python3pip3 来替代 pythonpip

3.2 创建虚拟环境并激活

为了避免全局依赖冲突,强烈建议为每个爬虫项目创建独立的虚拟环境:

# 进入项目根目录
mkdir my_spider && cd my_spider# 在项目目录下创建虚拟环境(python3 -m venv venv 或 python -m venv venv)
python3 -m venv venv# 激活虚拟环境
# Windows:
venv\Scripts\activate# macOS/Linux:
source venv/bin/activate

激活后,终端左侧会显示 (venv),此时安装的所有包都只作用于该环境。

3.3 常用开发工具推荐

  • IDE/编辑器

    • PyCharm Community / Professional:功能强大,集成测试、版本管理。
    • VS Code:轻量且插件丰富,适合快速编辑。
    • Sublime Text:轻量,启动快;对于小脚本很方便。
  • 调试工具

    • VS Code/PyCharm 自带的调试器,可以单步、断点调试。
    • 对于命令行脚本,也可以使用 pdb
  • 版本管理

    • Git + VS Code / PyCharm Git 插件,实现代码托管与协作。
    • 将项目托管到 GitHub/Gitee 等。
  • 其他辅助

    • Postman / Insomnia:用于模拟 HTTP 请求、查看响应头;
    • Charles / Fiddler:抓包工具,可调试 AJAX 请求、Cookie、headers 等。

4. 基础篇:用 Requests + BeautifulSoup 做简单爬虫

4.1 安装必要库

在虚拟环境中,执行:

pip install requests beautifulsoup4 lxml
  • requests:Python 最常用的 HTTP 库,用于发送 GET/POST 请求。
  • beautifulsoup4:常见的 HTML/XML 解析库,入门简单。
  • lxml:速度快、功能强大的解析器,供 BeautifulSoup 使用。

4.2 认识 HTTP 请求与响应

  • HTTP 请求:由方法(GET、POST、PUT 等)、URL、请求头(Headers)、请求体(Body)等组成。

  • HTTP 响应:包含状态码(200、404、500 等)、响应头、响应体(通常为 HTML、JSON、图片、文件等)。

  • Requests 常用参数

    • url:请求地址。
    • params:URL 参数(字典/字符串)。
    • headers:自定义请求头(例如 User-Agent、Referer、Cookie)。
    • data / json:POST 请求时发送的表单或 JSON 数据。
    • timeout:超时时间(秒),防止请求一直卡住。
    • proxies:配置代理(详见后文)。

示例:

import requestsurl = 'https://httpbin.org/get'
params = {'q': 'python 爬虫', 'page': 1}
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'
}response = requests.get(url, params=params, headers=headers, timeout=10)
print(response.status_code)        # 打印状态码,例如 200
print(response.encoding)          # 编码,例如 'utf-8'
print(response.text[:200])        # 前 200 字符

4.3 编写第一个爬虫:抓取网页标题

下面以爬取「https://www.example.com」网页标题为例,演示最简单的流程:

# file: simple_spider.pyimport requests
from bs4 import BeautifulSoupdef fetch_title(url):try:# 1. 发送 GET 请求headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'}response = requests.get(url, headers=headers, timeout=10)response.raise_for_status()  # 如果状态码不是 200,引发 HTTPError# 2. 设置正确的编码response.encoding = response.apparent_encoding# 3. 解析 HTMLsoup = BeautifulSoup(response.text, 'lxml')# 4. 提取 <title> 标签内容title_tag = soup.find('title')if title_tag:return title_tag.get_text().strip()else:return '未找到 title 标签'except Exception as e:return f'抓取失败:{e}'if __name__ == '__main__':url = 'https://www.example.com'title = fetch_title(url)print(f'网页标题:{title}')

运行结果示例

(venv) $ python simple_spider.py
网页标题:Example Domain

4.4 解析HTML:BeautifulSoup 用法详解

BeautifulSoup 库使用简单,常用方法如下:

  1. 创建对象

    soup = BeautifulSoup(html_text, 'lxml')  # 或 'html.parser'
    
  2. 查找单个节点

    • soup.find(tag_name, attrs={}, recursive=True, text=None, **kwargs)
    • 示例:soup.find('div', class_='content')
    • 可以使用 attrs={'class': 'foo', 'id': 'bar'} 精确定位。
  3. 查找所有节点

    • soup.find_all(tag_name, attrs={}, limit=None, **kwargs)
    • 示例:soup.find_all('a', href=True) 返回所有带 href 的链接。
  4. CSS 选择器

    • soup.select('div.content > ul li a'),返回列表。
    • 支持 id(#id)、class(.class)、属性([attr=value])等。
  5. 获取属性或文本

    • node.get('href'):拿属性值;
    • node['href']:同上,但如果属性不存在会抛异常;
    • node.get_text(strip=True):获取节点文本,并去除前后空白;
    • node.text:获取节点及子节点合并文本。
  6. 常用属性

    • soup.title / soup.title.string / soup.title.text
    • soup.body / soup.head / soup.a / soup.div 等快捷属性。
  7. 示例:提取列表页所有文章链接

    html = response.text
    soup = BeautifulSoup(html, 'lxml')
    # 假设每篇文章链接都在 <h2 class="post-title"><a href="...">...</a></h2>
    for h2 in soup.find_all('h2', class_='post-title'):a_tag = h2.find('a')title = a_tag.get_text(strip=True)link = a_tag['href']print(title, link)
    

4.5 文件存储:将抓到的数据保存为 CSV/JSON

  1. CSV 格式

    import csvdata = [{'title': '第一篇', 'url': 'https://...'},{'title': '第二篇', 'url': 'https://...'},# ...
    ]with open('result.csv', mode='w', newline='', encoding='utf-8-sig') as f:fieldnames = ['title', 'url']writer = csv.DictWriter(f, fieldnames=fieldnames)writer.writeheader()for item in data:writer.writerow(item)
    
    • encoding='utf-8-sig' 能兼容 Excel 打开时不出现乱码。
  2. JSON 格式

    import jsondata = [{'title': '第一篇', 'url': 'https://...'},{'title': '第二篇', 'url': 'https://...'},# ...
    ]with open('result.json', 'w', encoding='utf-8') as f:json.dump(data, f, ensure_ascii=False, indent=4)
    
  3. SQLite 存储(适合小规模项目)

    import sqlite3conn = sqlite3.connect('spider.db')
    cursor = conn.cursor()
    # 创建表(如果不存在)
    cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT,url TEXT UNIQUE);
    ''')
    # 插入数据
    items = [('第一篇', 'https://...'),('第二篇', 'https://...'),
    ]
    for title, url in items:try:cursor.execute('INSERT INTO articles (title, url) VALUES (?, ?)', (title, url))except sqlite3.IntegrityError:pass  # URL 已存在就跳过
    conn.commit()
    conn.close()
    

4.6 常见反爬措施及应对策略

  1. User-Agent 检测

    • 默认 requests 的 User-Agent 大多被识别为“爬虫”,容易被屏蔽。
    • 应用:在请求头中随机选用常见浏览器 User-Agent。
    import randomUSER_AGENTS = ['Mozilla/5.0 ... Chrome/100.0.4896.127 ...','Mozilla/5.0 ... Firefox/110.0 ...','Mozilla/5.0 ... Safari/605.1.15 ...',# 更多可从网上获取
    ]
    headers = {'User-Agent': random.choice(USER_AGENTS)}
    response = requests.get(url, headers=headers)
    
  2. IP 限制

    • 如果同一 IP 在短时间内发起大量请求,服务器可能会封禁或返回 403。
    • 应对:使用代理池(详见第 11 节),定期更换 IP。
  3. Cookie 验证

    • 某些网站登录后才能访问完整内容,需要先模拟登录获取 Cookie,再在后续请求中带上。
    • requests.Session() 管理会话,同一 Session 自动保存并发送 Cookie。
    import requestssession = requests.Session()
    login_data = {'username': 'xxx', 'password': 'xxx'}
    session.post('https://example.com/login', data=login_data)
    # 登录成功后,session 自动保存了 Cookie
    response = session.get('https://example.com/protected-page')
    
  4. 验证码

    • 简易验证码有时可通过 OCR 自动识别,但复杂图片验证码需要专门打码平台或人工识别。
    • 在入门阶段,尽量选择不需要验证码或抢先获取 API。
  5. AJAX / 动态渲染

    • 如果页面数据是通过 JavaScript 动态加载,直接用 requests 只能获取静态 HTML。
    • 应用:可分析 AJAX 请求接口(Network 面板),直接请求接口返回的 JSON;或使用浏览器自动化工具(Selenium/Playwright)模拟浏览器渲染。

5. 进阶篇:更强大的解析工具

虽然 BeautifulSoup 足以应付大部分新手场景,但当你遇到结构复杂、嵌套多、或需要批量高效提取时,下面这些工具会更适合。

5.1 lxml (XPath)

  • 特点:基于 C 语言实现,解析速度快,支持标准的 XPath 查询。

  • 安装

    pip install lxml
    
  • 示例

    from lxml import etreehtml = '''<html><body><div class="post"><h2><a href="/p1">文章A</a></h2></div><div class="post"><h2><a href="/p2">文章B</a></h2></div>
    </body></html>'''# 1. 将文本转换为 Element 对象
    tree = etree.HTML(html)# 2. 使用 XPath 语法提取所有链接文本和 href
    titles = tree.xpath('//div[@class="post"]/h2/a/text()')
    links = tree.xpath('//div[@class="post"]/h2/a/@href')for t, l in zip(titles, links):print(t, l)
    # 输出:
    # 文章A /p1
    # 文章B /p2
    
  • 常见 XPath 语法

    • //tag[@attr="value"]:查找所有符合条件的 tag。
    • text():获取文本节点;
    • @href:获取属性值;
    • //div//a:查找 div 下所有后代中的 a;
    • //ul/li[1]:查找第一个 li;
    • contains(@class, "foo"):class 中包含 foo 的元素。

5.2 parsel(Scrapy 内置的解析器)

  • 特点:Scrapy 自带的一套基于 Css/XPath 的快速解析工具,接口与 lxml 类似,但更贴合 Scrapy 的数据提取习惯。

  • 安装

    pip install parsel
    
  • 示例

    from parsel import Selectorhtml = '''<ul><li class="item"><a href="/a1">Item1</a></li><li class="item"><a href="/a2">Item2</a></li>
    </ul>'''sel = Selector(text=html)
    # 使用 CSS 选择器
    for item in sel.css('li.item'):title = item.css('a::text').get()link = item.css('a::attr(href)').get()print(title, link)
    # 使用 XPath
    for item in sel.xpath('//li[@class="item"]'):title = item.xpath('./a/text()').get()link = item.xpath('./a/@href').get()print(title, link)
    
  • parsel.Selector 对象在 Scrapy 中经常用到,直接拿过来在项目外部也能用。

5.3 PyQuery(类似 jQuery 的解析方式)

  • 特点:接口风格类似 jQuery,习惯了前端的同学会很快上手。

  • 安装

    pip install pyquery
    
  • 示例

    from pyquery import PyQuery as pqhtml = '''<div id="posts"><h2><a href="/x1">新闻X1</a></h2><h2><a href="/x2">新闻X2</a></h2>
    </div>'''doc = pq(html)
    # 通过标签/ID/css 选择器定位
    for item in doc('#posts h2'):# item 是 lxml 的 Element,需要再次包装a = pq(item).find('a')title = a.text()url = a.attr('href')print(title, url)
    
  • PyQuery 内部使用 lxml 作为解析器,速度不逊于直接调用 lxml。

5.4 正则表达式在爬虫中的应用

  • 正则并不是万能的 HTML 解析方案,但在提取简单规则(如邮箱、电话号码、特定模式字符串)时非常方便。

  • 在爬虫中,可先用 BeautifulSoup/lxml 找到相应的大块内容,再对内容字符串用正则提取。

  • 示例

    import re
    from bs4 import BeautifulSouphtml = '''<div class="info">联系邮箱:abc@example.com联系电话:123-4567-890
    </div>'''soup = BeautifulSoup(html, 'lxml')
    info = soup.find('div', class_='info').get_text()# 匹配邮箱
    email_pattern = r'[\w\.-]+@[\w\.-]+'
    emails = re.findall(email_pattern, info)
    print('邮箱:', emails)# 匹配电话号码
    phone_pattern = r'\d{3}-\d{4}-\d{3,4}'
    phones = re.findall(phone_pattern, info)
    print('电话:', phones)
    

6. 框架篇:Scrapy 全面入门

如果你想快速搭建一个可维护、可扩展的爬虫项目,Scrapy 是 Python 爬虫生态中最成熟、最流行的爬虫框架之一。

6.1 Scrapy 简介

  • Scrapy:一个专门为大规模网络爬取与信息提取设计的开源框架,具有高性能、多并发、支持分布式、内置各种中间件与管道。

  • 适用场景

    • 大规模爬取同类型大量网页。
    • 对页面进行复杂数据清洗、去重、存储。
    • 需要高度定制化中间件或扩展时。

6.2 安装与项目结构

  1. 安装 Scrapy:

    pip install scrapy
    
  2. 创建 Scrapy 项目:

    scrapy startproject myproject
    
  3. 项目目录结构(示例):

    myproject/scrapy.cfg            # 部署时使用的配置文件myproject/            # 项目 Python 模块__init__.pyitems.py          # 定义数据模型(Item)middlewares.py    # 自定义中间件pipelines.py      # 数据处理与存储 Pipelinesettings.py       # Scrapy 全局配置spiders/          # 各种爬虫文件放在这里__init__.pyexample_spider.py
    

6.3 编写第一个 Scrapy 爬虫 Spider

假设我们要爬去 quotes.toscrape.com 网站上所有名言及作者:

  1. myproject/spiders/ 下新建 quotes_spider.py

    import scrapy
    from myproject.items import MyprojectItemclass QuotesSpider(scrapy.Spider):name = 'quotes'  # 爬虫名,运行时指定allowed_domains = ['quotes.toscrape.com']start_urls = ['https://quotes.toscrape.com/']def parse(self, response):# 提取每个名言块for quote in response.css('div.quote'):item = MyprojectItem()item['text'] = quote.css('span.text::text').get()item['author'] = quote.css('small.author::text').get()item['tags'] = quote.css('div.tags a.tag::text').getall()yield item# 翻页:获取下一页链接并递归next_page = response.css('li.next a::attr(href)').get()if next_page:yield response.follow(next_page, callback=self.parse)
    
  2. 定义 Item 模型 (myproject/items.py):

    import scrapyclass MyprojectItem(scrapy.Item):text = scrapy.Field()author = scrapy.Field()tags = scrapy.Field()
    
  3. 配置数据存储 Pipeline(可选存储到 JSON/CSV/数据库),如在 myproject/pipelines.py

    import jsonclass JsonWriterPipeline:def open_spider(self, spider):self.file = open('quotes.json', 'w', encoding='utf-8')self.file.write('[\n')def close_spider(self, spider):self.file.write('\n]')self.file.close()def process_item(self, item, spider):line = json.dumps(dict(item), ensure_ascii=False)self.file.write(line + ',\n')return item
    

    并在 settings.py 中启用:

    ITEM_PIPELINES = {'myproject.pipelines.JsonWriterPipeline': 300,
    }
    
  4. 运行爬虫:

    scrapy crawl quotes
    

    运行后,会在项目根目录生成 quotes.json,其中包含抓取到的所有名言数据。

6.4 Item、Pipeline、Settings 详解

  • Items (items.py):定义要提取的数据结构与字段,相当于“数据模型”。
  • Spiders (spiders/xxx.py):每个 spider 文件对应一个任务,可接收 start_urlsallowed_domainsparse() 回调等。可自定义不同的回调函数来解析不同页面。
  • Pipelines (pipelines.py):处理从 Spider 返回的 Item,常见操作包括数据清洗(去重、格式化)、存储(写入 JSON/CSV、入库)、下载附件等。
  • Settings (settings.py):全局配置文件,包含并发数(CONCURRENT_REQUESTS)、下载延时(DOWNLOAD_DELAY)、中间件配置、管道配置、User-Agent 等。

常见 Settings 配置示例:

# settings.py(只列部分)  
BOT_NAME = 'myproject'SPIDER_MODULES = ['myproject.spiders']
NEWSPIDER_MODULE = 'myproject.spiders'# 遵循 robots 协议
ROBOTSTXT_OBEY = True# 并发请求数(默认 16)
CONCURRENT_REQUESTS = 8# 下载延时(秒),防止对目标站造成过大压力
DOWNLOAD_DELAY = 1# 配置 User-Agent
DEFAULT_REQUEST_HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
}# 启用 Pipeline
ITEM_PIPELINES = {'myproject.pipelines.JsonWriterPipeline': 300,
}# 启用或禁用中间件、扩展、管道等
DOWNLOADER_MIDDLEWARES = {# 'myproject.middlewares.SomeDownloaderMiddleware': 543,
}# 日志等级
LOG_LEVEL = 'INFO'

6.5 Scrapy Shell 在线调试

  • Scrapy 提供了 scrapy shell <URL> 命令,可以快速测试 XPath、CSS 选择器。

    scrapy shell 'https://quotes.toscrape.com/'
    
  • 进入 shell 后,你可以执行:

    >>> response.status
    200
    >>> response.css('div.quote span.text::text').getall()
    ['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', ...]
    >>> response.xpath('//div[@class="quote"]/span[@class="text"]/text()').getall()
    
  • Shell 模式下,你可以快速试错、验证提取逻辑,比写完整 Spider 再跑要高效很多。

6.6 分布式与多线程:Scrapy 爬虫并发配置

  • 并发请求数:在 settings.py 中设置 CONCURRENT_REQUESTS(默认 16);
  • 单域名并发CONCURRENT_REQUESTS_PER_DOMAIN(默认 8);
  • 单 IP 并发CONCURRENT_REQUESTS_PER_IP
  • 下载延时DOWNLOAD_DELAY(默认 0);
  • 自动限速AUTOTHROTTLE_ENABLED = True,配合 AUTOTHROTTLE_START_DELAYAUTOTHROTTLE_MAX_DELAY 等。
  • 并行请求:Scrapy 内部使用 Twisted 异步网络库实现高并发,单机即可轻松处理成千上万请求。

6.7 Scrapy 中间件与扩展(Downloader Middleware、Downloader Handler)

  • Downloader Middleware:位于 Scrapy 引擎与下载器之间,可控制请求/响应,常用于:

    • 动态设置 User-Agent、Proxy;
    • 拦截并修改请求/响应头;
    • 处理重试(Retry)、重定向(Redirect)等。
  • 示例:随机 User-Agent Middleware

    # myproject/middlewares.pyimport random
    from scrapy import signalsclass RandomUserAgentMiddleware:def __init__(self, user_agents):self.user_agents = user_agents@classmethoddef from_crawler(cls, crawler):return cls(user_agents=crawler.settings.get('USER_AGENTS_LIST'))def process_request(self, request, spider):ua = random.choice(self.user_agents)request.headers.setdefault('User-Agent', ua)
    

    并在 settings.py 中配置:

    USER_AGENTS_LIST = ['Mozilla/5.0 ... Chrome/100.0 ...','Mozilla/5.0 ... Firefox/110.0 ...',# 更多 User-Agent
    ]DOWNLOADER_MIDDLEWARES = {'myproject.middlewares.RandomUserAgentMiddleware': 400,'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    }
    
  • Downloader Handler:更底层的接口,一般不常用,Scrapy 已提供 HttpDownloadHandlerS3DownloadHandler 等。


7. 动态内容爬取:Selenium 与 Playwright

当目标网页内容依赖 JavaScript 动态渲染时,单纯用 requests 或 Scrapy 获取到的 HTML 往往不包含最终可视化的数据。此时可以使用“浏览器自动化”工具,让其像真实浏览器一样加载页面,再提取渲染后的内容。

7.1 为什么需要浏览器自动化?

  • 许多现代网站(尤其是单页应用 SPA)使用 React、Vue、Angular 等框架,通过 AJAX 或 API 获取数据并在前端渲染,直接请求 URL 只能拿到空白或框架代码。

  • 浏览器自动化可以:

    1. 启动一个真实或无头浏览器实例;
    2. 访问页面,等待 JavaScript 执行完成;
    3. 拿到渲染完毕的 DOM,然后再用解析库提取。

7.2 Selenium 基础用法

  1. 安装

    pip install selenium
    
  2. 下载 WebDriver(以 Chrome 为例):

    • 前往 ChromeDriver 下载页面 ,下载与本地 Chrome 版本相匹配的 chromedriver
    • chromedriver 放置在系统 PATH 下,或在代码中指定路径。
  3. 示例:抓取动态网页内容

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service as ChromeService
    from selenium.webdriver.common.by import By
    from selenium.webdriver.chrome.options import Options
    import time# 1. 配置 Chrome 选项
    chrome_options = Options()
    chrome_options.add_argument('--headless')  # 无界面模式
    chrome_options.add_argument('--no-sandbox')
    chrome_options.add_argument('--disable-gpu')# 2. 指定 chromedriver 路径或直接放到 PATH 中
    service = ChromeService(executable_path='path/to/chromedriver')# 3. 创建 WebDriver
    driver = webdriver.Chrome(service=service, options=chrome_options)try:# 4. 打开页面driver.get('https://quotes.toscrape.com/js/')  # 这是一个 JavaScript 渲染的示例# 5. 等待 JS 渲染,最简单的方式:time.sleep(建议改用显式/隐式等待)time.sleep(2)# 6. 提取渲染后的 HTMLhtml = driver.page_source# 7. 交给 BeautifulSoup 或 lxml 解析from bs4 import BeautifulSoupsoup = BeautifulSoup(html, 'lxml')for quote in soup.css('div.quote'):text = quote.find('span', class_='text').get_text()author = quote.find('small', class_='author').get_text()print(text, author)
    finally:driver.quit()
    
  4. 显式等待与隐式等待

    • 隐式等待driver.implicitly_wait(10),在寻找元素时最长等待 10 秒;

    • 显式等待:使用 WebDriverWaitExpectedConditions,例如:

      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as ECelement = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.quote'))
      )
      

7.3 Playwright for Python(更快更轻量)

  • Playwright:由微软维护、继承自 Puppeteer 的跨浏览器自动化库,支持 Chromium、Firefox、WebKit,无需单独下载 WebDriver。

  • 优点:启动速度快、API 简洁、并发控制更灵活。

  • 安装

    pip install playwright
    # 安装浏览器内核(只需第一次执行)
    playwright install
    
  • 示例:抓取动态内容

    import asyncio
    from playwright.async_api import async_playwright
    from bs4 import BeautifulSoupasync def main():async with async_playwright() as p:browser = await p.chromium.launch(headless=True)page = await browser.new_page()await page.goto('https://quotes.toscrape.com/js/')# 可选:等待某个元素加载完成await page.wait_for_selector('div.quote')content = await page.content()  # 获取渲染后的 HTMLawait browser.close()# 交给 BeautifulSoup 解析soup = BeautifulSoup(content, 'lxml')for quote in soup.select('div.quote'):text = quote.select_one('span.text').get_text()author = quote.select_one('small.author').get_text()print(text, author)if __name__ == '__main__':asyncio.run(main())
    
  • 同步版 Playwright
    如果你不想使用异步,也可以借助 sync_api

    from playwright.sync_api import sync_playwright
    from bs4 import BeautifulSoupdef main():with sync_playwright() as p:browser = p.chromium.launch(headless=True)page = browser.new_page()page.goto('https://quotes.toscrape.com/js/')page.wait_for_selector('div.quote')html = page.content()browser.close()soup = BeautifulSoup(html, 'lxml')for quote in soup.select('div.quote'):text = quote.select_one('span.text').get_text()author = quote.select_one('small.author').get_text()print(text, author)if __name__ == '__main__':main()
    

7.4 无头浏览器(headless)模式及性能优化

  • 无头模式:在 Linux 服务器等环境下,没有图形界面,需要 --headless 参数;在 macOS/Windows 上也可加速启动。

  • 资源限制:可以通过设置启动参数降低资源占用,如:

    • Chrome:chrome_options.add_argument('--disable-gpu')--no-sandbox--disable-dev-shm-usage
    • Playwright:browser = await p.chromium.launch(headless=True, args=['--disable-gpu', '--no-sandbox'])
  • 避免过度渲染:如果只想拿纯数据,尽量通过分析接口(XHR 请求)直接调用后台 API,不必启动完整浏览器。

7.5 结合 Selenium/Playwright 与 BeautifulSoup 解析

一般流程:

  1. 用 Selenium/Playwright 拿到渲染后的 page_sourcecontent()
  2. 用 BeautifulSoup/lxml 对 HTML 进行二次解析与提取。

示例综合:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoupchrome_options = Options()
chrome_options.add_argument('--headless')
service = ChromeService('path/to/chromedriver')
driver = webdriver.Chrome(service=service, options=chrome_options)try:driver.get('https://example.com/dynamic-page')driver.implicitly_wait(5)html = driver.page_sourcesoup = BeautifulSoup(html, 'lxml')# 根据解析需求提取数据for item in soup.select('div.article'):title = item.select_one('h1').get_text()content = item.select_one('div.content').get_text(strip=True)print(title, content)
finally:driver.quit()

8. 异步爬虫:aiohttp + asyncio 与 HTTPX

当面对上千个、甚至上万个链接需要同时抓取时,同步阻塞式的 requests 就显得效率低下。Python 原生的 asyncio 协程、aiohttp 库或 httpx 异步模式可以极大提升并发性能。

8.1 同步 vs 异步:性能原理简述

  • 同步(Blocking):一次请求完毕后才开始下一次请求。
  • 异步(Non-Blocking):发出请求后可立即切换到其他任务,网络 I/O 等待期间不阻塞线程。
  • 对于 I/O 密集型爬虫,异步能显著提高吞吐量。

8.2 aiohttp 入门示例

  1. 安装

    pip install aiohttp
    
  2. 使用 asyncio + aiohttp 并发抓取

    import asyncio
    import aiohttp
    from bs4 import BeautifulSoupasync def fetch(session, url):try:async with session.get(url, timeout=10) as response:text = await response.text()return textexcept Exception as e:print(f'抓取 {url} 失败:{e}')return Noneasync def parse(html, url):if not html:returnsoup = BeautifulSoup(html, 'lxml')title = soup.find('title').get_text(strip=True) if soup.find('title') else 'N/A'print(f'URL: {url},Title: {title}')async def main(urls):# connector 限制最大并发数,防止打开过多 TCP 连接conn = aiohttp.TCPConnector(limit=50)async with aiohttp.ClientSession(connector=conn) as session:tasks = []for url in urls:task = asyncio.create_task(fetch(session, url))tasks.append(task)# gather 等待所有 fetch 完成htmls = await asyncio.gather(*tasks)# 逐一解析for html, url in zip(htmls, urls):await parse(html, url)if __name__ == '__main__':urls = [f'https://example.com/page/{i}' for i in range(1, 101)]asyncio.run(main(urls))
    
  3. 说明

    • aiohttp.TCPConnector(limit=50) 将并发连接限制在 50,避免短时间打开过多连接被服务器封。
    • asyncio.create_task 创建并发 Task,交由事件循环调度。
    • await asyncio.gather(*) 等待所有任务完成。

8.3 使用 asyncio 协程池提高并发

如果需要对抓取和解析做更精细的并行控制,可使用 asyncio.Semaphore 或第三方协程池库(如 aiomultiprocess、aiojobs)来控制并发数。

import asyncio
import aiohttp
from bs4 import BeautifulSoupsemaphore = asyncio.Semaphore(20)  # 最多同时跑 20 个协程async def fetch_with_sem(session, url):async with semaphore:try:async with session.get(url, timeout=10) as resp:return await resp.text()except Exception as e:print(f'Error fetching {url}: {e}')return Noneasync def main(urls):async with aiohttp.ClientSession() as session:tasks = [asyncio.create_task(fetch_with_sem(session, url)) for url in urls]results = await asyncio.gather(*tasks)for html, url in zip(results, urls):if html:title = BeautifulSoup(html, 'lxml').find('title').get_text(strip=True)print(url, title)if __name__ == '__main__':sample_urls = [f'https://example.com/page/{i}' for i in range(1, 51)]asyncio.run(main(sample_urls))

8.4 HTTPX:Requests 的异步升级版

  • HTTPX:由 Encode 团队开发,与 requests API 十分相似,同时支持同步与异步模式。

  • 安装

    pip install httpx
    
  • 示例

    import asyncio
    import httpx
    from bs4 import BeautifulSoupasync def fetch(client, url):try:resp = await client.get(url, timeout=10.0)resp.raise_for_status()return resp.textexcept Exception as e:print(f'Error {url}: {e}')return Noneasync def main(urls):async with httpx.AsyncClient(limits=httpx.Limits(max_connections=50)) as client:tasks = [asyncio.create_task(fetch(client, url)) for url in urls]for coro in asyncio.as_completed(tasks):html = await coroif html:title = BeautifulSoup(html, 'lxml').find('title').get_text(strip=True)print('Title:', title)if __name__ == '__main__':urls = [f'https://example.com/page/{i}' for i in range(1, 101)]asyncio.run(main(urls))
    
  • requests 兼容的 API(如 .get().post().json().text 等),极大降低了上手门槛。

8.5 异步下使用解析库示例(aiohttp + lxml)

import asyncio
import aiohttp
from lxml import etreeasync def fetch_and_parse(session, url):try:async with session.get(url, timeout=10) as resp:text = await resp.text()tree = etree.HTML(text)# 提取第一条消息msg = tree.xpath('//div[@class="msg"]/text()')print(url, msg)except Exception as e:print(f'Error fetching {url}: {e}')async def main(urls):conn = aiohttp.TCPConnector(limit=30)async with aiohttp.ClientSession(connector=conn) as session:tasks = [fetch_and_parse(session, url) for url in urls]await asyncio.gather(*tasks)if __name__ == '__main__':url_list = [f'https://example.com/messages/{i}' for i in range(1, 51)]asyncio.run(main(url_list))

9. 数据存储与去重

爬虫的最终目的是获取并存储有价值的数据,因此选择合适的存储方式与去重机制至关重要。

9.1 本地文件:CSV、JSON、SQLite

  1. CSV/JSON

    • 适合一次性、容量较小、对数据结构要求不高的场景。
    • 直接用 Python 标准库即可读写。
  2. SQLite

    • 轻量级嵌入式数据库,无需额外部署数据库服务器。

    • 适合中小规模项目,比如几万条数据。

    • 示例:

      import sqlite3conn = sqlite3.connect('data.db')
      cursor = conn.cursor()
      cursor.execute('CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, title TEXT, url TEXT UNIQUE)')
      data = [('标题1', 'https://a.com/1'), ('标题2', 'https://a.com/2')]
      for title, url in data:try:cursor.execute('INSERT INTO items (title, url) VALUES (?, ?)', (title, url))except sqlite3.IntegrityError:pass  # 去重
      conn.commit()
      conn.close()
      

9.2 MySQL/PostgreSQL 等关系型数据库

  • 优点:适合大规模数据存储,支持 SQL 强大的查询功能,能更好地做数据分析、统计。

  • 安装:先安装对应数据库服务器(MySQL、MariaDB、PostgreSQL),然后在 Python 中安装驱动:

    pip install pymysql  # MySQL
    pip install psycopg2 # PostgreSQL
    
  • 示例(MySQL)

    import pymysqlconn = pymysql.connect(host='localhost', user='root', password='root', db='spider_db', charset='utf8mb4')
    cursor = conn.cursor()
    cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255),url VARCHAR(255) UNIQUE) CHARACTER SET utf8mb4;
    ''')
    data = [('标题1', 'https://a.com/1'), ('标题2', 'https://a.com/2')]
    for title, url in data:try:cursor.execute('INSERT INTO articles (title, url) VALUES (%s, %s)', (title, url))except pymysql.err.IntegrityError:pass
    conn.commit()
    conn.close()
    

9.3 MongoDB 等 NoSQL 存储

  • 优点:文档型数据库,对半结构化 JSON 数据支持友好,可灵活存储字段不同的条目。

  • 安装与驱动

    • 本地安装 MongoDB 或使用云服务;
    • Python 驱动:pip install pymongo
  • 示例

    from pymongo import MongoClientclient = MongoClient('mongodb://localhost:27017/')
    db = client['spider_db']
    collection = db['articles']
    # 插入或更新(去重依据:url)
    data = {'title': '标题1', 'url': 'https://a.com/1', 'tags': ['新闻', '推荐']}
    collection.update_one({'url': data['url']}, {'$set': data}, upsert=True)
    

9.4 Redis 用作去重与短期缓存

  • Redis:键值存储,支持超高并发访问,非常适合做指纹去重、短期缓存、队列等。

  • 常见策略

    1. 布隆过滤器(Bloom Filter):当 URL 数量达到数百万级别时,普通 Python 集合会占用大量内存,布隆过滤器用空间换时间,以极少内存判断某个 URL 是否已爬取(有一定误判率)。可以使用 pybloom-live 或直接在 Redis 中搭建 Bloom Filter(如 RedisBloom 模块)。
    2. Redis Set:小规模去重可直接用 Redis set 存储已爬 URL。
    import redisr = redis.Redis(host='localhost', port=6379, db=0)
    url = 'https://example.com/page/1'
    # 尝试添加到 set,返回 1 表示新添加,返回 0 表示已存在
    if r.sadd('visited_urls', url):print('新 URL,可爬取')
    else:print('URL 已存在,跳过')
    

9.5 去重策略:指纹、哈希、Bloom Filter

  • 指纹:通常对 URL 做标准化(去掉排序不同但内容相同的参数、多余的斜杠),然后对标准化后 URL 做哈希(如 MD5、SHA1),存到 Set 中对比。

  • Bloom Filter:一种以极少内存做到高效去重的概率算法,对大规模 URL 判断去重十分划算,但有极小误判率(可能会把未访问的 URL 误判为已访问)。

  • 库推荐

    • pybloom-live:纯 Python 布隆过滤器库;
    • redis-py-bloom 或 Redis 官方 RedisBloom 模块(需 Redis 安装相应扩展);
    • Scrapy 内置 scrapy.dupefilters.RFPDupeFilter,默认用的是文件或 Redis 存储的指纹去重。

10. 分布式爬虫:Scrapy-Redis 与分布式调度

当单机爬虫难以满足高并发、大规模抓取时,就需要分布式爬虫,将任务分布到多台机器协同完成。Scrapy-Redis 是 Scrapy 官方推荐的分布式方案之一。

10.1 为什么要做分布式?

  • 海量链接:需要抓取数百万、上亿条 URL 时,单机进程/线程或协程都难以在可接受时间内完成。
  • 速度要求:需要更短时间内获取全量数据,提高爬取速度。
  • 容错与扩展:分布式部署可实现节点增减、机器故障自愈等。

10.2 Scrapy-Redis 简介与安装

  • Scrapy-Redis:基于 Redis 存储队列与去重指纹,实现分布式调度、分布式去重、数据共享的 Scrapy 扩展。

  • 安装

    pip install scrapy-redis
    

10.3 分布式去重队列与调度

  1. 在 Scrapy 项目中集成 Scrapy-Redis

    • 修改 settings.py

      # settings.py
      # 使用 redis 作为调度器
      SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      # 每次爬虫重启时是否继续未爬取完的爬取队列
      SCHEDULER_PERSIST = True
      # 使用 redis 去重(替换默认的 RFPDupeFilter)
      DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      # 指定 redis 链接地址
      REDIS_URL = 'redis://:password@127.0.0.1:6379/0'
      # 将 item 存入 redis 由其他进程或管道处理
      ITEM_PIPELINES = {'scrapy_redis.pipelines.RedisPipeline': 300
      }
      # 指定用来存储队列的 redis key 前缀
      REDIS_ITEMS_KEY = '%(spider)s:items'
      REDIS_START_URLS_KEY = '%(name)s:start_urls'
      
  2. 修改 Spider

    • 继承 scrapy_redis.spiders.RedisSpiderRedisCrawlSpider,将原本的 start_urls 替换为从 Redis 队列中获取种子 URL。
    # myproject/spiders/redis_quotes.pyfrom scrapy_redis.spiders import RedisSpider
    from myproject.items import MyprojectItemclass RedisQuotesSpider(RedisSpider):name = 'redis_quotes'# Redis 中存放 start_urls 的 keyredis_key = 'redis_quotes:start_urls'def parse(self, response):for quote in response.css('div.quote'):item = MyprojectItem()item['text'] = quote.css('span.text::text').get()item['author'] = quote.css('small.author::text').get()item['tags'] = quote.css('div.tags a.tag::text').getall()yield itemnext_page = response.css('li.next a::attr(href)').get()if next_page:yield response.follow(next_page, callback=self.parse)
    
  3. 将种子 URL 推入 Redis

    • 在本地或远程机器上,用 redis-cli 将种子 URL 推入列表:

      redis-cli
      lpush redis_quotes:start_urls "https://quotes.toscrape.com/"
      
  4. 启动分布式爬虫

    • 在多台服务器或多终端分别启动爬虫:

      scrapy crawl redis_quotes
      
    • 所有实例会从同一个 Redis 队列中获取 URL,去重也基于 Redis,互不重复。

10.4 多机协作示例

  1. 部署多台服务器(A、B、C),都能访问同一个 Redis 实例。

  2. 在 A 机上运行:

    redis-server  # 启动 Redis(可独立部署)
    
  3. 在 A、B、C 机上,各自拉取完整的 Scrapy 项目代码,并配置好 settings.py 中的 REDIS_URL

  4. 在 A 机或任意一处,将种子 URL 塞入 Redis:

    redis-cli -h A_ip -p 6379 lpush redis_quotes:start_urls "https://quotes.toscrape.com/"
    
  5. 在 A、B、C 分别运行:

    scrapy crawl redis_quotes
    
    • 三台机器会自动协调,每台都从 Redis 队列中取 URL,去重也由 Redis 统一维护。
  6. 数据收集:

    • 爬取的 Item 通过 RedisPipeline 自动存入 Redis 列表(key: quotes:items);
    • 之后可通过独立脚本或 pipeline 再将数据持久化到数据库/文件。

11. 常见反爬与反制策略

11.1 频率限制与请求头伪装

  1. 访问频率控制(限速)

    • 对目标站设置随机或固定延时:

      import time, random
      time.sleep(random.uniform(1, 3))  # 随机等待 1~3 秒
      
    • Scrapy 中使用 DOWNLOAD_DELAYAUTOTHROTTLE_ENABLED 等。

  2. User-Agent 伪装

    • 通过随机 User-Agent 模拟不同浏览器。
    • 代码示例见第 4.6 节。
  3. Referer、Accept-Language、Accept-Encoding 等 Headers

    • 模拟真实浏览器请求时携带的完整 Header:

      headers = {'User-Agent': 'Mozilla/5.0 ...','Referer': 'https://example.com/','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8','Accept-Encoding': 'gzip, deflate, br',# 如有需要,可带上 Cookie'Cookie': 'sessionid=xxx; other=yyy',
      }
      response = requests.get(url, headers=headers)
      

11.2 登录验证与 Cookie 管理

  • Session 对象:在 requests 中,使用 requests.Session() 方便统一管理 Cookie。

  • 模拟登录流程

    1. 获取登录页 GET 请求,拿到隐藏的 token(如 CSRF);
    2. 结合用户名/密码、token,POST 到登录接口;
    3. 成功后,session 内部有了 Cookie,后续使用同一 session 发起请求即可保持登录状态。
  • 带 Cookie 抓取

    session = requests.Session()
    # 第一次请求,拿到 CSRF Token
    login_page = session.get('https://example.com/login')
    # 用 BeautifulSoup 解析隐藏 token
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(login_page.text, 'lxml')
    token = soup.find('input', {'name': 'csrf_token'})['value']# 构造登录表单
    data = {'username': 'yourname','password': 'yourpwd','csrf_token': token
    }
    # 登录
    session.post('https://example.com/login', data=data, headers={'User-Agent': '...'})
    # 登录成功后用 session 继续抓取需要登录才能访问的页面
    profile = session.get('https://example.com/profile')
    print(profile.text)
    

11.3 验证码识别(简单介绍)

  • 常见验证码类型

    • 验证码图片(扭曲字母/数字);
    • 滑动验证码(拼图/拖动)
    • 点选验证码(选特定图像)
    • 行为生物特征(人机验证)
  • 常用方案

    1. 简单 OCR 识别:用 pytesseract 对简单数字/字母验证码进行识别,但对扭曲度高或干扰线多的验证码成功率不高。

      pip install pytesseract pillow
      
      from PIL import Image
      import pytesseractimg = Image.open('captcha.png')
      text = pytesseract.image_to_string(img).strip()
      print('识别结果:', text)
      
    2. 打码平台/人工打码:当验证码过于复杂时,可调用第三方打码平台 API(如超级鹰、打码兔等),将图片发送给平台,由平台返回识别结果;或者简单地由人工识别。

    3. 绕过/获取接口:很多网站的登录并不真用验证码进行提交,而是在前端校验。可以抓包找到真实的登录接口,模拟接口请求,绕过验证码。

11.4 代理 IP 池的搭建与旋转

  1. 为什么要用代理

    • 同一 IP 短时间内请求次数过多容易被封禁;使用代理 IP 池可以不断切换 IP,降低单 IP 请求频率。
  2. 获取代理

    • 免费代理:网上公开的免费代理 IP,但一般不稳定、易失效。可用爬虫定期从免费代理网站(如 xicidaili、kuaidaili)抓取可用代理,并验证可用性。
    • 付费代理:阿布云、快代理等付费代理服务,更稳定、更安全。
  3. 搭建本地简单代理池示例(以免费代理为例,仅供学习)

    import requests
    from lxml import etree
    import random
    import timedef fetch_free_proxies():url = 'https://www.kuaidaili.com/free/inha/1/'headers = {'User-Agent': 'Mozilla/5.0 ...'}resp = requests.get(url, headers=headers)tree = etree.HTML(resp.text)proxies = []for row in tree.xpath('//table//tr')[1:]:ip = row.xpath('./td[1]/text()')[0]port = row.xpath('./td[2]/text()')[0]proxy = f'http://{ip}:{port}'# 简单校验try:r = requests.get('https://httpbin.org/ip', proxies={'http': proxy, 'https': proxy}, timeout=3)if r.status_code == 200:proxies.append(proxy)except:continuereturn proxiesdef get_random_proxy(proxies):return random.choice(proxies) if proxies else Noneif __name__ == '__main__':proxy_list = fetch_free_proxies()print('可用代理:', proxy_list)# 实际爬虫中使用示例:proxy = get_random_proxy(proxy_list)if proxy:resp = requests.get('https://example.com', proxies={'http': proxy, 'https': proxy}, timeout=10)print(resp.status_code)
    
  4. 在 Scrapy 中配置代理

    • 简单在 settings.py 中设置:

      # settings.py
      # 下载中间件(若自定义 proxy pool、user-agent,则参照上文中间件示例)
      DOWNLOADER_MIDDLEWARES = {'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,'myproject.middlewares.RandomProxyMiddleware': 100,
      }
      # 代理列表
      PROXY_LIST = ['http://ip1:port1','http://ip2:port2',# ...
      ]
      
    • 自定义 RandomProxyMiddleware

      # myproject/middlewares.pyimport randomclass RandomProxyMiddleware:def __init__(self, proxies):self.proxies = proxies@classmethoddef from_crawler(cls, crawler):return cls(proxies=crawler.settings.get('PROXY_LIST'))def process_request(self, request, spider):proxy = random.choice(self.proxies)request.meta['proxy'] = proxy
      
    • 这样 Scrapy 在每次请求时会随机从 PROXY_LIST 中取一个代理。


12. 完整案例:爬取某新闻网站并存入数据库

本节以“爬取某模拟新闻网站(示例:https://news.example.com)的头条新闻,并将标题、摘要、链接存入 MySQL 数据库”为例,完整演示 Scrapy + MySQL 的使用。

12.1 需求分析

  1. 目标数据:新闻标题、摘要(简介)、文章链接、发布时间。
  2. 爬取范围:首页头条新闻(假设分页结构或动态加载,可视情况调整)。
  3. 存储方式:MySQL 数据库,表名 headline_news,字段:id, title, summary, url, pub_date
  4. 反爬策略:设置随机 User-Agent、下载延时、简单 IP 伪装。

12.2 使用 Scrapy + MySQL 完整实现

  1. 创建 Scrapy 项目

    scrapy startproject news_spider
    cd news_spider
    
  2. 安装依赖

    pip install scrapy pymysql
    
  3. 定义 Item (news_spider/items.py)

    import scrapyclass NewsSpiderItem(scrapy.Item):title = scrapy.Field()summary = scrapy.Field()url = scrapy.Field()pub_date = scrapy.Field()
    
  4. 设置 MySQL 配置 (news_spider/settings.py)

    # Database settings
    MYSQL_HOST = 'localhost'
    MYSQL_PORT = 3306
    MYSQL_USER = 'root'
    MYSQL_PASSWORD = 'root'
    MYSQL_DB = 'news_db'
    MYSQL_CHARSET = 'utf8mb4'# Item Pipeline
    ITEM_PIPELINES = {'news_spider.pipelines.MySQLPipeline': 300,
    }# Download settings
    ROBOTSTXT_OBEY = True
    DOWNLOAD_DELAY = 1
    CONCURRENT_REQUESTS = 8
    USER_AGENTS_LIST = ['Mozilla/5.0 ... Chrome/100.0 ...','Mozilla/5.0 ... Firefox/110.0 ...',# 可自行补充
    ]
    DOWNLOADER_MIDDLEWARES = {'news_spider.middlewares.RandomUserAgentMiddleware': 400,'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    }
    
  5. 自定义中间件:随机 User-Agent (news_spider/middlewares.py)

    import randomclass RandomUserAgentMiddleware:def __init__(self, user_agents):self.user_agents = user_agents@classmethoddef from_crawler(cls, crawler):return cls(user_agents=crawler.settings.get('USER_AGENTS_LIST'))def process_request(self, request, spider):ua = random.choice(self.user_agents)request.headers.setdefault('User-Agent', ua)
    
  6. MySQL Pipeline (news_spider/pipelines.py)

    import pymysql
    from pymysql.err import IntegrityErrorclass MySQLPipeline:def open_spider(self, spider):# 连接数据库self.conn = pymysql.connect(host=spider.settings.get('MYSQL_HOST'),port=spider.settings.get('MYSQL_PORT'),user=spider.settings.get('MYSQL_USER'),password=spider.settings.get('MYSQL_PASSWORD'),db=spider.settings.get('MYSQL_DB'),charset=spider.settings.get('MYSQL_CHARSET'),cursorclass=pymysql.cursors.DictCursor)self.cursor = self.conn.cursor()# 创建表create_table_sql = """CREATE TABLE IF NOT EXISTS headline_news (id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255),summary TEXT,url VARCHAR(512) UNIQUE,pub_date DATETIME) CHARACTER SET utf8mb4;"""self.cursor.execute(create_table_sql)self.conn.commit()def close_spider(self, spider):self.cursor.close()self.conn.close()def process_item(self, item, spider):insert_sql = """INSERT INTO headline_news (title, summary, url, pub_date)VALUES (%s, %s, %s, %s)"""try:self.cursor.execute(insert_sql, (item.get('title'),item.get('summary'),item.get('url'),item.get('pub_date')))self.conn.commit()except IntegrityError:# URL 已存在则跳过passreturn item
    
  7. 编写 Spider (news_spider/spiders/news.py)

    import scrapy
    from news_spider.items import NewsSpiderItemclass NewsSpider(scrapy.Spider):name = 'news'allowed_domains = ['news.example.com']start_urls = ['https://news.example.com/']def parse(self, response):# 假设首页头条新闻在 <div class="headline-list"> 下,每个新闻项 <div class="item">for news in response.css('div.headline-list div.item'):item = NewsSpiderItem()item['title'] = news.css('h2.title::text').get().strip()item['summary'] = news.css('p.summary::text').get().strip()item['url'] = response.urljoin(news.css('a::attr(href)').get())item['pub_date'] = news.css('span.pub-date::text').get().strip()  # 需后续转换为标准时间yield scrapy.Request(url=item['url'],callback=self.parse_detail,meta={'item': item})# 假设分页结构:下一页链接在 <a class="next-page" href="...">next_page = response.css('a.next-page::attr(href)').get()if next_page:yield response.follow(next_page, callback=self.parse)def parse_detail(self, response):item = response.meta['item']# 在详情页可提取更精确的发布时间pub_date = response.css('div.meta span.date::text').get().strip()item['pub_date'] = self.parse_date(pub_date)yield itemdef parse_date(self, date_str):# 假设 date_str 格式为 '2025-05-30 14:30:00'from datetime import datetimetry:dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')return dtexcept:return None
    
  8. 运行爬虫

    • 确保 MySQL 已创建数据库 news_db,用户名、密码正确;

    • 在项目根目录执行:

      scrapy crawl news
      
    • 运行期间,日志会显示抓取进度,成功后可在 headline_news 表中查看抓取结果:

      SELECT * FROM headline_news LIMIT 10;
      

12.3 代码详解与常见 Q&A

  • Q:为什么要在 parse 方法中发起新的 Request 到详情页?

    • 因为首页展示的数据有限,有些字段(如精确发布时间、作者、正文)要到详情页才能拿到。meta 参数可将部分已抓取的字段传递到下一个回调。
  • Q:如何将字符串 '2025-05-30 14:30:00' 转为 datetime

    • 使用 Python 标准库 datetime.strptime,传入对应格式;若格式不一致,可先 strip() 或正则提取。
  • Q:如果目标网站有登录或验证码怎么办?

    • 可在 start_requests 方法里模拟登录(使用 requests + cookies 或 Selenium),登录后获取 Cookie,再将 Cookie 带入 Scrapy 调用。
  • Q:如何处理分页数量巨大(上千页)?

    • 可分析 URL 规律(如 page=1,2,3...),使用 for page in range(1, 1001): yield scrapy.Request(...)。注意限速与 IP 轮换,防止被封。
  • Q:为什么要随机 User-Agent?

    • 防止被网站识别为爬虫。
  • Q:如何在 Scrapy 中使用代理?

    • 参考第 11.4 节,在 DOWNLOADER_MIDDLEWARES 中配置自己的 RandomProxyMiddleware,或直接使用 Scrapy-Proxy-Pool 等库。

13. Python 爬虫相关的常用第三方库一览(截至 2025年6月)

以下对各类常用库进行分类归纳,并附简要说明与典型使用场景。

13.1 基础请求与解析

库 名功能简介典型场景
requests同步 HTTP 请求,API 简洁,生态成熟绝大多数简单爬虫,表单提交、Cookie 支持
httpx支持同步 & 异步的 HTTP 客户端,与 requests 兼容需要异步或更多高级功能时的首选
aiohttp原生 asyncio 协程模式的 HTTP 客户端高并发抓取、异步爬虫
urllib3低级 HTTP 客户端,requests 底层依赖需要更底层的控制、定制化管理连接池时
BeautifulSoup (bs4)HTML/XML 解析,入门简单、灵活初学者快速上手、解析复杂 HTML
lxml基于 libxml2/libxslt 的高性能解析器,支持 XPath需要高性能、大量数据解析时,结合 XPath 提取
parselScrapy 自带的解析器,支持 CSS/XPathScrapy 项目中快捷解析、项目外独立解析
PyQuery类似 jQuery 的解析 API,基于 lxml前端同学更习惯 CSS 选择器,快速上手
re (正则)Python 内置正则模块,对结构简单的文本进行模式匹配提取邮箱、电话号码、URL、数字等简单模式
html5lib兼容性最强的解析器(支持容错 HTML),速度相对较慢需要解析结构严重不规范的 HTML 时

13.2 浏览器自动化

库 名功能简介典型场景
Selenium最成熟的浏览器自动化框架,支持 Chrome、Firefox、Edge 等需模拟用户操作 (点击、滑动、表单提交)、抓取 JS 渲染内容
Playwright微软出品,继承 Puppeteer,API 简洁,支持多浏览器高性能 headless 模式,异步/同步模式都支持
PyppeteerPuppeteer 的 Python 移植版Node.js 用户转 Python 时快速上手
undetected-chromedriver对抗反爬,屏蔽 Selenium 特征需要更强的逃避检测能力,尤其面对高级反爬
Splash由 Scrapy-Splash 提供,基于 QtWebKit 的渲染服务Scrapy 与动态渲染结合,用于批量异步渲染

13.3 异步爬取

库 名功能简介典型场景
asyncioPython 标准库,提供事件循环与异步协程基础编写异步爬虫主框架
aiohttp基于 asyncio 的 HTTP 客户端高并发抓取、配合 BeautifulSoup/lxml 解析
httpx支持同步 & 异步,与 requests 接口兼容希望无缝从 requests 切换到异步模式
trio另一个异步框架,示意图结构友好,但生态相对较小深度研究异步原理或希望新尝试
curio纯 Python 异步库,强调简洁研究异步 I/O 原理的场景
aiofiles异步文件操作异步模式下同时要读写大量文件

13.4 登录模拟与验证码处理

库 名功能简介典型场景
requests + Session模拟登录,自动管理 Cookie大部分需要登录后抓取的场景
selenium浏览器自动化登录,执行 JS,处理复杂登录逻辑登录时有 JS 加密或动态 token
Playwright与 Selenium 类似,但速度更快,接口更现代更轻量级的浏览器自动化
pytesseractOCR 识别图片文字简单验证码识别
captcha_solver第三方打码平台 SDK需要调用付费打码平台处理验证码
twoCaptcha付费打码平台 Python 客户端需要可靠的验证码打码服务

13.5 反爬与代理

库 名功能简介典型场景
fake-useragent随机生成 User-Agent防止被识别为爬虫
scrapy-fake-useragentScrapy 专用随机 UA 插件Scrapy 项目中一键启用随机 UA
requests-random-user-agent为 requests 提供随机 UA 支持轻松控制 requests 请求头
scrapy-rotating-proxiesScrapy 专用代理轮换中间件,用于自动切换代理池(付费或免费)Scrapy 大规模抓取时避免单 IP 封禁
scrapy-proxies开源 Scrapy 代理中间件,可使用免费代理池入门级 Scrapy 项目快速使用代理
proxylist2Python 包,从多个免费代理网站抓取代理 IP自动化维护免费代理列表
requests-redis-rotating-proxies结合 Redis 存储代理列表,实现高可用代理池中大型项目需集中管理代理 IP
scrapy-user-agentsScrapy 插件,内置常见 UA 列表简化 Scrapy 中的 UA 列表管理
cfscrape用于绕过 Cloudflare 简易 JS 保护某些站点需要绕过 Cloudflare 5 秒验证页面

13.6 分布式调度

库 名功能简介典型场景
scrapy-redisScrapy 分布式爬虫扩展,统一 Redis 作为队列与去重存储分布式 Scrapy 项目
scrapy-cluster基于 Kafka + Redis 的 Scrapy 分布式爬虫系统企业级分布式环境,需与消息队列协同
Frigate高性能分布式爬虫,结合 Redis + MongoDB大规模分布式爬取且需要与 NoSQL 存储集成
PhantomJS + Splash无头浏览器渲染服务,可与 Scrapy 搭配形成分布式渲染环境需要大规模渲染 JS 页面后再抓取

13.7 其它有用工具

库 名功能简介典型场景
robotparserPython 内置 urllib.robotparser,解析 robots.txt爬虫前先检查 robots.txt
tldextract提取域名、子域名、后缀需要对 URL 做域名归类或统计时
url-normalizeURL 规范化,去除重复查询参数爬虫过程对 URL 进行标准化去重
loggingPython 标准库,用于日志输出任何爬虫项目都应进行日志记录
fake_useragent动态获取并生成随机 UA避免 UA 列表过时
termcolor终端字符着色,调试输出更直观爬虫日志、调试时需要彩色提示
psutil系统资源监控,可查看 CPU、内存占用长时间运行爬虫时监控资源使用情况
schedule定时任务库,可定时运行脚本需要定时执行爬虫任务
watchdog文件系统监控,当文件/目录变化时触发回调实时监控爬取结果文件、触发后续任务

说明:因篇幅所限,上表仅列出截至 2024 年底常用或较为稳定的 Python 爬虫库,后续可能有新库或旧库迭代,请根据实际需求及时查阅官方文档或社区资源。


14. 附录

14.1 常见报错及解决方案

  1. ModuleNotFoundError: No module named 'xxx'

    • 原因:未安装该包或安装在全局而非虚拟环境中。
    • 解决:确认当前虚拟环境是否已激活,并执行 pip install xxx
  2. requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]

    • 原因:本机 CA 证书有问题,无法验证 HTTPS。

    • 解决:

      • 升级 certifipip install --upgrade certifi
      • 临时忽略:requests.get(url, verify=False)(不推荐用于生产)。
  3. ValueError: too many values to unpack (expected 2) 在 XPath 返回多值时

    • 原因:使用 for x, y in tree.xpath(...),但 XPath 返回值数量与预期不符。
    • 解决:检查 XPath 语法,或者使用 zip() 将两个列表匹配。
  4. selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH

    • 原因:chromedriver 未放在系统 PATH,或路径不正确。
    • 解决:下载与 Chrome 版本一致的 chromedriver,并将其路径添加到环境变量,或者在代码中指定 executable_path
  5. pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")

    • 原因:MySQL 用户名/密码、权限或 MySQL 服务未启动。
    • 解决:检查用户名、密码是否正确,MySQL 服务是否运行,数据库名称是否存在。
  6. TimeoutErrorasyncio.exceptions.TimeoutError

    • 原因:网络慢或被目标站点限制。
    • 解决:加大 timeout 参数,降低并发数,适当设置代理。
  7. UnicodeEncodeError/UnicodeDecodeError

    • 原因:处理的文本编码与 Python 默认编码不一致。
    • 解决:明确指定 response.encoding = 'utf-8',或者在读写文件时加 encoding='utf-8'

14.2 常用 HTTP 状态码速查

状态码含义
200OK,请求成功
301永久重定向
302临时重定向
400Bad Request,请求报文语法错误
401Unauthorized,需要身份验证
403Forbidden,服务器拒绝访问(常见反爬屏蔽码)
404Not Found,资源不存在
405Method Not Allowed,请求方法被禁止
408Request Timeout,服务器等待客户端发送请求超时
429Too Many Requests,客户端请求频率过高
500Internal Server Error,服务器内部错误
502Bad Gateway,服务器作为网关或代理时收到上游服务器无效响应
503Service Unavailable,服务器暂时无法处理请求,常见于流量过大被限流

14.3 学习资源与进阶指南

  1. 官方文档

    • Requests:https://docs.python-requests.org/
    • BeautifulSoup:http://beautifulsoup.readthedocs.io/
    • Scrapy:https://docs.scrapy.org/
    • Selenium:https://www.selenium.dev/documentation/
    • Playwright:https://playwright.dev/python/
    • aiohttp:https://docs.aiohttp.org/
    • httpx:https://www.python-httpx.org/
  2. 推荐书籍

    • 《Python网络数据采集(第二版)》—— Ryan Mitchell
    • 《深入Python爬虫框架 Scrapy》—— 黄今
    • 《Python3网络爬虫开发实战》—— 石刚
  3. 课程与视频

    • B 站、YouTube 上均有优质 Python 爬虫视频教程(可搜索“Python 爬虫 零基础”、“Scrapy 教程”等)。
    • Coursera/慕课网上的 Python 爬虫进阶课程。
  4. 社区资源

    • Stack Overflow:https://stackoverflow.com/(遇到报错可搜索)
    • SegmentFault:https://segmentfault.com/(国内开发者社区)
    • GitHub Trending:搜索开源爬虫项目,学习最佳实践。

15. 总结

本教程从最基础的 requests + BeautifulSoup,到 Scrapy 框架、浏览器自动化、异步爬虫、分布式爬虫,系统梳理了 Python 爬虫的常见技术与实践要点,并盘点了截至 2024 年底的主流库与工具。对于初学者而言,掌握以下几个关键点即可快速上手:

  1. 理解 HTTP 基础:会构造 GET/POST 请求、分析响应;
  2. 掌握 HTML 解析:熟悉 BeautifulSoup、lxml(XPath/CSS Selector);
  3. 尝试 Scrapy:学会搭建 Scrapy 项目、编写 Spider、Pipeline、Settings,并用 Scrapy Shell 调试;
  4. 应对动态页面:熟练使用 Selenium 或 Playwright 抓取 JS 渲染内容,并结合常规解析方法提取数据;
  5. 探索异步爬虫:理解协程原理,用 aiohttp、httpx 提升并发性能;
  6. 数据存储与去重:掌握 CSV/JSON/SQLite/MySQL/MongoDB 的使用,并做好 URL 去重(集合、Redis、Bloom Filter);
  7. 反爬与反制:设置 User-Agent、Referer、下载延时、代理 IP 池等,了解验证码处理思路;
  8. 分布式爬虫:学习 Scrapy-Redis,将任务分配到多台机器,提高抓取效率。

最后,爬虫技术更新迅速,截止到本教程编写时(2024 年底)的主流库可能会随着技术迭代、站点反爬升级而发生变化。建议你在入门后,积极关注各大 Python 社区、GitHub Trending 以及官方文档,及时跟进新特性、新库、新思路,不断优化自己的爬虫方案。祝你能在数据抓取的道路上越走越远,愉快地玩转 Python 爬虫世界!


创作时间:2025 年 6 月 1 日

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916158.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916158.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916158.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

openmv识别数字

Lenet是一种卷积识别网络,可以用来识别打印的&#xff0c;或者是手写的数字利用NCC的模板匹配算法来进行数字识别&#xff0c;模板匹配需要我们事先保存需要匹配的数字以及字母的模板图片,模板匹配对于模板的大小和角度&#xff0c;有一定的要求如果数字的大小和角度有所变换&a…

一款功能全面的文体场所预约小程序

大家好👋 ,我是 阿问学长!专注于分享优质开源项目解析、计算机学习资料推荐,并为同学们提供毕业设计项目指导支持,欢迎关注交流!🚀 项目概述 随着全民健身的普及,各地新建了大批体育、健身、文化娱乐场所,中小学校园的运动设施也开始对市民开放。为了合理安排主办…

PyTorch中实现早停机制(EarlyStopping)附代码

1. 核心目的 当模型在验证集上的性能不再提升时&#xff0c;提前终止训练防止过拟合&#xff0c;节省计算资源 2. 实现方法 监控验证集指标&#xff08;如损失、准确率&#xff09;&#xff0c;设置耐心值&#xff08;Patience&#xff09; 3. 代码&#xff1a; class EarlySto…

Nacos-服务注册,服务发现(一)

nacos快速入手 Nacos是Spring Cloud Alibaba的组件, Spring Cloud Alibaba遵循Spring Cloud中定义的服务注册, 服 务发现规范. 因此使⽤Nacos和使⽤Eureka对于微服务来说&#xff0c;并没有太⼤区别. 主要差异在于&#xff1a; Eureka需要⾃⼰搭建⼀个服务, Nacos不⽤⾃⼰搭…

单片机(STM32-ADC模数转换器)

一、基础知识1. 模拟信号&#xff08;Analog Signal&#xff09;定义&#xff1a;模拟信号是连续变化的信号&#xff0c;可以取任意数值。特点&#xff1a;幅值和时间都是连续的&#xff0c;没有“跳变”。举例&#xff1a;声音&#xff08;麦克风采集到的电压&#xff09;温度…

side.cpp - OpenExo

side.cpp构造函数源代码run_side - 核心read_data()源代码FSR压力传感器读取与赋值步态事件检测&#xff1a;落地&#xff08;ground_strike&#xff09;步态周期自适应&#xff1a;期望步长更新Toe-Off/Toe-On事件检测与站立/摆动窗口更新步态百分比进度估算FSR阈值动态读取&a…

基于Java+MySQL实现(Web)文件共享管理系统(仿照百度文库)

文件共享管理系统的设计与实现摘要&#xff1a;本文件共享管理系统解决了用户在搜索文件不需要下载文件到本地硬盘后才能查看文件的详细内容的弊端&#xff1b;解决用户在搜索关键字不明确条件下无法搜索到自己需要的文件弊端&#xff1b;解决了系统用户并发量增加后服务器宕机…

go语言基础教程:1. Go 下载安装和设置

1. Go 下载安装和设置1. 安装Go 官网下载安装即可&#xff0c;注意要记住安装的位置&#xff0c;例如D:\Go cmd输入go 或者go env 会输出各种信息&#xff0c;代表安装成功 2. hello go &#xff08;1&#xff09;编写 hello.go go是以文件夹为最小单位管理程序的&#xff0c…

使用相机不同曝光时间测试灯光闪烁频率及Ai解释

1.背景坐地铁上&#xff0c;拨弄着手机拍照中的专业模式&#xff0c;偶然发现拍出了条纹&#xff0c;怀疑是灯光的缘故&#xff0c;但是随后在家里的LED等下就拍不出类似的效果了。好奇心❤让我又尝试多了解了一点和不断尝试&#xff0c;发现不同的曝光时间可以拍出不同明显程度…

力扣-416.分割等和子集

题目链接 416.分割等和子集 class Solution {public boolean canPartition(int[] nums) {int sum 0;for (int i 0; i < nums.length; i) {sum nums[i];}if (sum % 2 1)return false;int target sum / 2;// dp[i]表示&#xff1a;背包容量为i时&#xff0c;能装的最大…

http协议学习-body各种类型

1、概述使用postman工具和nc命令分析http协议中body各种类型的格式。2、分析环境准备虚拟机中用nc命令模仿服务器&#xff0c;启动监听状态。 windows机器安装postmannc -k -l 192.168.202.223 80821、params参数postman中params添加俩个key为m、n&#xff1b;value为1、2&…

C++中的塔尖算法(Tarjan算法)详解

C中的塔尖算法&#xff08;Tarjan算法&#xff09;详解——目录C中的塔尖算法&#xff08;Tarjan算法&#xff09;详解一、什么是Tarjan算法&#xff1f;二、算法原理与实现步骤1. 核心概念2. 主要逻辑3. C代码示例三、应用场景与扩展1. 典型应用2. 注意事项四、为什么选择Tarj…

Qt 数据库事务处理与数据安全

在 Qt 应用程序中&#xff0c;数据库事务处理是确保数据完整性和一致性的关键技术。通过事务&#xff0c;可以将多个数据库操作作为一个不可分割的单元执行&#xff0c;保证数据在并发访问和异常情况下的安全性。本文将详细介绍 Qt 中数据库事务的处理方法和数据安全策略。 一、…

Redis的事务和Lua之间的区别

Redis的事务和Lua之间的区别 Redis 提供了事务和 Lua 脚本两种实现原子性操作的方式。当需要以原子方式执行多个命令时,我们可以选择其中一种方案。 原子性保证 两者都确保操作的不可分割性 需要注意:不管是事务还是 Lua 脚本都不支持回滚机制 区别: 事务:某个命令失败不会…

腾讯云SDK

SDK的用途&#xff0c;现在显然是想更系统地了解它的产品定位和核心能力。 用户可能是开发者或者技术决策者&#xff0c;正在评估腾讯云的开发工具链。从ta连续追问云服务相关技术细节的习惯看&#xff0c;应该具备相当的技术背景&#xff0c;但需要避免过度使用术语。 需要突出…

大数据集分页优化:LIMIT OFFSET的替代方案

针对大数据集分页场景中 LIMIT OFFSET 的性能瓶颈&#xff0c;以下是已验证的高效替代方案及实施要点&#xff1a;⚠️ 一、LIMIT OFFSET 的核心问题当偏移量&#xff08;OFFSET&#xff09;增大时&#xff0c;数据库需‌物理扫描并丢弃前 N 条记录‌&#xff0c;导致资源浪费和…

Linux网络框架分析

在 Linux 内核架构中,/net 和 /drivers/net 是网络子系统的两个核心组成部分,它们之间的关系体现了 Linux 经典的 “抽象层分离” 设计哲学。以下是深入分析: 一、核心关系图解 #mermaid-svg-esFw9i3LN65SYumi {font-family:"trebuchet ms",verdana,arial,sans-se…

ISIS高级特性GR

一、概述IS-IS GR是一种支持GR能力的高可靠性技术&#xff0c;可以实现数据的不间断转发。与我们之前介绍的OSPF的GR功能几乎一致,但实现方法并不相同。1、GR支持GR的ISIS的设备,IIH报文中一定会携带TLV211(GR),TLV211包含的字段(1)RR:restart request 请求重启,默认是3秒发送1…

电厂液压执行器自动化升级:Modbus TCP与DeviceNet的协议贯通实践

一、项目背景在我们电厂的汽轮机控制区&#xff0c;液压执行器是实打实的“关键选手”——从调节蒸汽阀门开度到控制闸板起落&#xff0c;全靠它在高压环境下精准动作。但这套系统一直有个“沟通障碍”&#xff1a;负责统筹控制的施耐德PLC走Modbus TCP协议&#xff0c;而液压执…

ucharts 搭配uniapp 自定义x轴文字 实现截取显示

formatter格式化问题因为组件不能传递 function&#xff0c;所有的 formatter 均需要变成别名 format 来定义&#xff0c;并在 config-ucharts.js 或 config-echarts.js 配置对应的 formatter 方法&#xff0c;组件会根据 format 的值自动替换配置文件中的 formatter 方法。uCh…