当前位置: 首页 > news >正文

Python 爬虫入门:从数据爬取到转存 MySQL 数据库

前言

在本篇博客中,我们将介绍一个基础的 Python 爬虫项目,包括使用 requestsBeautifulSoup 进行网页数据爬取,并将获取的数据存储到 MySQL 数据库中。该项目适合初学者了解网络爬虫的基本流程以及如何将数据持久化存储。


一、项目目标

  • 学习使用 requests 发起 HTTP 请求获取网页内容。
  • 使用 BeautifulSoup 解析 HTML 页面并提取数据。
  • 将提取的数据保存到 MySQL 数据库中。
  • 掌握基本的数据库连接与操作方法。

二、环境准备

所需模块安装:

pip install requests beautifulsoup4 mysql-connector-python
  • requests: 用于发送 HTTP 请求。
  • beautifulsoup4: 用于解析 HTML 文档。
  • mysql-connector-python: 用于连接和操作 MySQL 数据库。

三、爬取目标网站示例

我们以爬取 豆瓣电影 Top250 页面为例,抓取以下信息:

  • 电影名称
  • 导演/主演
  • 上映年份
  • 豆瓣评分

四、代码实现与讲解

1. 网页爬取部分(使用 requests)

import requests
from bs4 import BeautifulSoup
import timeheaders = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0 Safari/537.36'
}def fetch_page(url):response = requests.get(url, headers=headers)if response.status_code == 200:return response.textelse:print(f"请求失败,状态码:{response.status_code}")return None

说明:

  • 使用 requests.get() 获取网页内容。
  • 设置 headers 模拟浏览器访问,防止被反爬机制屏蔽。
  • 若返回状态码为 200,则返回 HTML 内容。

2. 数据解析部分(使用 BeautifulSoup)

def parse_html(html):soup = BeautifulSoup(html, 'html.parser')movie_list = []for item in soup.find_all('div', class_='item'):rank = item.find('em').text.strip()title = item.find('span', class_='title').text.strip()info = item.find('div', class_='bd').p.text.strip().split('\n')[0]year = item.find('span', class_='year').text.strip()rating = item.find('span', class_='rating_num').text.strip()movie_list.append({'rank': rank,'title': title,'info': info,'year': year,'rating': rating})return movie_list

说明:

  • 使用 BeautifulSoup 解析 HTML 结构。
  • 查找每个电影条目 <div class="item">
  • 提取电影排名、名称、导演/演员信息、年份、评分等字段。
  • 将每部电影的信息以字典形式添加到列表中。

3. 存储到 MySQL 数据库部分

import mysql.connectordef save_to_mysql(data):conn = mysql.connector.connect(host='localhost',user='root',password='yourpassword',database='douban_movies')cursor = conn.cursor()# 创建表(如果不存在)create_table_sql = """CREATE TABLE IF NOT EXISTS top250 (id INT AUTO_INCREMENT PRIMARY KEY,rank VARCHAR(10),title VARCHAR(255),info TEXT,year VARCHAR(10),rating VARCHAR(10))"""cursor.execute(create_table_sql)# 插入数据insert_sql = """INSERT INTO top250 (rank, title, info, year, rating)VALUES (%s, %s, %s, %s, %s)"""for movie in data:cursor.execute(insert_sql, (movie['rank'],movie['title'],movie['info'],movie['year'],movie['rating']))conn.commit()cursor.close()conn.close()print("数据已成功插入数据库!")

说明:

  • 使用 mysql.connector.connect() 连接本地 MySQL 数据库。
  • 使用 SQL 建表语句创建 top250 表(若不存在)。
  • 使用参数化 SQL 插入数据,避免 SQL 注入。
  • 循环遍历所有电影数据并插入数据库。

4. 主程序入口

def main():all_movies = []base_url = "https://movie.douban.com/top250?start={}&filter="for i in range(0, 250, 25):  # 爬取前10页url = base_url.format(i)html = fetch_page(url)if html:movies = parse_html(html)all_movies.extend(movies)print(f"第 {i // 25 + 1} 页数据抓取完成,共 {len(movies)} 条记录")time.sleep(2)  # 避免频繁请求# 存储到数据库save_to_mysql(all_movies)if __name__ == '__main__':main()

说明:

  • 构造分页 URL 地址,循环爬取多页数据。
  • 每次请求后暂停 2 秒,防止被封 IP。
  • 最后统一将所有数据插入数据库。

五、数据库结构设计

CREATE DATABASE douban_movies;USE douban_movies;CREATE TABLE top250 (id INT AUTO_INCREMENT PRIMARY KEY,rank VARCHAR(10),title VARCHAR(255),info TEXT,year VARCHAR(10),rating VARCHAR(10)
);

六、运行结果示例

第 1 页数据抓取完成,共 25 条记录
第 2 页数据抓取完成,共 25 条记录
...
第 10 页数据抓取完成,共 25 条记录
数据已成功插入数据库!

MySQL 中的 top250 表将包含如下字段:

idranktitleinfoyearrating
11肖申克的救赎导演: 弗兰克·德拉邦特19949.7
..................

七、注意事项

  1. 反爬策略:实际部署时应设置合理的请求间隔,必要时使用代理 IP。
  2. 异常处理:建议增加异常捕获逻辑,如超时重试、页面解析错误等。
  3. 编码问题:注意网页编码是否为 UTF-8,必要时进行转换。
  4. 数据库安全:生产环境中应使用配置文件管理数据库账号密码,避免硬编码。

注:当然这个基础爬虫代码非常适合初学者入门,但在实际应用中还存在一些明显的缺点和潜在问题。下面我将从几个方面分析其不足之处,并给出相应的补偿措施或优化建议

八、代码缺点讲解

1. 缺乏异常处理机制

问题:
  • 网络请求可能失败(如超时、403/404 错误);
  • 页面结构变化可能导致解析失败;
  • 数据库连接失败或插入出错未做捕获。
补偿措施:
  • 使用 try-except 捕获异常;
  • 添加重试机制;
  • 日志记录错误信息以便排查。
def fetch_page(url):try:response = requests.get(url, headers=headers, timeout=10)if response.status_code == 200:return response.textelse:print(f"请求失败,状态码:{response.status_code}")return Noneexcept requests.RequestException as e:print(f"请求异常:{e}")return None

2. 数据解析依赖页面结构,稳定性差

问题:
  • 如果目标网站更新了 HTML 结构,解析会失败;
  • 没有做字段缺失判断,容易抛出 AttributeError
补偿措施:
  • 使用 .find() 或 .select() 前判断是否存在;
  • 使用 get_text(strip=True) 替代 .text.strip() 提高容错;
  • 对关键字段使用默认值。
title_tag = item.find('span', class_='title')
title = title_tag.text.strip() if title_tag else '未知标题'

3. 数据库操作效率低

问题:
  • 每次插入都建立一次数据库连接,效率低下;
  • 插入数据没有批量处理,速度慢。
补偿措施:
  • 将数据库连接提取到函数外,复用连接;
  • 使用 executemany() 批量插入数据。
def save_to_mysql(data):conn = mysql.connector.connect(...)cursor = conn.cursor()insert_sql = """INSERT INTO top250 (rank, title, info, year, rating)VALUES (%s, %s, %s, %s, %s)"""values = [(movie['rank'], movie['title'], movie['info'], movie['year'], movie['rating'])for movie in data]cursor.executemany(insert_sql, values)conn.commit()...

4. 无去重机制

问题:
  • 若多次运行脚本,会导致重复插入相同数据;
  • 缺乏唯一性校验或更新机制。
补偿措施:
  • 在数据库表中添加唯一索引(如电影名称 + 年份);
  • 插入前先查询是否已存在该条目;
  • 或者采用 INSERT IGNORE / ON DUPLICATE KEY UPDATE
ALTER TABLE top250 ADD UNIQUE (title, year);
insert_sql = """
INSERT IGNORE INTO top250 (rank, title, info, year, rating)
VALUES (%s, %s, %s, %s, %s)
"""

5. 反爬应对能力弱

问题:
  • 固定 User-Agent 易被识别为爬虫;
  • 请求频率固定,容易触发封禁;
  • 没有使用代理 IP。
补偿措施:
  • 使用随机 User-Agent;
  • 设置随机延迟;
  • 配置代理 IP 列表轮换使用;
  • 使用 fake_useragent 库生成真实 UA。
from fake_useragent import UserAgentua = UserAgent()
headers = {'User-Agent': ua.random}
import random
time.sleep(random.uniform(1, 3))  # 随机延迟 1~3 秒

6. 日志和调试信息不足

问题:
  • 出现问题难以定位;
  • 缺乏进度跟踪与详细输出。
补偿措施:
  • 使用 Python 的 logging 模块记录日志;
  • 记录请求 URL、响应状态、插入数量等关键信息。
import logginglogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')# 示例
logging.info("开始抓取第 {} 页".format(page_num))

7. 配置信息硬编码在代码中

问题:
  • 修改数据库账号密码需要修改源码;
  • 不利于部署多个环境(开发/测试/生产)。
补偿措施:
  • 使用配置文件(如 config.ini 或 .env 文件);
  • 使用 dotenv 加载环境变量。
# config.ini
[mysql]
host = localhost
user = root
password = yourpassword
database = douban_movies
import configparserconfig = configparser.ConfigParser()
config.read('config.ini')
db_config = config['mysql']

九、总结对比表

问题点影响程度优化建议
异常处理缺失添加 try-except 和重试机制
页面结构变动增加字段判空、健壮的解析逻辑
数据库效率低复用连接 + 批量插入
数据重复添加唯一索引 + 去重插入
反爬机制薄弱随机 UA、IP 代理、延迟控制
日志不完善使用 logging 模块
配置信息硬编码使用配置文件或环境变量

十、进阶改进建议(可根据自身要求选择)

  • 使用 Scrapy 框架替代手动编写爬虫;
  • 使用 Selenium 对抗 JavaScript 渲染页面;
  • 使用 Redis 实现分布式爬虫;
  • 使用 Celery 进行异步任务调度;
  • 使用 SQLAlchemy 替代原生 SQL 提升 ORM 能力;
  • 使用 Docker 容器化部署爬虫项目。

如果你是刚入门的新手,这篇博客中的代码已经足够帮助你理解整个流程。但如果你想把这个代码用于生产环境或长期稳定运行,就需要根据上述分析进行优化和完善。

如果你希望我帮你把这段代码重构为一个更健壮、模块化的版本,也可以告诉我,我可以为你提供完整的重构方案和代码实现。

十一、总结

通过本教程,你已经大致掌握了:

  • 如何使用 requests 抓取网页数据;
  • 使用 BeautifulSoup 提取关键信息;
  • 使用 mysql-connector-python 将数据写入 MySQL;
  • 分页爬取、延迟请求等基本技巧。

这个项目是一个普通入门级爬虫案例,适用于大多数静态网页的数据采集需求。


如需进一步扩展,可以尝试:

  • 使用 Scrapy 框架构建更复杂的爬虫系统;
  • 将数据导出为 CSV 或 Excel 文件;
  • 可视化分析豆瓣电影评分分布等。

如果你喜欢这篇博客,欢迎点赞、收藏或留言交流!

相关文章:

  • 有没有免费b2b平台百度seo排名360
  • 电子设计全国网站建设线上营销策略都有哪些
  • 上海网站建设开发电话做广告推广哪个平台好
  • 深圳电商网络网站建设seo排名工具提升流量
  • 动态网站开发用的什么语言全国疫情突然又严重了
  • 自媒体网站建设seo岗位职责
  • 深度学习入门--(二)感知机
  • VBA技术资料MF329:获得屏幕分辨率
  • 数据库1.0
  • 【请关注】实操mongodb集群部署
  • 迁移学习—基于猫狗数据集
  • SpringCloud系列(37)--搭建SpringCloud Gateway
  • 解释一下黑盒测试和白盒测试的区别?
  • 零基础入门Java+大模型(持续更新)
  • 创新让生活更美好丨“鑫亘科技亮相2025上海CMEF,创新医疗材料引领未来!”
  • 淘宝API安全合规指南:避免数据泄露与封禁
  • Encoder-only PLM RoBERTa ALBERT (BERT的变体)
  • 使用 Spread.net将 Excel 中的文本拆分为多段
  • EloqCloud for KV 初体验:兼容redis的云原生KV数据库
  • 《解锁前端潜力:自动化流程搭建秘籍》
  • 代码随想录day15二叉树3
  • 获取YARN application 应用列表的几种方法
  • 博图运动控制入门篇1-伺服组态和基本设置
  • Windows 安装 Redis8.0.2
  • 逆序对的数量
  • python的少数民族音乐网站系统