Python 爬虫练习 批量爬取导师信息与照片

'# Python 爬虫练习 批量爬取导师信息与照片

一、背景与问题

在科研合作、学术交流等场景中,获取导师的详细信息(如研究方向、联系方式、学术成果)和高质量照片是常见需求。然而,传统人工整理方式效率低下,而爬虫技术能有效解决这一问题。

但实际开发中会遇到诸多挑战:

  1. 目标网站存在反爬虫机制(如验证码、请求头限制)
  2. 导师信息分散在多个页面中需要分页处理
  3. 照片可能通过JavaScript动态加载
  4. 需要处理异构数据格式(如JSON嵌套结构)
  5. 需要遵守网站的robots.txt规则

二、基本原理

爬虫系统的核心是模拟浏览器行为,完成以下三个步骤:

  1. 网络请求:使用HTTP协议向目标服务器发送请求,获取原始数据(HTML/JSON)
  2. 数据解析:分析响应内容,提取所需信息(HTML解析、JSON提取)
  3. 数据存储:将提取数据持久化保存(数据库、文件系统、云存储)

对于动态加载内容的网页,还需要引入浏览器自动化工具(如Selenium)模拟真实用户操作。

三、环境准备

pip install requests beautifulsoup4 lxml selenium

需要额外安装浏览器驱动(如ChromeDriver)并配置环境变量。

四、核心实现

1. 基础请求与响应处理

import requests
from bs4 import BeautifulSoup

def fetch_page(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.116 Safari/537.36'
    }
    response = requests.get(url, headers=headers, timeout=10)
    response.encoding = 'utf-8'
    return response.text

关键点解释:

  • 设置合理的User-Agent避免被识别为爬虫
  • 设置超时时间防止程序卡死
  • 处理响应编码(有些网站返回的是gbk编码)

2. 动态内容处理(使用Selenium)

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def get_dynamic_content(url):
    chrome_options = Options()
    chrome_options.add_argument('--headless')  # 无头模式
    chrome_options.add_argument('--disable-gpu')
    driver = webdriver.Chrome(options=chrome_options)
    
    try:
        driver.get(url)
        # 等待JavaScript加载
        driver.implicitly_wait(10)
        return driver.page_source
    finally:
        driver.quit()

注意事项:

  • 需要安装Chrome浏览器和对应版本的chromedriver
  • 无头模式可能被反爬虫机制检测到
  • 考虑使用代理IP池避免IP封禁

3. 数据提取与存储

import sqlite3

def save_to_sqlite(data):
    conn = sqlite3.connect('teachers.db')
    c = conn.cursor()
    
    # 创建表(如果不存在)
    c.execute('''CREATE TABLE IF NOT EXISTS teachers
                 (id INTEGER PRIMARY KEY, name TEXT, title TEXT, photo_url TEXT, research_area TEXT)''')
    
    # 插入数据
    c.executemany('INSERT OR IGNORE INTO teachers VALUES (?,?,?,?,$)', 
                  [(d['id'], d['name'], d['title'], d['photo_url'], d['research_area']) for d in data])
    
    conn.commit()
    conn.close()

优化点:

  • 使用INSERT OR IGNORE避免重复插入
  • 使用事务保证数据一致性
  • 可扩展为MySQL/PostgreSQL等数据库

五、完整案例:某高校导师信息爬取

项目结构

teacher_crawler/
├── main.py
├── utils/
│   ├── request_utils.py
│   └── parser_utils.py
└── db/
    └── teachers.db

主程序实现

# main.py
import requests
from bs4 import BeautifulSoup
import sqlite3

def main():
    base_url = 'https://example-university.edu/teachers'
    pages = 3  # 爬取前3页
    
    for page in range(1, pages+1):
        url = f"{base_url}?page={page}"
        html = fetch_page(url)
        soup = BeautifulSoup(html, 'html.parser')
        
        for item in soup.select('.teacher-item'):
            name = item.select_one('.name').text.strip()
            title = item.select_one('.title').text.strip()
            photo_url = item.select_one('img')['src']
            research_area = item.select_one('.research-area').text.strip()
            
            # 保存到数据库
            save_to_sqlite({
                'id': page*10 + i,  # 假设每页10条数据
                'name': name,
                'title': title,
                'photo_url': photo_url,
                'research_area': research_area
            })

动态内容处理扩展

# utils/request_utils.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def get_dynamic_content(url):
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    
    driver = webdriver.Chrome(options=chrome_options)
    try:
        driver.get(url)
        driver.implicitly_wait(10)
        return driver.page_source
    finally:
        driver.quit()

六、源码解析

1. 请求头构造

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.116 Safari/537.36'
}
  • 模拟现代浏览器的特征
  • 可添加其他字段如Accept-Language、Referer

2. 数据解析

soup.select('.teacher-item')
  • 使用CSS选择器提高解析效率
  • select_one用于获取单个元素
  • 需要处理可能的空值(text.strip())

3. 数据存储优化

c.executemany('INSERT OR IGNORE INTO teachers VALUES (?,?,?,?,$)', 
              [(d['id'], d['name'], d['title'], d['photo_url'], d['research_area']) for d in data])
  • 批量插入提升性能
  • 使用OR IGNORE避免重复数据
  • 可考虑使用UPSERT语句(需数据库支持)

七、进阶使用

1. 并发处理优化

import concurrent.futures

def crawl_page(page):
    url = f"{base_url}?page={page}"
    html = fetch_page(url)
    # 解析并保存数据...

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    executor.map(crawl_page, range(1, pages+1))

2. 代理IP池配置

def fetch_page(url):
    proxies = {
        'http': 'http://10.10.1.10:3128',
        'https': 'http://10.10.1.10:1080'
    }
    response = requests.get(url, headers=headers, timeout=10, proxies=proxies)

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 get_dynamic_content(url):
    driver.get(url)
    # 等待特定元素加载
    WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CLASS_NAME, 'teacher-item'))
    )
    return driver.page_source

八、性能与工程实践

1. 性能优化策略

优化点方法效果
线程数使用ThreadPoolExecutor提升并发效率
请求头随机User-Agent避免被识别为爬虫
重试机制requests重试库提高稳定性
限速time.sleep()避免触发反爬虫

2. 异常处理方案

try:
    response = requests.get(url, headers=headers, timeout=10)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    print(f"请求失败: {e}")
    # 可添加重试逻辑

3. 安全风险分析

  • 法律风险:需遵守《计算机软件保护条例》和网站robots.txt规则
  • 反爬虫机制:常见手段包括:

    • 验证码识别(需引入第三方服务)
    • 请求频率限制(需使用时间间隔)
    • IP封禁(需使用代理池)

九、常见问题与踩坑

1. 验证码处理

错误示例:

# 直接请求包含验证码的页面
response = requests.get('https://example.com/teachers?captcha=1')

解决方案:

  • 使用第三方验证码识别服务(如云打码)
  • 使用Selenium模拟人工输入

2. 动态内容加载问题

错误示例:

# 仅获取静态HTML
html = fetch_page('https://example.com/dynamic-page')

解决方案:

  • 使用Selenium等待元素加载
  • 检查开发者工具中的Network面板确认数据源

3. 数据清洗问题

错误示例:

# 直接使用text属性获取数据
research_area = item.select_one('.research-area').text

改进方案:

# 处理多行文本
research_area = '\n'.join([line.strip() for line in item.select_one('.research-area').text.split('\n')])

十、最佳实践

1. 推荐技术栈组合

技术说明
requests简单高效的HTTP请求
BeautifulSoup快速解析静态HTML
Selenium处理动态内容
SQLite轻量级数据存储
Proxy池避免IP封禁

2. 推荐开发流程

  1. 分析网站结构,确认数据源
  2. 编写基础爬虫验证可行性
  3. 引入反爬虫机制处理
  4. 实现数据清洗和存储
  5. 添加异常处理和日志记录
  6. 部署到服务器并监控运行

3. 推荐的目录结构

teacher_crawler/
├── main.py
├── utils/
│   ├── request_utils.py
│   └── parser_utils.py
├── db/
│   └── teachers.db
├── logs/
│   └── crawler.log
└── config/
    └── settings.py

十一、总结

批量爬取导师信息与照片是典型的数据采集场景,涉及多技术栈的综合应用。本文深入解析了爬虫的实现原理,提供了完整的代码示例和优化方案,涵盖静态页面解析、动态内容处理、数据存储等关键环节。

在实际开发中,建议:

  • 对于简单页面使用requests+BeautifulSoup
  • 对于动态内容使用Selenium
  • 对于大规模数据采用分布式爬虫框架
  • 始终遵守网站的robots.txt规则

同时需要警惕法律风险和反爬虫机制,建议在合法合规的前提下进行数据采集。通过合理的技术选型和工程实践,可以有效提升爬虫系统的稳定性和扩展性。

最后修改于:2026年10月01日 15:00

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日