
- HTML提取:使用 Python 库(如
requests)从网页获取 HTML 内容。 - HTML解析:使用解析器(如
BeautifulSoup或lxml)从 HTML 中提取你想要的数据。 - 数据库存储:使用数据库连接库(如
sqlite3、psycopg2、pymysql或SQLAlchemy)将提取的数据存入数据库。
第一步:准备工作 - 安装必要的库
你需要安装几个关键的 Python 库,打开你的终端或命令行,运行以下命令:
# 用于发送 HTTP 请求,获取网页内容 pip install requests # 用于解析 HTML/XML 文档,非常强大且易用 pip install beautifulsoup4 # 用于数据库操作(这里以 SQLite 为例,它是 Python 内置的) # 如果你使用 MySQL/PostgreSQL,需要安装对应的驱动,如 pip install pymysql 或 pip install psycopg2 pip install lxml # 作为 BeautifulSoup 的解析器,速度更快
第二步:HTML 提取与解析
我们将使用 requests 和 BeautifulSoup 来完成这个任务,假设我们要从一个电商网站(http://books.toscrape.com/,这是一个专为练习设计的数据抓取网站)上抓取书籍信息。
目标: 抓取每本书的标题、价格和评分。
示例代码:extract_data.py
import requests
from bs4 import BeautifulSoup
def scrape_books(url):
"""
从指定 URL 抓取书籍数据
"""
try:
# 1. 发送 HTTP GET 请求
# headers 模拟浏览器访问,避免被一些网站屏蔽
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers=headers)
# 检查请求是否成功 (状态码 200)
response.raise_for_status()
# 2. 解析 HTML
# 使用 'lxml' 解析器,也可以使用 'html.parser' (Python 内置)
soup = BeautifulSoup(response.text, 'lxml')
# 3. 提取数据
books_data = []
# 找到所有书籍的容器
books = soup.find_all('article', class_='product_pod')
for book in books:
title = book.h3.a['title']
price = book.find('p', class_='price_color').text
rating = book.p['class'][1] # 评分在 class 属性中,如 'star-rating Three'
# 将提取的数据整理成字典
books_data.append({
'title': title,
'price': price,
'rating': rating
})
return books_data
except requests.exceptions.RequestException as e:
print(f"请求错误: {e}")
return None
except Exception as e:
print(f"解析错误: {e}")
return None
# --- 执行抓取 ---
if __name__ == "__main__":
target_url = "http://books.toscrape.com/"
scraped_books = scrape_books(target_url)
if scraped_books:
for book in scraped_books:
print(book)
代码解释:

requests.get(url, headers=headers): 向目标 URL 发送 GET 请求。headers用来模拟浏览器,防止被反爬虫机制拦截。response.raise_for_status(): 如果请求失败(404 Not Found 或 500 Server Error),这行代码会抛出一个异常。BeautifulSoup(response.text, 'lxml'): 将获取到的 HTML 内容 (response.text) 传给BeautifulSoup,并指定使用lxml解析器来创建一个解析树对象soup。soup.find_all('article', class_='product_pod'): 这是BeautifulSoup的核心功能,它会查找所有<article>标签,并且这些标签的class属性包含product_pod,这返回一个列表。- 循环提取: 在
for循环中,我们对每个书籍容器进行更精细的查找:book.h3.a['title']: 先找到h3标签,再找到其下的a标签,然后获取其title属性的值。book.find('p', class_='price_color').text: 找到class为price_color的p标签,并获取其内部的文本内容。book.p['class'][1]: 评分信息存储在p标签的class属性中,如star-rating Three,我们通过索引[1]来获取Three这个评级。
第三步:将数据存入数据库
现在我们有了抓取到的数据(一个包含字典的列表),下一步就是将它们存入数据库,我们将使用 SQLite 作为例子,因为它无需额外安装数据库服务器,非常适合演示。
设计数据库表
我们需要在数据库中创建一个表来存储书籍信息,表结构应该与我们抓取的数据字典的键对应。
| 字段名 | 数据类型 | 描述 |
|---|---|---|
id |
INTEGER |
主键,自动递增 |
price |
TEXT |
价格 (抓取时是字符串) |
rating |
TEXT |
评级 (如 'One', 'Two') |
完整代码:抓取 + 存储
我们将上面的抓取代码和数据库操作结合起来。
import requests
from bs4 import BeautifulSoup
import sqlite3 # Python 内置的 SQLite 库
# --- 数据库设置 ---
DB_NAME = 'books.db'
def create_database_table():
"""创建数据库和表"""
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
# 创建表,如果它不存在
# 使用 IF NOT EXISTS 防止重复创建
cursor.execute('''
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
price TEXT NOT NULL,
rating TEXT NOT NULL
)
''')
conn.commit()
conn.close()
print("数据库和表准备就绪。")
def insert_books_into_database(books_data):
"""将书籍数据插入数据库"""
if not books_data:
print("没有数据可插入。")
return
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
# 使用 ? 作为占位符,防止 SQL 注入
# executemany 可以高效地执行多条 INSERT 语句
cursor.executemany('''
INSERT INTO books (title, price, rating) VALUES (?, ?, ?)
''', [(book['title'], book['price'], book['rating']) for book in books_data])
conn.commit()
conn.close()
print(f"成功插入 {len(books_data)} 条数据到数据库。")
def scrape_books(url):
"""从指定 URL 抓取书籍数据 (同上)"""
try:
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
response = requests.get(url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'lxml')
books_data = []
books = soup.find_all('article', class_='product_pod')
for book in books:
title = book.h3.a['title']
price = book.find('p', class_='price_color').text
rating = book.p['class'][1]
books_data.append({'title': title, 'price': price, 'rating': rating})
return books_data
except requests.exceptions.RequestException as e:
print(f"请求错误: {e}")
return None
except Exception as e:
print(f"解析错误: {e}")
return None
# --- 主程序 ---
if __name__ == "__main__":
# 1. 准备数据库
create_database_table()
# 2. 抓取数据
target_url = "http://books.toscrape.com/"
scraped_books = scrape_books(target_url)
# 3. 存储数据
if scraped_books:
insert_books_into_database(scraped_books)
print("数据抓取和存储完成!")
else:
print("数据抓取失败。")
数据库代码解释:

sqlite3.connect(DB_NAME): 连接到一个名为books.db的 SQLite 数据库文件,如果文件不存在,它会自动创建。conn.cursor(): 创建一个游标对象,用于执行 SQL 命令。cursor.execute('''...'''): 执行一条 SQL 语句,我们用CREATE TABLE IF NOT EXISTS来确保脚本能多次运行而不会报错。conn.commit(): 非常重要! 在执行了INSERT,UPDATE,DELETE等修改数据的操作后,必须调用commit()来将更改保存到数据库。conn.close(): 关闭数据库连接。cursor.executemany(...): 这是批量插入数据的高效方式,它接受一个 SQL 模板和一个列表(列表中的每个元素都是一组参数)。 是参数占位符,它可以有效防止 SQL 注入攻击,强烈推荐使用。
进阶与最佳实践
使用 ORM (SQLAlchemy) 进行更高级的数据库操作
对于大型项目,直接写 SQL 语句会比较繁琐,ORM(Object-Relational Mapping,对象关系映射)库如 SQLAlchemy 允许你用 Python 类和对象来操作数据库,更加直观和强大。
示例 (SQLAlchemy + SQLite):
# 首先安装: pip install sqlalchemy
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 1. 定义模型 (Python 类)
Base = declarative_base()
class Book(Base):
__tablename__ = 'books_sqlalchemy' # 映射到数据库中的表名
id = Column(Integer, primary_key=True)= Column(String, nullable=False)
price = Column(String, nullable=False)
rating = Column(String, nullable=False)
def __repr__(self):
return f"<Book(title='{self.title}', price='{self.price}')>"
# 2. 创建数据库连接和引擎
# 'sqlite:///books.db' 表示连接到当前目录下的 books.db 文件
engine = create_engine('sqlite:///books.db')
# 3. 创建表 (如果不存在)
Base.metadata.create_all(engine)
# 4. 创建会话
Session = sessionmaker(bind=engine)
session = Session()
# 5. 插入数据 (使用 ORM)
# 假设 scraped_books 是之前抓取到的数据列表
for book_data in scraped_books:
# 创建一个新的 Book 对象
book_obj = Book(title=book_data['title'], price=book_data['price'], rating=book_data['rating'])
session.add(book_obj)
# 6. 提交会话
session.commit()
print(f"使用 SQLAlchemy 成功插入 {len(scraped_books)} 条数据。")
# 7. 查询数据示例
all_books = session.query(Book).all()
print("\n从数据库查询所有书籍:")
for book in all_books[:5]: # 只打印前5条
print(book)
session.close()
分页抓取
大多数网站不会把所有数据都放在一页,你需要处理分页。
# 在 scrape_books 函数中修改 URL
base_url = "http://books.toscrape.com/catalogue/page-{}.html"
all_books_data = []
for page_num in range(1, 51): # 假设最多50页
url = base_url.format(page_num)
print(f"正在抓取: {url}")
books_on_page = scrape_books(url) # 假设 scrape_books 返回一个列表或 None
if books_on_page:
all_books_data.extend(books_on_page)
else:
break # 如果某一页没有数据,就停止
# 最后将 all_books_data 存入数据库
insert_books_into_database(all_books_data)
处理 JavaScript 渲染的网站
像 requests 这样的库只能获取初始的 HTML,无法执行 JavaScript,如果网站内容是通过 JS 动态加载的,你需要使用 Selenium 或 Playwright 这样的浏览器自动化工具。
# 安装 Selenium 和对应浏览器的 WebDriver pip install selenium # 使用 Chrome 浏览器,需要下载 chromedriver 并配置到 PATH
Selenium 会启动一个真实的浏览器(或无头浏览器),访问网页,等待 JS 渲染完成后再获取最终的 HTML 源码,后续的解析步骤和 BeautifulSoup 是一样的。
| 步骤 | 工具/库 | 关键代码/概念 |
|---|---|---|
| HTML 提取 | requests |
requests.get(url, headers=headers) |
| HTML 解析 | BeautifulSoup |
soup.find(), soup.find_all(), tag.text, tag['attr'] |
| 数据库存储 | sqlite3 / SQLAlchemy |
CREATE TABLE, INSERT INTO, executemany, ORM 模型 |
| 进阶 | Selenium |
处理 JS 渲染的网页 |
通过以上步骤,你就可以构建一个完整的、从网页抓取数据并存入数据库的 Python 应用程序。
