本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:网络爬虫是获取互联网数据的重要工具,Python凭借其简洁语法和丰富库支持,成为爬虫开发的首选语言。本文系统讲解Python网络爬虫的核心知识,涵盖HTTP/HTTPS协议基础、HTML结构解析、常用爬虫库(如Requests、BeautifulSoup、Scrapy、Selenium)、爬虫流程设计、反反爬策略以及实战案例。通过本项目学习,读者能够掌握从网页抓取到数据存储的完整流程,并具备应对复杂网页结构和反爬机制的能力。
网络爬虫_python_中数爬取_

1. 网络爬虫基础概念

1.1 网络爬虫的定义与作用

网络爬虫(Web Crawler)是一种按照一定规则,自动抓取互联网信息的程序或脚本。其核心作用在于从网页中提取结构化或非结构化数据,为后续的数据分析、搜索引擎索引、舆情监控等提供原始数据支持。

从技术角度而言,爬虫的本质是一个自动化访问 Web 服务器并解析返回内容的客户端程序。它通过 HTTP 协议向目标服务器发起请求,获取 HTML 页面、JSON 数据或其他资源,并从中提取所需信息。

随着大数据与人工智能的发展,爬虫技术已成为数据驱动型应用的基础设施之一。无论是电商比价、金融数据采集,还是搜索引擎的索引构建,都离不开高效的爬虫系统。

2. HTTP/HTTPS协议详解

在构建网络爬虫系统的过程中,理解 HTTP 和 HTTPS 协议是基础且关键的一环。HTTP(HyperText Transfer Protocol)作为互联网数据传输的标准协议,规定了客户端与服务器之间的通信规则;而 HTTPS(HTTP Secure)则在此基础上加入了加密层,保障了通信的安全性。本章将深入剖析 HTTP/HTTPS 的工作原理、安全机制、常用方法及状态码,并结合抓包工具的使用,帮助读者全面掌握爬虫开发中涉及的网络通信核心知识。

2.1 HTTP协议基础

HTTP 是客户端-服务器模型中用于传输超文本的标准协议。它定义了客户端(如浏览器或爬虫程序)如何向服务器发送请求,以及服务器如何响应这些请求。理解 HTTP 协议的结构、请求方法和状态码分类,有助于更有效地编写爬虫程序并处理网络通信中的异常。

2.1.1 HTTP请求与响应结构

HTTP 通信由请求和响应组成。客户端发送请求,服务器返回响应。每个请求和响应都有特定的结构,包括起始行、头部(Headers)和主体(Body)。

请求结构

一个 HTTP 请求通常由以下三部分组成:

  1. 请求行(Request Line) :包括请求方法、请求的资源路径(URI)和使用的 HTTP 版本。
  2. 请求头(Headers) :包含客户端发送给服务器的附加信息,如 Host、User-Agent、Content-Type 等。
  3. 请求体(Body) :在某些请求方法(如 POST、PUT)中,请求体包含要发送的数据。

示例请求报文:

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml
响应结构

HTTP 响应同样由三部分组成:

  1. 状态行(Status Line) :包括 HTTP 版本、状态码和状态消息。
  2. 响应头(Headers) :提供服务器返回的元数据,如 Content-Type、Content-Length、Set-Cookie 等。
  3. 响应体(Body) :返回的实体内容,如 HTML 页面、JSON 数据等。

示例响应报文:

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2025 12:28:53 GMT
Server: Apache/2.4.1 (Unix)
Content-Type: text/html
Content-Length: 1234

<!DOCTYPE html>
<html>
<head><title>Example</title></head>
<body><h1>Hello, World!</h1></body>
</html>
请求与响应结构对比表:
部分 请求报文 响应报文
起始行 请求行(方法 URI 版本) 状态行(版本 状态码 描述)
头部 客户端发送的元信息 服务器返回的元信息
主体(Body) 通常用于 POST/PUT 请求 返回的数据内容
参数说明:
  • 请求方法 :常见方法包括 GET、POST、PUT、DELETE 等。
  • URI :统一资源标识符,表示请求的目标资源路径。
  • HTTP 版本 :当前多为 HTTP/1.1 或 HTTP/2。
  • Host :指定请求的目标主机名。
  • User-Agent :标识客户端的类型与版本。
  • 状态码 :如 200 表示成功,404 表示未找到资源。
  • Content-Type :告知接收方发送的数据类型。

2.1.2 常用请求方法(GET、POST、PUT、DELETE等)

HTTP 定义了多种请求方法,每种方法代表不同的操作语义。以下是几种最常用的请求方法及其用途:

常见请求方法一览表:
方法 描述
GET 获取指定资源。请求参数附在 URL 后面,适合获取数据。
POST 向服务器提交数据,常用于创建新资源。数据放在请求体中。
PUT 替换指定资源的全部内容。数据放在请求体中。
DELETE 删除指定资源。
PATCH 更新资源的部分内容。
HEAD 获取资源的头部信息,不返回响应体。
OPTIONS 获取服务器支持的 HTTP 方法等信息。
示例:使用 Python 的 requests 库发送 GET 和 POST 请求
import requests

# 发送 GET 请求
response_get = requests.get('https://api.example.com/data', params={'id': 1})
print(response_get.status_code)
print(response_get.json())

# 发送 POST 请求
data = {'username': 'test', 'password': '123456'}
response_post = requests.post('https://api.example.com/login', data=data)
print(response_post.status_code)
print(response_post.cookies)
代码逻辑分析:
  1. GET 请求
    - 使用 requests.get() 方法向服务器发送 GET 请求。
    - params 参数用于附加查询字符串到 URL。
    - .json() 方法将响应内容解析为 JSON 格式。

  2. POST 请求
    - 使用 requests.post() 方法提交数据。
    - data 参数用于传递表单数据。
    - .cookies 属性可获取服务器设置的 Cookie。

参数说明:
  • url :请求的目标地址。
  • params :GET 请求的查询参数。
  • data :POST 请求的表单数据。
  • json :用于发送 JSON 格式的数据(自动设置 Content-Type 为 application/json)。

2.1.3 状态码含义与分类(2xx、3xx、4xx、5xx)

HTTP 状态码用于表示请求的处理结果。根据状态码的不同,可以判断请求是否成功、是否需要重定向或出现错误。

状态码分类表:
分类 状态码范围 描述
1xx 100-199 信息性状态码,表示请求已被接收,继续处理
2xx 200-299 成功状态码,请求已被成功接收、理解并处理
3xx 300-399 重定向状态码,客户端需进一步操作以完成请求
4xx 400-499 客户端错误状态码,请求有误或无法被服务器处理
5xx 500-599 服务器错误状态码,服务器无法完成合法请求
常见状态码示例:
状态码 描述
200 请求成功
301 永久重定向
302 临时重定向
400 错误请求
401 未授权
403 禁止访问
404 资源未找到
500 内部服务器错误
502 网关错误
503 服务不可用
示例:使用 Python 处理状态码
import requests

response = requests.get('https://api.example.com/data')

if response.status_code == 200:
    print("请求成功,返回数据:", response.json())
elif response.status_code == 404:
    print("资源未找到,请检查 URL 是否正确。")
elif response.status_code == 500:
    print("服务器内部错误,请稍后再试。")
else:
    print(f"请求失败,状态码:{response.status_code}")
代码逻辑分析:
  1. 使用 requests.get() 发送请求。
  2. 使用 response.status_code 获取状态码。
  3. 通过条件判断处理不同的状态码,进行相应的逻辑处理。
参数说明:
  • status_code :响应的状态码,类型为整数。
  • json() :将响应内容解析为 JSON 格式。
  • text :获取响应的原始文本内容。

2.2 HTTPS与安全通信

随着网络安全问题日益突出,HTTPS 已成为现代 Web 通信的标准协议。HTTPS 在 HTTP 协议的基础上引入了 SSL/TLS 加密层,确保数据在传输过程中不会被窃取或篡改。理解 HTTPS 的工作原理、数字证书机制以及在 Python 中如何处理 HTTPS 请求,是构建安全爬虫系统的关键。

2.2.1 HTTPS的工作原理与SSL/TLS协议

HTTPS 的核心在于 SSL/TLS 协议提供的加密通信机制。其工作流程如下:

  1. 客户端发起 HTTPS 请求 :浏览器或爬虫程序向服务器发起 HTTPS 连接请求。
  2. 服务器返回证书 :服务器将自身的数字证书发送给客户端。
  3. 客户端验证证书 :客户端检查证书是否由可信的 CA(证书颁发机构)签发,是否在有效期内,域名是否匹配等。
  4. 密钥交换与加密通道建立 :客户端与服务器通过非对称加密交换对称密钥,之后使用该密钥进行加密通信。
HTTPS通信流程图(mermaid格式):
sequenceDiagram
    participant Client
    participant Server
    Client->>Server: 发起 HTTPS 请求
    Server-->>Client: 返回数字证书
    Client->>Client: 验证证书有效性
    Client->>Server: 使用公钥加密对称密钥
    Server->>Client: 使用私钥解密对称密钥
    Client<->Server: 使用对称密钥进行加密通信
参数说明:
  • SSL/TLS :用于加密通信的协议,TLS 是 SSL 的继任者。
  • 数字证书 :包含服务器的公钥和身份信息,由 CA 签发。
  • 非对称加密 :使用公钥加密,私钥解密,用于安全交换对称密钥。
  • 对称加密 :使用同一个密钥进行加密和解密,效率高,用于实际数据传输。

2.2.2 数字证书与加密机制

HTTPS 安全性的核心依赖于数字证书和加密算法。以下是几个关键概念:

数字证书结构:
  • 颁发者(Issuer) :签发证书的 CA 名称。
  • 主体(Subject) :证书所有者的身份信息,如域名。
  • 有效期(Validity) :证书的起始和截止时间。
  • 公钥(Public Key) :用于加密的密钥。
  • 签名(Signature) :CA 对证书内容的数字签名,确保证书未被篡改。
加密机制:
  • 对称加密(AES、DES) :通信双方使用相同密钥加解密,速度快。
  • 非对称加密(RSA、ECC) :使用公钥加密,私钥解密,用于安全交换密钥。
  • 哈希算法(SHA-256) :用于生成证书指纹,确保数据完整性。

2.2.3 使用Python处理HTTPS请求的注意事项

在使用 Python 发送 HTTPS 请求时,需要注意以下几点:

示例:使用 requests 发送 HTTPS 请求并忽略 SSL 证书验证
import requests

response = requests.get('https://self-signed.badssl.com/', verify=False)
print(response.status_code)
代码逻辑分析:
  • verify=False :禁用 SSL 证书验证,适用于测试环境或自签名证书。
  • 注意 :生产环境中应避免禁用 SSL 验证,以防止中间人攻击。
示例:指定本地 CA 证书路径
response = requests.get('https://self-signed.badssl.com/', verify='/path/to/cert.pem')
print(response.status_code)
参数说明:
  • verify :指定 CA 证书路径或布尔值。默认为 True ,表示验证服务器证书。
异常处理示例:
try:
    response = requests.get('https://invalid.example.com', timeout=5)
except requests.exceptions.SSLError as e:
    print("SSL证书验证失败:", e)
except requests.exceptions.Timeout:
    print("请求超时")
except requests.exceptions.RequestException as e:
    print("请求异常:", e)
参数说明:
  • timeout :设置请求超时时间。
  • SSLError :SSL 证书验证失败时抛出的异常。
  • Timeout :请求超时时抛出的异常。
  • RequestException :所有请求异常的基类。

3. Requests库使用与HTTP请求发送

3.1 Requests库简介与安装

3.1.1 Requests的优势与特点

Requests 是 Python 中用于发送 HTTP 请求的第三方库,它简化了与 Web 服务的交互过程,使得开发者能够以更自然、更易读的方式进行网络请求操作。其核心优势包括:

  • 简洁易用的 API :Requests 提供了简洁的函数接口,如 get() post() 等,使得代码更易维护和理解。
  • 自动处理常见事务 :例如自动解码响应内容、保持会话(Session)、自动处理 Cookie、自动重定向等。
  • 支持多种请求方式 :包括 GET、POST、PUT、DELETE、HEAD 和 OPTIONS。
  • 良好的异常处理机制 :提供了清晰的异常类,便于错误捕获和处理。
  • 支持文件上传与下载 :通过 files 参数可以轻松实现文件上传,下载内容也可以直接写入文件。
  • 兼容性好 :支持 Python 2.7 和 Python 3.x,广泛应用于各类网络爬虫、API 接口测试等场景。

3.1.2 安装与环境配置

安装 Requests 库非常简单,推荐使用 pip 包管理器进行安装。在终端或命令行中输入以下命令即可完成安装:

pip install requests

安装完成后,可以通过 Python 交互式环境验证是否安装成功:

import requests
print(requests.__version__)

输出版本号即表示安装成功。

在某些企业或学校网络环境下,可能需要使用代理或指定镜像源来加速安装,可以使用以下命令:

pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

3.2 发送GET与POST请求

3.2.1 参数传递方式(params、data)

在实际开发中,我们经常需要向服务器传递参数。GET 请求通常将参数附加在 URL 上,而 POST 请求则将数据放在请求体中。Requests 提供了 params data 两个参数来分别处理这两种情况。

GET 请求传递参数

使用 params 参数可以将字典或元组列表转换为查询字符串,并自动进行 URL 编码。

import requests

params = {
    'query': 'requests tutorial',
    'page': 1
}

response = requests.get('https://api.example.com/search', params=params)
print(response.url)

输出示例:

https://api.example.com/search?query=requests+tutorial&page=1

代码逻辑分析:
- params 参数将字典转换为查询字符串,附加在 URL 后面。
- response.url 展示了最终请求的完整 URL。
- Requests 自动处理了空格转义和 URL 编码。

POST 请求传递参数

POST 请求通常用于提交数据,使用 data 参数传递表单数据。

import requests

data = {
    'username': 'admin',
    'password': '123456'
}

response = requests.post('https://api.example.com/login', data=data)
print(response.text)

代码逻辑分析:
- data 参数用于传递表单数据,默认以 application/x-www-form-urlencoded 格式发送。
- response.text 返回服务器响应的文本内容。

3.2.2 自定义请求头与用户代理(User-Agent)

HTTP 请求头(Headers)是客户端与服务器通信时的重要元数据,其中 User-Agent 用于标识客户端浏览器类型。在爬虫中,设置合适的 User-Agent 可以避免被网站识别为机器人。

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
    'Accept-Language': 'en-US,en;q=0.9',
    'Referer': 'https://www.google.com/'
}

response = requests.get('https://api.example.com/data', headers=headers)
print(response.request.headers)

输出示例:

{
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
    'Accept-Language': 'en-US,en;q=0.9',
    'Referer': 'https://www.google.com/'
}

代码逻辑分析:
- headers 字典用于自定义请求头。
- response.request.headers 展示了最终发送的请求头内容。
- 设置合适的 User-Agent 可以绕过部分网站的反爬机制。

3.2.3 文件上传与下载处理

Requests 支持文件上传与下载功能,适用于处理图像、文档等二进制资源。

文件上传

使用 files 参数上传文件,适用于 multipart/form-data 格式。

import requests

url = 'https://api.example.com/upload'
file_path = 'example.txt'

with open(file_path, 'rb') as f:
    files = {'file': f}
    response = requests.post(url, files=files)

print(response.status_code)
print(response.text)

代码逻辑分析:
- 使用 with open() 打开文件为二进制模式。
- files 参数接受一个字典,键为表单字段名,值为文件对象。
- 服务器返回状态码和响应内容。

文件下载

下载文件时可以使用 stream=True 参数避免一次性加载大文件。

import requests

url = 'https://example.com/large_file.zip'
response = requests.get(url, stream=True)

with open('downloaded_file.zip', 'wb') as f:
    for chunk in response.iter_content(chunk_size=8192):
        if chunk:
            f.write(chunk)

print("Download completed.")

代码逻辑分析:
- stream=True 表示以流式方式下载,适用于大文件。
- iter_content() 方法按块读取响应内容。
- chunk_size=8192 指定每次读取的大小(单位为字节)。

3.3 响应处理与异常捕获

3.3.1 响应内容解析与编码处理

HTTP 响应内容通常包括文本、JSON、HTML 等格式,Requests 提供了多种方法来解析响应内容。

import requests

response = requests.get('https://api.example.com/data')

# 获取文本内容
print(response.text)

# 获取字节内容
print(response.content)

# 获取JSON数据
try:
    data = response.json()
    print(data)
except requests.exceptions.JSONDecodeError:
    print("Response is not JSON format.")

代码逻辑分析:
- response.text :自动解码响应内容,适用于文本数据。
- response.content :原始字节流,适用于二进制数据。
- response.json() :尝试将响应内容解析为 JSON 格式,若失败则抛出异常。

3.3.2 状态码判断与重定向处理

HTTP 状态码用于表示请求的结果,常见的有 2xx(成功)、3xx(重定向)、4xx(客户端错误)、5xx(服务器错误)。

import requests

response = requests.get('https://api.example.com/data')

# 判断状态码
if response.status_code == 200:
    print("请求成功")
elif 300 <= response.status_code < 400:
    print("重定向中")
elif 400 <= response.status_code < 500:
    print("客户端错误")
elif 500 <= response.status_code < 600:
    print("服务器错误")
else:
    print("未知错误")

# 查看是否发生重定向
if response.history:
    print("请求发生了重定向")
    for resp in response.history:
        print(f"重定向到: {resp.url}")

代码逻辑分析:
- response.status_code 获取响应状态码。
- response.history 存储了所有重定向的响应对象。

3.3.3 异常类型与错误处理机制

Requests 提供了丰富的异常类,便于开发者捕获并处理不同类型的错误。

import requests
from requests.exceptions import ConnectionError, Timeout, HTTPError

try:
    response = requests.get('https://api.example.com/data', timeout=5)
    response.raise_for_status()
except ConnectionError:
    print("连接失败,请检查网络")
except Timeout:
    print("请求超时")
except HTTPError as e:
    print(f"HTTP错误:{e.response.status_code}")
except Exception as e:
    print(f"发生其他错误:{e}")

代码逻辑分析:
- raise_for_status() :如果响应状态码不是 2xx,抛出 HTTPError
- timeout :设置请求超时时间(单位秒)。
- 使用多个 except 捕获不同类型的异常,提高程序健壮性。

3.4 会话对象与Cookie管理

3.4.1 Session对象的使用

Requests 提供了 Session 对象用于持久化请求,可以跨请求保持 Cookie、设置默认请求头等。

import requests

# 创建会话对象
session = requests.Session()

# 设置默认请求头
session.headers.update({
    'User-Agent': 'MyApp/1.0'
})

# 发送请求
response1 = session.get('https://api.example.com/page1')
response2 = session.get('https://api.example.com/page2')

print(response1.cookies.get_dict())
print(response2.cookies.get_dict())

代码逻辑分析:
- Session 对象在整个会话期间保持 Cookie。
- 可以设置默认请求头、认证信息等,减少重复代码。

3.4.2 持久化请求与Cookie自动管理

Session 会自动管理 Cookie,适用于需要登录状态的爬虫。

import requests

session = requests.Session()

# 登录请求
login_data = {
    'username': 'test',
    'password': '123456'
}
session.post('https://api.example.com/login', data=login_data)

# 后续请求自动携带 Cookie
profile = session.get('https://api.example.com/profile')
print(profile.text)

代码逻辑分析:
- 登录后,服务器返回的 Cookie 被 Session 自动保存。
- 后续请求无需手动设置 Cookie,Session 会自动附加。

3.4.3 手动设置Cookie进行身份验证

有时需要手动设置 Cookie,例如从浏览器复制 Cookie 进行调试。

import requests

session = requests.Session()

# 手动设置 Cookie
session.cookies.update({
    'sessionid': 'abc123xyz',
    'csrftoken': 'csrf123'
})

# 发送请求
response = session.get('https://api.example.com/protected')
print(response.text)

代码逻辑分析:
- 使用 session.cookies.update() 方法设置 Cookie。
- 可用于模拟登录或绕过部分验证机制。

本章总结

第三章详细介绍了 Python 中 Requests 库的使用方法,包括 GET 和 POST 请求的参数传递、自定义请求头、文件上传下载、响应处理与异常捕获,以及会话管理与 Cookie 操作。这些内容构成了网络请求的基础,为后续爬虫项目开发打下坚实基础。

4. BeautifulSoup解析HTML实战

在现代网络爬虫开发中,HTML解析是数据提取的关键环节。BeautifulSoup 作为 Python 中最强大的 HTML 解析库之一,凭借其灵活的 API 和对复杂 HTML 结构的友好支持,广泛应用于网页数据提取任务中。本章将从安装与基础使用入手,逐步深入讲解 HTML 解析的核心技术、实战技巧以及性能优化策略,帮助开发者掌握从简单页面提取到复杂结构处理的完整流程。

4.1 BeautifulSoup库概述与安装

BeautifulSoup 是一个用于解析 HTML 和 XML 文档的 Python 库,特别适合从网页中提取数据。它能够自动将输入文档转换为 Unicode 编码,并构建文档树,使得开发者可以轻松地通过标签名、类名、ID 等方式查找和操作页面元素。

4.1.1 安装与基本用法

要使用 BeautifulSoup,首先需要通过 pip 安装:

pip install beautifulsoup4

安装完成后,可以通过以下方式导入并使用:

from bs4 import BeautifulSoup

html = """
<html>
<head><title>示例页面</title></head>
<body>
  <h1 class="title">Hello BeautifulSoup</h1>
  <p id="content">这是一个用于演示的段落。</p>
</body>
</html>

soup = BeautifulSoup(html, "html.parser")
print(soup.title.string)  # 输出:示例页面
print(soup.h1['class'])   # 输出:['title']
print(soup.p.text)        # 输出:这是一个用于演示的段落。

代码解释:

  • BeautifulSoup(html, "html.parser") :创建一个 BeautifulSoup 对象,使用内置的 html.parser 解析器。
  • soup.title.string :获取 <title> 标签内的文本内容。
  • soup.h1['class'] :访问 <h1> 标签的 class 属性。
  • soup.p.text :提取 <p> 标签的文本内容。

4.1.2 支持的解析器(html.parser、lxml、html5lib)

BeautifulSoup 支持多种解析器,开发者可以根据需求选择最适合的一种:

解析器 描述 优点 缺点
html.parser Python 标准库中的 HTML 解析器 无需额外安装 解析速度较慢,容错性一般
lxml 使用 C 实现的解析器,支持 HTML 和 XML 解析速度快,容错性强 需要安装 lxml 模块
html5lib 按照 HTML5 规范解析文档,适合解析不规范的 HTML 极强的容错能力,生成标准 DOM 速度慢,依赖较多外部库

安装 lxml:

pip install lxml

使用 lxml 解析 HTML:

soup = BeautifulSoup(html, "lxml")

mermaid 流程图展示解析器选择逻辑:

graph TD
    A[开始] --> B{是否需要快速解析?}
    B -->|是| C[lxml]
    B -->|否| D{是否需要兼容 HTML5?}
    D -->|是| E[html5lib]
    D -->|否| F[html.parser]

4.2 HTML结构解析与元素定位

掌握 HTML 结构的解析与元素定位技巧,是使用 BeautifulSoup 进行数据提取的基础。BeautifulSoup 提供了多种方式来查找和操作 HTML 元素,包括基于标签名、属性、类名等方式的查找。

4.2.1 标签查找与层级遍历

可以通过 find() find_all() 方法查找标签:

# 查找第一个 <p> 标签
first_p = soup.find("p")
print(first_p)

# 查找所有 <p> 标签
all_ps = soup.find_all("p")
for p in all_ps:
    print(p)

层级遍历:

BeautifulSoup 提供了多种方式遍历文档树:

# 父节点
print(first_p.parent.name)

# 子节点
children = first_p.children
for child in children:
    print(child)

# 所有后代节点
descendants = first_p.descendants
for d in descendants:
    print(d)

4.2.2 属性获取与内容提取

提取标签的属性值和文本内容是数据提取的核心操作:

# 获取属性
h1_tag = soup.find("h1")
print(h1_tag.get("class"))  # 输出:['title']

# 获取文本内容
print(h1_tag.text)  # 输出:Hello BeautifulSoup

4.2.3 多标签匹配与结果过滤

可以通过传递多个标签名或使用正则表达式进行更灵活的匹配:

# 查找 <h1> 或 <p> 标签
tags = soup.find_all(["h1", "p"])
for tag in tags:
    print(tag.name, tag.text)

# 查找 class 包含 'title' 的所有标签
title_tags = soup.find_all(class_="title")
for tag in title_tags:
    print(tag.name, tag.text)

代码解释:

  • find_all(["h1", "p"]) :同时匹配多个标签。
  • class_="title" :由于 class 是 Python 的关键字,因此使用 class_ 来匹配 class 属性。

4.3 数据提取实战技巧

在实际项目中,HTML 页面往往结构复杂,数据嵌套深、格式不规范。掌握高级提取技巧对于高效爬取数据至关重要。

4.3.1 提取文本与属性值

在实际开发中,往往需要提取多个字段并组合成结构化数据:

data = {
    "title": soup.title.string,
    "h1_text": soup.h1.text,
    "p_content": soup.find("p", id="content").text
}

print(data)

4.3.2 处理嵌套结构与复杂页面

当页面中存在多层嵌套结构时,可通过多层查找提取数据:

# 示例 HTML
html_complex = """
<div class="article">
  <h2>文章标题</h2>
  <div class="content">
    <p>正文内容1</p>
    <p>正文内容2</p>
  </div>
</div>

soup_complex = BeautifulSoup(html_complex, "lxml")

# 提取嵌套结构中的内容
article_title = soup_complex.find("div", class_="article").h2.text
content_ps = soup_complex.find("div", class_="content").find_all("p")

print("标题:", article_title)
for p in content_ps:
    print("段落:", p.text)

4.3.3 结合正则表达式提取非结构化信息

有时候页面中包含不规则结构的信息,可以结合 re 模块进行模糊匹配:

import re

# 提取所有以 "段落" 开头的文本
pattern = re.compile(r"段落.*")
matches = soup.find_all(text=pattern)

for match in matches:
    print(match)

4.4 性能优化与常见问题处理

在处理大型 HTML 页面或高频爬取任务时,BeautifulSoup 的性能表现直接影响程序效率。合理优化解析策略和处理异常情况是保障程序稳定运行的关键。

4.4.1 提高解析效率的技巧

  • 选择高效解析器 :优先使用 lxml 解析器。
  • 避免全量解析 :只解析需要的部分 HTML 内容。
  • 缓存查找结果 :避免重复查找相同标签。
# 避免重复查找
all_links = soup.find_all("a")
for link in all_links:
    print(link.get("href"))

4.4.2 大型页面处理策略

处理大型页面时,可以采用分段解析或流式解析策略:

from bs4.builder._parser import ParserRejectedMarkup

try:
    with open("large_page.html", "r", encoding="utf-8") as f:
        html_large = f.read()
    soup_large = BeautifulSoup(html_large, "lxml")
except ParserRejectedMarkup:
    print("页面内容被解析器拒绝,尝试其他方式")

4.4.3 解析失败的常见原因与解决方案

问题原因 表现 解决方案
页面内容为空或不完整 报错或返回 None 检查请求是否成功,使用异常处理
使用了不支持的解析器 报错或解析结果异常 更换为 lxml html5lib
页面使用了 JavaScript 渲染 HTML 中无目标数据 改用 Selenium 或 Puppeteer
标签名称或属性书写错误 无法找到目标元素 检查 HTML 源码,使用调试工具

异常处理示例:

try:
    title = soup.title.string
except AttributeError:
    print("标题标签不存在")

以上内容从 BeautifulSoup 的基础安装与使用出发,逐步深入到 HTML 解析、数据提取、性能优化和异常处理等多个方面,帮助开发者构建完整的数据提取能力。后续章节将继续介绍更高级的爬虫框架与实战技巧。

5. Scrapy框架搭建与项目结构

Scrapy 是一个用于大规模网络爬取的强大框架,专为高效抓取网页数据而设计。它不仅提供了完整的请求调度、数据解析、持久化等功能,还支持中间件机制、异步处理、日志系统和分布式部署。本章将从 Scrapy 的安装配置、项目结构解析、核心组件剖析到请求调度与中间件机制进行深入探讨,最后讲解如何部署和调试 Scrapy 项目,帮助开发者构建稳定高效的爬虫系统。

5.1 Scrapy框架概述与环境搭建

5.1.1 Scrapy的特点与优势

Scrapy 是一个基于 Python 的开源网络爬虫框架,其设计目标是高效、可扩展和可维护。主要特点如下:

特性 说明
异步处理 基于 Twisted 库实现异步 I/O,提升爬取效率
内置中间件 支持请求拦截、代理设置、User-Agent轮换等
可扩展性强 可自定义 Spider、Pipeline、Middleware 等组件
数据流清晰 从请求到解析再到存储流程清晰
支持多种导出格式 JSON、CSV、XML、MongoDB、MySQL 等
社区活跃 文档完善,社区支持广泛,生态丰富

5.1.2 安装与依赖配置

Scrapy 可通过 pip 安装,但需注意依赖环境的配置:

pip install scrapy

常见问题及解决方案:

  • Windows 系统缺少依赖 :需要安装 Microsoft Visual C++ Build Tools。
  • Twisted 安装失败 :建议使用 pip install twisted 单独安装后再装 Scrapy。
  • PyOpenSSL 报错 :升级或安装 pyopenssl

验证安装:

scrapy version

输出类似:

Scrapy 2.6.1

5.2 Scrapy项目结构与核心组件

5.2.1 工程目录结构详解

创建一个 Scrapy 项目非常简单,使用如下命令:

scrapy startproject example

生成的目录结构如下:

example/
├── scrapy.cfg
├── example/
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders/
│       └── __init__.py
└── tutorials/

各文件作用:

文件 作用
scrapy.cfg 项目配置文件,用于部署和运行
items.py 定义数据模型(Item)
middlewares.py 自定义中间件逻辑
pipelines.py 数据处理流水线
settings.py 配置项(如 User-Agent、下载延迟等)
spiders/ 存放爬虫类文件

5.2.2 Spider爬虫类与解析逻辑

Spider 是 Scrapy 的核心组件,负责发送请求和解析响应。以下是一个基本的 Spider 示例:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/']

    def parse(self, response):
        yield {
            'title': response.xpath('//h1/text()').get(),
            'url': response.url
        }

代码解析:

  • name :爬虫名称,启动时使用。
  • allowed_domains :限制爬取域名。
  • start_urls :起始爬取地址。
  • parse 方法:解析响应内容,返回提取的数据。

yield 机制:

yield 是 Python 的生成器语法,Scrapy 使用它将提取的数据传入后续的 Pipeline 处理流程。

5.2.3 Item数据模型定义

Item 是结构化数据的容器,定义数据字段:

import scrapy

class ExampleItem(scrapy.Item):
    title = scrapy.Field()
    url = scrapy.Field()
    content = scrapy.Field()

优势:

  • 数据字段清晰,便于后期处理。
  • 支持字段验证与类型转换。
  • 提高代码可维护性。

5.2.4 Pipeline数据处理流程

Pipeline 用于处理提取的数据,如清洗、验证、存储等。以下是一个存储到 JSON 的示例:

import json

class JsonPipeline:
    def open_spider(self, spider):
        self.file = open('output.json', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

Pipeline 方法说明:

  • open_spider() :爬虫启动时执行。
  • close_spider() :爬虫结束时执行。
  • process_item() :每条数据都会经过此方法。

启用 Pipeline:

settings.py 中配置:

ITEM_PIPELINES = {
    'example.pipelines.JsonPipeline': 300,
}

5.3 Scrapy请求调度与中间件

5.3.1 下载器中间件配置

中间件(Middleware)用于拦截请求和响应,实现如代理设置、User-Agent 轮换、请求重试等。

启用中间件:

settings.py 中:

DOWNLOADER_MIDDLEWARES = {
    'example.middlewares.RandomUserAgentMiddleware': 543,
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
}

自定义中间件示例:

import random

class RandomUserAgentMiddleware:
    def process_request(self, request, spider):
        ua_list = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15'
        ]
        request.headers['User-Agent'] = random.choice(ua_list)

说明:

  • process_request() :在请求发送前处理。
  • 设置随机 User-Agent,有助于规避反爬机制。

5.3.2 请求调度机制与去重策略

Scrapy 使用 Scheduler 模块管理请求队列,支持去重机制。

去重原理:

  • 默认使用 RFPDupeFilter ,基于指纹去重。
  • 使用 scrapy.dupefilters 包,支持自定义去重逻辑。

开启去重:

DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'

自定义去重逻辑:

from scrapy.dupefilters import RFPDupeFilter

class CustomDupeFilter(RFPDupeFilter):
    def request_seen(self, request):
        # 自定义指纹生成逻辑
        fp = request.url.split('?')[0]
        if fp in self.fingerprints:
            return True
        self.fingerprints.add(fp)
        return False

5.3.3 自定义中间件开发实践

中间件是 Scrapy 框架中最为灵活的组件之一,可用于请求拦截、响应修改、代理轮换等。

示例:请求重试中间件

class RetryMiddleware:
    def process_response(self, request, response, spider):
        if response.status in [500, 502, 503]:
            retries = request.meta.get('retry_times', 0)
            if retries < 3:
                request.meta['retry_times'] = retries + 1
                return request.copy()
        return response

说明:

  • 当响应码为 500 类错误时,自动重试最多 3 次。
  • 利用 meta 字段传递状态信息。

5.4 Scrapy部署与调试

5.4.1 日志查看与调试技巧

Scrapy 内置了强大的日志系统,可通过配置日志级别进行调试:

LOG_LEVEL = 'DEBUG'  # 可选 DEBUG、INFO、WARNING、ERROR、CRITICAL

日志输出示例:

2023-10-01 12:00:00 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.example.com/>

调试技巧:

  • 使用 scrapy shell 进入交互式调试环境。
  • 使用 response.css() response.xpath() 快速测试解析逻辑。
  • 设置 DOWNLOAD_DELAY 延迟请求,避免被封禁。

5.4.2 数据导出格式配置(JSON、CSV等)

Scrapy 支持多种数据导出格式:

scrapy crawl example -o output.json

常用格式:

格式 示例
JSON -o output.json
CSV -o output.csv
XML -o output.xml
MySQL 配合 Pipeline 写入数据库

CSV 导出示例:

scrapy crawl example -o output.csv -t csv

CSV 输出内容:

title,url
"Example Domain","http://www.example.com/"

5.4.3 使用Scrapyd进行分布式部署

Scrapyd 是 Scrapy 的部署服务,支持远程调度、任务管理和日志查看。

安装 Scrapyd:

pip install scrapyd

配置 Scrapyd 服务:

创建 scrapyd.conf 文件:

[scrapyd]
eggs_dir = eggs
logs_dir = logs
items_dir = items
jobs_to_keep = 5

打包项目并部署:

scrapy deploy

远程运行爬虫:

curl http://localhost:6800/schedule.json -d project=default -d spider=example

部署架构流程图:

graph TD
A[Scrapy 项目] --> B(打包部署)
B --> C[Scrapyd 服务]
C --> D[任务调度]
D --> E[爬虫执行]
E --> F[日志与结果输出]

通过本章的详细讲解,我们从 Scrapy 的安装配置入手,逐步深入到项目结构、核心组件、请求调度、中间件开发以及部署调试等多个方面,全面掌握了 Scrapy 框架的使用方式和构建爬虫系统的流程。下一章我们将介绍 Selenium 的使用,解决动态页面抓取难题。

6. Selenium模拟浏览器操作

在现代网页中,越来越多的页面内容依赖于 JavaScript 动态加载,传统的基于 HTTP 请求的爬虫(如 Requests)往往无法获取完整的页面内容。Selenium 是一个强大的浏览器自动化工具,能够模拟用户操作浏览器,真实地渲染页面内容,是处理动态加载网页的理想选择。

本章将详细介绍 Selenium 的使用方法,涵盖环境搭建、元素定位、页面操作、动态页面抓取等内容,帮助开发者高效构建可应对复杂网页结构的爬虫系统。

6.1 Selenium概述与环境准备

Selenium 是一个开源的自动化测试工具,广泛用于 Web 应用的功能测试和 UI 自动化。它通过控制真实浏览器(如 Chrome、Firefox、Edge 等)来模拟用户的操作行为,从而可以获取完整的页面 DOM 结构和动态渲染内容。

6.1.1 Selenium的优势与适用场景

Selenium 的核心优势在于其 真实浏览器渲染能力 ,适用于以下场景:

场景 描述
动态页面抓取 页面内容通过 JavaScript 异步加载(如 AJAX)
用户行为模拟 模拟点击、输入、下拉、滚动等用户操作
登录验证绕过 自动填写用户名密码完成登录
页面截图与测试 获取网页截图用于测试或存档
复杂表单交互 自动化填写、提交复杂表单

Selenium 支持多种浏览器,如 Chrome、Firefox、Edge、Safari 等,并提供多语言接口,包括 Python、Java、C# 等,非常适合 Python 爬虫开发。

6.1.2 安装与浏览器驱动配置

安装 Selenium

使用 pip 安装 Selenium:

pip install selenium
浏览器驱动配置

Selenium 依赖浏览器驱动来与浏览器进行通信。不同浏览器需要对应的驱动程序:

浏览器 驱动名称 官网
Chrome chromedriver https://sites.google.com/chromium.org/driver/
Firefox geckodriver https://github.com/mozilla/geckodriver
Edge edgedriver https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/

安装完成后,将驱动程序路径添加到系统环境变量中,或在代码中指定驱动路径。

示例:启动 Chrome 浏览器

from selenium import webdriver

# 指定chromedriver路径
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')

# 打开网页
driver.get("https://www.baidu.com")

# 关闭浏览器
driver.quit()

代码逻辑分析:

  • webdriver.Chrome() 初始化一个 Chrome 浏览器实例。
  • get() 方法用于打开指定的 URL。
  • quit() 方法关闭浏览器并释放资源。

6.2 元素定位与页面操作

Web 页面由 HTML 构成,Selenium 通过定位 HTML 元素来进行交互。准确的元素定位是实现自动化操作的前提。

6.2.1 定位方式(ID、XPath、CSS选择器等)

Selenium 提供多种元素定位方式,常用的有:

定位方式 语法 示例
ID find_element(By.ID, "id") find_element(By.ID, "username")
Name find_element(By.NAME, "name") find_element(By.NAME, "password")
XPath find_element(By.XPATH, "xpath") find_element(By.XPATH, "//input[@id='submit']")
CSS选择器 find_element(By.CSS_SELECTOR, "selector") find_element(By.CSS_SELECTOR, "input[type='text']")
Link Text find_element(By.LINK_TEXT, "text") find_element(By.LINK_TEXT, "登录")
Partial Link Text find_element(By.PARTIAL_LINK_TEXT, "部分文本") find_element(By.PARTIAL_LINK_TEXT, "登")

示例:使用 CSS 选择器定位百度搜索框并输入内容

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")

# 定位搜索框并输入内容
search_box = driver.find_element(By.CSS_SELECTOR, "#kw")
search_box.send_keys("Selenium 教程")

# 提交搜索
search_box.submit()

driver.quit()

代码逻辑分析:

  • find_element() 用于定位页面元素。
  • send_keys() 方法模拟键盘输入。
  • submit() 方法用于提交表单。

6.2.2 常见操作(点击、输入、下拉等)

点击操作
button = driver.find_element(By.XPATH, "//button[@id='submit']")
button.click()
输入操作
username = driver.find_element(By.NAME, "username")
username.send_keys("test_user")
下拉菜单选择

使用 Select 类处理下拉菜单:

from selenium.webdriver.support.ui import Select

select = Select(driver.find_element(By.ID, 'country'))
select.select_by_visible_text('China')

6.2.3 显式等待与隐式等待机制

由于网页加载速度不一致,直接定位元素可能失败。Selenium 提供了两种等待机制:

隐式等待(Implicit Wait)

全局等待,适用于整个 WebDriver 生命周期。

driver.implicitly_wait(10)  # 最多等待10秒
显式等待(Explicit Wait)

针对特定条件等待,更加灵活可靠。

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "result"))
    )
finally:
    driver.quit()

流程图:显式等待执行流程

graph TD
    A[开始等待] --> B{元素是否出现?}
    B -->|是| C[返回元素]
    B -->|否| D[等待指定时间]
    D --> B
    C --> E[执行下一步操作]

6.3 浏览器自动化与动态页面抓取

现代网页大量使用 JavaScript 动态加载内容,传统爬虫无法获取完整页面数据。Selenium 可以通过执行 JavaScript、处理 AJAX 请求、模拟用户交互等方式,实现动态页面的完整抓取。

6.3.1 动态加载页面的处理方案

方案一:等待元素出现(推荐)

使用 WebDriverWait 等待关键元素加载完成。

element = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located((By.CLASS_NAME, "dynamic-content"))
)

方案二:滚动页面触发加载

模拟用户滚动页面以触发内容加载:

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

6.3.2 执行JavaScript脚本

Selenium 支持直接执行 JavaScript 脚本,常用于操作页面、获取数据、绕过反爬等。

示例:获取页面滚动高度

height = driver.execute_script("return document.body.scrollHeight")
print(f"页面高度为:{height}")

示例:修改页面样式

driver.execute_script("document.getElementById('header').style.display='none';")

6.3.3 截图与页面状态保存

Selenium 支持截图功能,方便调试和记录页面状态。

全屏截图

driver.save_screenshot("screenshot.png")

元素截图

element = driver.find_element(By.ID, "login-form")
element.screenshot("form_screenshot.png")

页面源码获取

html = driver.page_source
with open("page.html", "w", encoding="utf-8") as f:
    f.write(html)

总结与延伸

Selenium 是处理动态网页内容的强大工具,通过模拟真实浏览器操作,能够有效绕过反爬机制、抓取异步加载内容、模拟用户行为等。结合 WebDriverWait、JavaScript 脚本执行和截图功能,开发者可以构建出高度自动化、稳定可靠的网页爬虫系统。

在下一章中,我们将探讨如何将爬取的数据进行持久化存储,包括 CSV、JSON 和 MySQL 数据库的写入方式,为构建完整的数据采集系统打下基础。

7. 数据存储:CSV、JSON、MySQL写入实战

在爬虫开发过程中,数据的采集只是第一步,如何高效、安全地存储和管理数据是整个流程中至关重要的环节。本章将详细介绍爬虫数据的几种常见存储方式:CSV、JSON 和 MySQL,并通过实际操作示例,展示如何将爬取的数据写入这些存储介质。

7.1 数据存储方式概述

在数据存储中,我们需要根据数据量、结构化程度、查询需求和长期维护等因素选择合适的存储格式或数据库。

存储方式 特点 适用场景
CSV 简单、轻量,适合表格型数据 小型数据集、快速导出、Excel兼容
JSON 支持嵌套结构,可读性好 API接口数据、非结构化数据
MySQL 结构化强、查询高效、支持事务 需频繁查询、更新、多用户并发的数据系统

在实际项目中,常常会将多种方式结合使用,例如先将原始数据以 JSON 格式暂存,再清洗后导入 MySQL 数据库进行长期管理。

7.2 CSV与JSON存储实践

7.2.1 使用Python标准库写入CSV

Python 标准库 csv 提供了便捷的 CSV 文件操作方法。以下是一个将爬取的书籍信息写入 CSV 的示例:

import csv

# 假设这是爬取到的数据
data = [
    {'title': 'Python编程从入门到实践', 'author': 'Eric Matthes', 'price': '69.00'},
    {'title': '流畅的Python', 'author': 'Luciano Ramalho', 'price': '109.00'},
    {'title': '算法导论', 'author': 'Thomas H. Cormen', 'price': '128.00'}
]

# 写入CSV
with open('books.csv', mode='w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=['title', 'author', 'price'])
    writer.writeheader()  # 写入表头
    writer.writerows(data)  # 写入数据行

参数说明:

  • fieldnames : 定义CSV列的顺序。
  • newline='' : 防止在Windows系统下出现空行。
  • DictWriter : 支持字典格式写入,适用于结构化数据。

7.2.2 JSON格式构建与数据序列化

json 模块用于将 Python 对象序列化为 JSON 字符串或文件。适用于需要嵌套结构或API交互的场景。

import json

# 写入JSON文件
with open('books.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

参数说明:

  • ensure_ascii=False : 保证中文字符不被转义。
  • indent=4 : 美化输出格式,增加缩进,便于阅读。

7.2.3 大文件写入优化策略

当数据量较大时(如百万级以上),建议采用以下策略优化写入效率:

  • 分块写入(Chunking) :将数据按批次写入,避免一次性加载内存。
  • 使用生成器 :逐条生成数据逐条写入,节省内存。
  • 使用 csv.writer 而非 DictWriter :在不需字段名时, writer 性能更高。

7.3 数据库存储与MySQL操作

MySQL 是结构化数据库的代表,适用于需要持久化、支持查询、事务等操作的场景。Python 中可通过 PyMySQL SQLAlchemy 实现数据库写入。

7.3.1 MySQL数据库连接与配置

首先确保安装 MySQL 服务器并创建数据库和表结构:

CREATE DATABASE crawler_db;
USE crawler_db;

CREATE TABLE books (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    author VARCHAR(255),
    price DECIMAL(10, 2)
);

7.3.2 使用PyMySQL与SQLAlchemy进行数据写入

PyMySQL 示例:
import pymysql

# 连接数据库
conn = pymysql.connect(
    host='localhost',
    user='root',
    password='yourpassword',
    database='crawler_db',
    charset='utf8mb4'
)

cursor = conn.cursor()

# 插入数据
for item in data:
    sql = "INSERT INTO books (title, author, price) VALUES (%s, %s, %s)"
    cursor.execute(sql, (item['title'], item['author'], float(item['price'])))

conn.commit()
cursor.close()
conn.close()
SQLAlchemy 示例(推荐):
from sqlalchemy import create_engine, Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 定义模型
Base = declarative_base()

class Book(Base):
    __tablename__ = 'books'
    id = Column(Integer, primary_key=True)
    title = Column(String(255))
    author = Column(String(255))
    price = Column(Float)

# 创建引擎与会话
engine = create_engine('mysql+pymysql://root:yourpassword@localhost/crawler_db')
Session = sessionmaker(bind=engine)
session = Session()

# 插入数据
for item in data:
    book = Book(title=item['title'], author=item['author'], price=float(item['price']))
    session.add(book)

session.commit()
session.close()

7.3.3 数据去重与批量插入优化

为避免重复插入相同数据,可在数据库中添加唯一索引:

ALTER TABLE books ADD UNIQUE (title, author);

批量插入时可使用以下方法:

cursor.executemany(sql, values_list)  # 批量执行SQL语句

7.3.4 异常处理与事务管理

良好的数据库操作应包含异常处理与事务控制:

try:
    for item in data:
        sql = "INSERT INTO books (title, author, price) VALUES (%s, %s, %s)"
        cursor.execute(sql, (item['title'], item['author'], float(item['price'])))
    conn.commit()
except Exception as e:
    conn.rollback()  # 出错回滚
    print("插入失败:", e)
finally:
    cursor.close()
    conn.close()

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:网络爬虫是获取互联网数据的重要工具,Python凭借其简洁语法和丰富库支持,成为爬虫开发的首选语言。本文系统讲解Python网络爬虫的核心知识,涵盖HTTP/HTTPS协议基础、HTML结构解析、常用爬虫库(如Requests、BeautifulSoup、Scrapy、Selenium)、爬虫流程设计、反反爬策略以及实战案例。通过本项目学习,读者能够掌握从网页抓取到数据存储的完整流程,并具备应对复杂网页结构和反爬机制的能力。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐