文章

Python 教程拆解索引 · 05:网络数据采集

#254 · 2026-05-13 · Python 教程拆解
Reading Path / PYTHON 先抓主张,再转成行动 #254 · Python 教程拆解 · 读完进入产品或下一篇

承上启下:在上一篇《Python 后端架构选型:Django 的厚重沉淀与 FastAPI 的现代跃迁》中,我们系统剖析了后端开发的并发选型与 WSGI/ASGI 的架构设计。后端应用为数据交互提供了稳定的接口,而在庞大的互联网生态中,如何主动获取海量外部非结构化数据则是另一项核心技能。本篇作为“网络数据采集”专题索引,将为您系统拆解从 requests 库基础请求,到 XPath 与 BeautifulSoup 的精准解析,再到并发编程、Selenium 动态渲染与 Scrapy 分布式框架的抓取路线图。

说明:本文基于 Day61-65/ 做原创教学整理,不复写原教程内容。

系列导航04 后端主线|05 数据采集|06 数据智能

本篇对应材料61.网络数据采集概述.md62.用Python获取网络资源-1.md62.用Python解析HTML页面-2.md63.*并发编程*.md64.使用Selenium抓取网页动态内容.md65.爬虫框架Scrapy简介.md

定位更正:这一页现在只是“采集专题入口”。requests、XPath、BS4、并发、Selenium、Scrapy 都应该拆开写,不能再压成一篇。

本章细教程

已经拆开的源文件

原仓库文件 主题 教程
Day61-65/62.用Python获取网络资源-1.md + 62.用Python解析HTML页面-2.md requests 获取内容、XPath、BS4/CSS 选择器解析 05A

下一批应该继续拆的文件

  • Day61-65/63.Python中的并发编程-1.md
  • Day61-65/63.Python中的并发编程-2.md
  • Day61-65/63.Python中的并发编程-3.md
  • Day61-65/64.使用Selenium抓取网页动态内容.md
  • Day61-65/65.爬虫框架Scrapy简介.md

这部分最容易学废的方式,就是打开别人的爬虫代码一顿抄,结果连“抓取”和“解析”到底在干什么都没弄明白。

所以今天不碰真实网站,先做一个合法、安全、本地可复现的采集练习。

今天你要做出的结果

我们会完成三步:

  1. 解析一份本地 HTML;
  2. 批量抽取结构化数据;
  3. 用线程池并发处理多个页面字符串。

Step 1:先准备一份本地 HTML

新建 practice/day05/sample.html

<!doctype html>
<html lang="zh-CN">
<body>
  <div class="book" data-id="101">
    <h2 class="title">Python 入门</h2>
    <span class="price">59.00</span>
  </div>
  <div class="book" data-id="102">
    <h2 class="title">FastAPI 实战</h2>
    <span class="price">88.00</span>
  </div>
</body>
</html>

Step 2:先做“解析”,不要急着上网络

新建 practice/day05/parse_local.py

import re
from pathlib import Path


html = Path("sample.html").read_text(encoding="utf-8")

pattern = re.compile(
    r'<div class="book" data-id="(\d+)">.*?'
    r'<h2 class="title">(.*?)</h2>.*?'
    r'<span class="price">(.*?)</span>',
    re.S
)

books = []
for book_id, title, price in pattern.findall(html):
    books.append({
        "id": int(book_id),
        "title": title,
        "price": float(price),
    })

print(books)

运行:

cd practice/day05
python parse_local.py

输出类似:

[{'id': 101, 'title': 'Python 入门', 'price': 59.0}, {'id': 102, 'title': 'FastAPI 实战', 'price': 88.0}]

这一步对应的就是 Day62页面解析

Step 3:再补一个“抓取”动作

如果你本机能联网,可以用一个公开演示站练请求;如果不想碰外网,这一步可以只看代码结构。

新建 practice/day05/fetch_demo.py

import requests


url = "https://httpbin.org/html"
resp = requests.get(url, timeout=10)

print("状态码:", resp.status_code)
print("内容前80个字符:")
print(resp.text[:80])

运行:

python fetch_demo.py

这里你学到的是:抓取解决“把内容拿回来”,解析解决“把数据拆出来”

Step 4:再做一个并发版

为了不碰真实多页面网站,我们用多个本地 HTML 字符串模拟任务。

新建 practice/day05/concurrent_parse.py

from concurrent.futures import ThreadPoolExecutor
import re


pages = [
    '<div class="book" data-id="1"><h2 class="title">A</h2><span class="price">10</span></div>',
    '<div class="book" data-id="2"><h2 class="title">B</h2><span class="price">20</span></div>',
    '<div class="book" data-id="3"><h2 class="title">C</h2><span class="price">30</span></div>',
]

pattern = re.compile(
    r'data-id="(\d+)".*?<h2 class="title">(.*?)</h2>.*?<span class="price">(.*?)</span>',
    re.S
)


def parse_one(html: str):
    book_id, title, price = pattern.search(html).groups()
    return {"id": int(book_id), "title": title, "price": float(price)}


with ThreadPoolExecutor(max_workers=3) as pool:
    results = list(pool.map(parse_one, pages))

print(results)

这一步对应 Day63:并发在爬虫里不是炫技,而是在解决 I/O 等待。

什么时候才该去学 Selenium 和 Scrapy

你现在先不要急着上来就装大框架。

Selenium 该在什么时候出场

当页面内容依赖浏览器执行 JavaScript 后才出现时。

Scrapy 该在什么时候出场

当你的脚本开始出现这些问题时:

  • 去重麻烦;
  • 调度混乱;
  • 重试逻辑难写;
  • 数据管道越来越乱。

本篇练习

  1. sample.html 里再加两本书。
  2. 给解析结果加一个 price_level 字段,比如大于 80 算 "high"
  3. 把并发版输出结果改成按价格从高到低排序。

常见坑

  • 坑 1:上来就拿真实网站乱试。 先学会本地流程,再谈外网。
  • 坑 2:把抓取和解析混成一坨。 这会让调试非常痛苦。
  • 坑 3:一听并发就上异步全家桶。 先弄清楚为什么慢,再决定并发策略。

💡 下一篇预告:掌握了网络数据的高并发抓取与解析清洗后,我们就拥有了业务决策的最原始燃料。但在海量数据堆积的当下,如何将其转化为具有商业价值 of 结构化分析与智能化预测,则是 Python 核心技能树上的又一高峰。下一章“数据智能”将带您跨入数据分析(Pandas/NumPy)与经典的机器学习算法(如 kNN 分类器)的核心实践。下一篇《Python 教程拆解索引 · 06:数据分析与机器学习》将为您系统梳理这一章节的知识拼图。