《使用Python Selenium爬取内容并存储MySQL数据库的实例图解》
在数据驱动的时代,网络爬虫技术已成为获取公开数据的重要手段。本文将通过一个完整的实例,详细讲解如何使用Python的Selenium库模拟浏览器操作爬取网页内容,并将数据存储到MySQL数据库中。该方案适用于需要动态渲染页面的场景(如JavaScript生成的页面),相比Requests+BeautifulSoup的静态爬取方案更具优势。
一、环境准备与工具安装
在开始编码前,需要配置以下环境:
- Python 3.6+环境
- Selenium WebDriver(ChromeDriver/GeckoDriver)
- MySQL数据库(5.7+版本)
- 相关Python库:selenium、pymysql、time、re
1.1 安装Python依赖库
pip install selenium pymysql
1.2 下载WebDriver
根据浏览器版本下载对应驱动:
将驱动文件放入系统PATH路径或项目根目录
1.3 MySQL数据库准备
CREATE DATABASE IF NOT EXISTS web_data DEFAULT CHARSET utf8mb4;
USE web_data;
CREATE TABLE IF NOT EXISTS articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT,
url VARCHAR(512) UNIQUE,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
二、Selenium基础操作详解
2.1 浏览器初始化配置
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def init_browser(headless=True):
chrome_options = Options()
if headless:
chrome_options.add_argument('--headless') # 无头模式
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
driver = webdriver.Chrome(
executable_path='./chromedriver', # 驱动路径
options=chrome_options
)
return driver
2.2 元素定位方法对比
方法 | 示例 | 适用场景 |
---|---|---|
ID定位 | find_element_by_id("element_id") | 唯一ID元素 |
CSS选择器 | find_element_by_css_selector(".class > #id") | 复杂结构定位 |
XPath | find_element_by_xpath("//div[@class='content']/p[1]") | 层级定位 |
2.3 等待机制实现
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def safe_find_element(driver, locator, timeout=10):
try:
return WebDriverWait(driver, timeout).until(
EC.presence_of_element_located(locator)
)
except Exception as e:
print(f"元素查找失败: {e}")
return None
# 使用示例
element = safe_find_element(
driver,
(By.CSS_SELECTOR, ".article-title")
)
三、完整爬虫实现步骤
3.1 项目结构规划
project/
├── config.py # 配置文件
├── crawler.py # 爬虫主逻辑
├── database.py # 数据库操作
└── requirements.txt # 依赖清单
3.2 配置文件设计
# config.py
MYSQL_CONFIG = {
'host': 'localhost',
'user': 'root',
'password': 'your_password',
'database': 'web_data',
'charset': 'utf8mb4'
}
CRAWLER_CONFIG = {
'start_url': 'https://example.com/articles',
'max_pages': 50,
'sleep_time': (1, 3) # 随机延迟范围
}
3.3 数据库操作模块
# database.py
import pymysql
from config import MYSQL_CONFIG
class MySQLHelper:
def __init__(self):
self.conn = pymysql.connect(
host=MYSQL_CONFIG['host'],
user=MYSQL_CONFIG['user'],
password=MYSQL_CONFIG['password'],
database=MYSQL_CONFIG['database'],
charset=MYSQL_CONFIG['charset']
)
self.cursor = self.conn.cursor()
def insert_article(self, title, content, url):
sql = """
INSERT INTO articles (title, content, url)
VALUES (%s, %s, %s)
ON DUPLICATE KEY UPDATE
title=VALUES(title), content=VALUES(content)
"""
try:
self.cursor.execute(sql, (title, content, url))
self.conn.commit()
return True
except Exception as e:
print(f"数据库插入错误: {e}")
self.conn.rollback()
return False
def close(self):
self.cursor.close()
self.conn.close()
3.4 核心爬虫实现
# crawler.py
import time
import random
from selenium.webdriver.common.by import By
from database import MySQLHelper
from config import CRAWLER_CONFIG
class ArticleCrawler:
def __init__(self):
self.driver = init_browser()
self.db = MySQLHelper()
def random_sleep(self):
t = random.uniform(*CRAWLER_CONFIG['sleep_time'])
time.sleep(t)
def parse_article(self, article_url):
self.driver.get(article_url)
self.random_sleep()
try:
title = self.driver.find_element_by_css_selector("h1.title").text
content = self.driver.find_element_by_css_selector("div.article-content").text
return {
'title': title,
'content': content,
'url': article_url
}
except Exception as e:
print(f"文章解析错误: {e}")
return None
def crawl_list_page(self, list_url):
self.driver.get(list_url)
self.random_sleep()
articles = []
elements = self.driver.find_elements_by_css_selector(".article-item a")
for elem in elements:
article_url = elem.get_attribute("href")
article_data = self.parse_article(article_url)
if article_data:
self.db.insert_article(
article_data['title'],
article_data['content'],
article_data['url']
)
articles.append(article_data)
return articles
def run(self):
current_page = 1
while current_page
四、进阶优化技巧
4.1 反爬策略应对
- 代理IP池:使用
selenium-wire
或scrapy-proxy-pool
- Cookie管理:
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
caps = DesiredCapabilities.CHROME
caps['goog:loggingPrefs'] = {'performance': 'ALL'}
driver = webdriver.Chrome(desired_capabilities=caps)
4.2 分布式爬虫架构
使用Redis实现任务队列:
import redis
class TaskQueue:
def __init__(self):
self.r = redis.Redis(host='localhost', port=6379, db=0)
def push_url(self, url):
self.r.lpush('crawler:tasks', url)
def pop_url(self):
_, url = self.r.brpop('crawler:tasks', timeout=10)
return url.decode('utf-8')
4.3 数据清洗与存储优化
import re
from html import unescape
def clean_content(text):
# 去除HTML标签
text = re.sub(r']+>', '', text)
# 解码HTML实体
text = unescape(text)
# 去除多余空格
text = ' '.join(text.split())
return text.strip()
五、常见问题解决方案
5.1 元素找不到的调试技巧
- 使用开发者工具检查元素是否在iframe中
- 添加显式等待:
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(EC.visibility_of_element_located((By.ID, "dynamic-element")))
5.2 数据库连接问题处理
import pymysql
from pymysql import MySQLError
try:
conn = pymysql.connect(**MYSQL_CONFIG)
except MySQLError as e:
if e.args[0] == 2003: # 连接失败
print("无法连接到MySQL服务器")
elif e.args[0] == 1045: # 认证失败
print("数据库用户名或密码错误")
5.3 性能优化建议
- 使用连接池管理数据库连接
- 批量插入数据:
def batch_insert(self, articles):
sql = """
INSERT INTO articles (title, content, url)
VALUES (%s, %s, %s)
"""
params = [(a['title'], a['content'], a['url']) for a in articles]
try:
self.cursor.executemany(sql, params)
self.conn.commit()
except Exception as e:
print(f"批量插入错误: {e}")
self.conn.rollback()
六、完整项目部署指南
6.1 日志系统实现
import logging
def setup_logger():
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('crawler.log'),
logging.StreamHandler()
]
)
return logging.getLogger('article_crawler')
# 使用示例
logger = setup_logger()
logger.info("爬虫启动")
6.2 定时任务配置(使用APScheduler)
from apscheduler.schedulers.blocking import BlockingScheduler
def scheduled_crawl():
crawler = ArticleCrawler()
try:
crawler.run()
finally:
crawler.close()
scheduler = BlockingScheduler()
scheduler.add_job(scheduled_crawl, 'cron', hour='8', minute='30')
scheduler.start()
6.3 Docker化部署
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "crawler.py"]
构建并运行:
docker build -t web-crawler .
docker run -d --name crawler web-crawler
七、总结与扩展思考
本文通过完整的代码实例,演示了从浏览器自动化到数据持久化的全流程。关键技术点包括:
- Selenium的元素定位与等待机制
- MySQL数据库的连接管理与批量操作
- 异常处理与日志记录
- 反爬策略与性能优化
扩展方向建议:
- 结合Scrapy框架实现分布式爬取
- 使用Elasticsearch构建搜索系统
- 添加数据可视化模块(如Matplotlib/Pyecharts)
关键词:Python爬虫、Selenium、MySQL数据库、WebDriver、数据持久化、反爬策略、动态页面爬取、无头浏览器
简介:本文详细讲解了使用Python Selenium库爬取动态网页内容并存储到MySQL数据库的完整实现方案,包含环境配置、核心代码实现、异常处理、性能优化及部署指南,适合需要处理JavaScript渲染页面的数据采集场景。