文章

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

#253 · 2026-05-13 · Python 教程拆解

说明:本文基于 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:一听并发就上异步全家桶。 先弄清楚为什么慢,再决定并发策略。

上一篇Python 教程拆解 · 04:Django 与 FastAPI
下一篇Python 教程拆解 · 06:数据分析与机器学习