102302125 数据采集第4次作业

数据采集与大数据处理综合实验报告

代码地址: https://gitee.com/jadevoice/data-collection-task-4


目录


作业①:东方财富网股票数据爬取实验

1. 实验要求

熟练掌握 Selenium 查找 HTML 元素、爬取 Ajax 网页数据、等待 HTML 元素等内容。使用 Selenium 框架 + MySQL 数据库存储技术路线爬取"沪深A股"、"上证A股"、"深证A股"3个板块的股票数据信息。

候选网站:东方财富网 http://quote.eastmoney.com/center/gridlist.html#hs_a_board

输出信息:MySQL数据库存储,表头包含序号、股票代码、股票名称、最新报价、涨跌幅、涨跌额、成交量、成交额、振幅、最高、最低、今开、昨收等信息。

2. 实验环境

环境 版本
Python 3.8+
Selenium 4.x
ChromeDriver 与Chrome浏览器版本匹配
MySQL 5.7+ / 8.0
PyMySQL 1.0+

3. 环境配置

3.1 安装依赖

pip install selenium pymysql

3.2 下载ChromeDriver

访问 https://chromedriver.chromium.org/downloads 下载与Chrome浏览器版本匹配的驱动,并配置到系统PATH。

3.3 配置MySQL

-- 确保MySQL服务已启动
-- 修改代码中的数据库连接配置
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': 'your_password',  -- 修改为你的密码
    'database': 'stock_db',
    'charset': 'utf8mb4'
}

4. 核心代码解析

4.1 数据库初始化

为了存储股票数据,首先需要创建数据库和数据表:

def create_database():
    """创建数据库和数据表"""
    conn = pymysql.connect(
        host=DB_CONFIG['host'],
        user=DB_CONFIG['user'],
        password=DB_CONFIG['password'],
        charset=DB_CONFIG['charset']
    )
    cursor = conn.cursor()

    # 创建数据库
    cursor.execute("CREATE DATABASE IF NOT EXISTS stock_db CHARACTER SET utf8mb4")
    cursor.execute("USE stock_db")

    # 创建股票数据表
    create_table_sql = """
    CREATE TABLE IF NOT EXISTS stock_data (
        id INT AUTO_INCREMENT PRIMARY KEY,
        board_type VARCHAR(20) COMMENT '板块类型',
        seq_no INT COMMENT '序号',
        stock_code VARCHAR(10) COMMENT '股票代码',
        stock_name VARCHAR(50) COMMENT '股票名称',
        latest_price DECIMAL(10,2) COMMENT '最新报价',
        change_percent VARCHAR(20) COMMENT '涨跌幅',
        change_amount DECIMAL(10,2) COMMENT '涨跌额',
        volume VARCHAR(30) COMMENT '成交量',
        turnover VARCHAR(30) COMMENT '成交额',
        amplitude VARCHAR(20) COMMENT '振幅',
        highest DECIMAL(10,2) COMMENT '最高',
        lowest DECIMAL(10,2) COMMENT '最低',
        today_open DECIMAL(10,2) COMMENT '今开',
        yesterday_close DECIMAL(10,2) COMMENT '昨收',
        create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    )
    """
    cursor.execute(create_table_sql)
    conn.commit()

4.2 Selenium爬取Ajax数据

东方财富网的股票数据通过Ajax动态加载,需要使用Selenium等待元素加载完成:

def scrape_stock_data(driver, board_name, url):
    """爬取单个板块的股票数据"""
    driver.get(url)

    # 使用WebDriverWait等待表格加载
    wait = WebDriverWait(driver, 20)
    wait.until(EC.presence_of_element_located(
        (By.CSS_SELECTOR, '#table_wrapper-table tbody tr')
    ))
    time.sleep(2)  # 额外等待数据完全加载

    stock_list = []

    # 获取表格行
    rows = driver.find_elements(By.CSS_SELECTOR, '#table_wrapper-table tbody tr')

    for row in rows:
        cols = row.find_elements(By.TAG_NAME, 'td')
        if len(cols) >= 13:
            stock_info = {
                'stock_code': cols[1].text,
                'stock_name': cols[2].text,
                'latest_price': cols[4].text,
                'change_percent': cols[5].text,
                # ... 其他字段
            }
            stock_list.append(stock_info)

    return stock_list

4.3 翻页处理

为了获取更多数据,实现了自动翻页功能:

# 尝试点击下一页
try:
    next_btn = driver.find_element(By.CSS_SELECTOR, '.paginate_input + a')
    if 'disabled' not in next_btn.get_attribute('class'):
        next_btn.click()
        page_num += 1
        time.sleep(1)
    else:
        break
except:
    break

5. 运行步骤

步骤1:修改配置

编辑 exp1_eastmoney_stock.py,修改MySQL密码:

DB_CONFIG = {
    'password': 'your_actual_password',  # 改为你的密码
}

步骤2:运行程序

python exp1_eastmoney_stock.py

image

image

步骤3:查看数据库结果

mysql -u root -p
USE stock_db;
SELECT * FROM stock_data LIMIT 20;
SELECT board_type, COUNT(*) FROM stock_data GROUP BY board_type;

image

6. 实验结果

image

7. 心得体会

  1. Ajax数据处理:东方财富网使用Ajax动态加载数据,传统的requests无法直接获取,必须使用Selenium模拟浏览器行为。

  2. 显式等待的重要性:使用WebDriverWait配合expected_conditions可以有效解决元素加载时机问题,避免因数据未加载完成导致的爬取失败。

  3. 数据类型处理:股票数据中包含带单位的数值(如"1.5亿"、"2000万"),需要编写专门的解析函数进行转换。

  4. 反爬虫应对:适当添加延时time.sleep()可以降低被识别为爬虫的风险。


作业②:中国MOOC网课程数据爬取实验

1. 实验要求

熟练掌握 Selenium 查找 HTML 元素、实现用户模拟登录、爬取 Ajax 网页数据等内容。使用 Selenium 框架 + MySQL 数据库存储技术路线爬取中国 MOOC 网课程资源信息。

候选网站:中国 MOOC 网 https://www.icourse163.org

输出信息:课程号、课程名称、学校名称、主讲教师、团队成员、参加人数、课程进度、课程简介

2. 实验环境

环境 版本
Python 3.8+
Selenium 4.x
ChromeDriver 与Chrome浏览器版本匹配
MySQL 5.7+ / 8.0

3. 核心代码解析

3.1 模拟登录实现

中国MOOC网需要登录才能获取完整信息,登录过程涉及iframe切换:

def login_mooc(driver):
    """模拟登录中国MOOC网"""
    driver.get('https://www.icourse163.org/')

    # 点击登录按钮
    login_btn = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, '.u-navLogin-loginBtn'))
    )
    login_btn.click()

    # 切换到登录iframe
    iframes = driver.find_elements(By.TAG_NAME, 'iframe')
    for iframe in iframes:
        driver.switch_to.frame(iframe)
        # 查找登录表单元素
        phone_input = driver.find_elements(By.CSS_SELECTOR, 'input[type="tel"]')
        if phone_input:
            break
        driver.switch_to.default_content()

    # 输入手机号和密码
    phone_input = driver.find_element(By.CSS_SELECTOR, 'input[type="tel"]')
    phone_input.send_keys(MOOC_ACCOUNT['phone'])

    pwd_input = driver.find_element(By.CSS_SELECTOR, 'input[type="password"]')
    pwd_input.send_keys(MOOC_ACCOUNT['password'])

    # 点击登录按钮
    submit_btn = driver.find_element(By.CSS_SELECTOR, '.u-loginbtn')
    submit_btn.click()

    # 需要手动完成验证码
    print("请在浏览器中完成验证码验证,完成后按回车继续...")
    input()

    driver.switch_to.default_content()

3.2 课程搜索与列表爬取

def search_courses(driver, keyword):
    """搜索课程"""
    search_url = f'https://www.icourse163.org/search.htm?search={keyword}#/'
    driver.get(search_url)

    # 等待搜索结果加载
    WebDriverWait(driver, 15).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '.u-clist'))
    )

    return keyword

def scrape_course_list(driver, keyword):
    """爬取课程列表"""
    course_links = []
    course_cards = driver.find_elements(By.CSS_SELECTOR, '.u-clist .u-clist-it')

    for card in course_cards[:MAX_COURSES_PER_KEYWORD]:
        link = card.find_element(By.TAG_NAME, 'a').get_attribute('href')
        if link and 'icourse163.org' in link:
            course_links.append(link)

    return course_links

3.3 课程详情提取

def scrape_course_detail(driver, course_url, keyword):
    """爬取课程详细信息"""
    driver.get(course_url)
    time.sleep(3)

    course_info = {
        'course_id': '',
        'course_name': '',
        'school_name': '',
        'main_teacher': '',
        'team_members': '',
        'participants': '',
        'course_progress': '',
        'course_intro': '',
        'search_keyword': keyword
    }

    # 课程名称
    try:
        name_elem = driver.find_element(By.CSS_SELECTOR, '.course-title')
        course_info['course_name'] = name_elem.text.strip()
    except:
        pass

    # 学校名称
    try:
        school_elem = driver.find_element(By.CSS_SELECTOR, '.m-teachers .f-fc3')
        course_info['school_name'] = school_elem.text.strip()
    except:
        pass

    # ... 提取其他字段

    return course_info

3.4 数据库存储

def save_to_mysql(course_list):
    """保存课程数据到MySQL"""
    conn = pymysql.connect(**DB_CONFIG)
    cursor = conn.cursor()

    insert_sql = """
    INSERT INTO course_data (course_id, course_name, school_name,
        main_teacher, team_members, participants, course_progress,
        course_intro, search_keyword)
    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
    """

    for course in course_list:
        cursor.execute(insert_sql, (
            course['course_id'],
            course['course_name'],
            course['school_name'],
            course['main_teacher'],
            course['team_members'],
            course['participants'],
            course['course_progress'],
            course['course_intro'],
            course['search_keyword']
        ))

    conn.commit()

4. 运行步骤

步骤1:修改配置

编辑 exp2_mooc_course.py

# 修改数据库密码
DB_CONFIG = {
    'password': 'your_actual_password',
}

# 修改MOOC账号信息(如需登录)
MOOC_ACCOUNT = {
    'phone': 'your_phone_number',
    'password': 'your_password'
}

# 修改搜索关键词
SEARCH_KEYWORDS = ['Python', '大数据', '人工智能']

步骤2:运行程序

python exp2_mooc_course.py

image

步骤3:完成登录验证

程序会提示手动完成验证码,在浏览器中完成后按回车继续。

image

步骤4:观察爬取过程

image

步骤5:查看数据库结果

USE mooc_db;
SELECT * FROM course_data LIMIT 10;
SELECT search_keyword, COUNT(*) FROM course_data GROUP BY search_keyword;

image

5. 实验结果

image

6. 心得体会

  1. iframe处理:MOOC网的登录框在iframe中,需要使用driver.switch_to.frame()切换上下文才能操作登录表单。

  2. 验证码问题:网站有验证码机制,本实验采用半自动方式,由用户手动完成验证码后继续执行。

  3. 反爬虫策略

    • 设置合理的请求间隔
    • 使用excludeSwitches禁用自动化检测
    • 修改navigator.webdriver属性
  4. 数据提取的灵活性:不同课程页面结构可能有差异,需要使用try-except处理,并设计多个备选选择器。


作业③:大数据实时分析处理实验

1. 实验要求

掌握大数据相关服务,熟悉 Xshell 的使用。完成华为云大数据实时分析处理实验手册中的 Flume 日志采集任务。

2. 实验环境

环境 说明
云平台 华为云
操作系统 CentOS 7.x / EulerOS
大数据组件 Hadoop、Flume
远程工具 Xshell

3. 实验准备

3.1 登录华为云ECS

  1. 打开Xshell,新建会话
  2. 输入ECS服务器的公网IP
  3. 选择SSH协议,端口22
  4. 输入用户名和密码连接

3.2 检查环境

# 检查Java环境
java -version

# 检查Hadoop进程
jps

# 检查HDFS状态
hdfs dfsadmin -report

4. Flume配置详解

4.1 Flume架构

Flume采用Agent架构,每个Agent包含三个组件:

  • Source:数据源,负责接收数据
  • Channel:数据通道,临时存储数据
  • Sink:数据目的地,负责将数据发送到目标
数据流向:Source → Channel → Sink

4.2 配置文件:NetCat到Logger

创建配置文件 flume-netcat-logger.conf

# 定义Agent组件名称
a1.sources = r1
a1.sinks = k1
a1.channels = c1

# 配置Source - 使用NetCat监听端口
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444

# 配置Sink - 输出到Logger
a1.sinks.k1.type = logger

# 配置Channel - 使用内存通道
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

# 绑定关系
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

4.3 配置文件:文件到HDFS

创建配置文件 flume-file-hdfs.conf

# 定义Agent组件名称
a2.sources = r2
a2.sinks = k2
a2.channels = c2

# 配置Source - 监控目录
a2.sources.r2.type = spooldir
a2.sources.r2.spoolDir = /opt/flume/logs
a2.sources.r2.fileHeader = true

# 配置Sink - 写入HDFS
a2.sinks.k2.type = hdfs
a2.sinks.k2.hdfs.path = hdfs://master:9000/flume/logs/%Y%m%d
a2.sinks.k2.hdfs.filePrefix = events-
a2.sinks.k2.hdfs.useLocalTimeStamp = true
a2.sinks.k2.hdfs.batchSize = 100
a2.sinks.k2.hdfs.fileType = DataStream
a2.sinks.k2.hdfs.rollInterval = 60

# 配置Channel
a2.channels.c2.type = memory
a2.channels.c2.capacity = 10000

# 绑定关系
a2.sources.r2.channels = c2
a2.sinks.k2.channel = c2

5. 实验步骤

任务一:NetCat到Logger

步骤1:上传配置文件

使用Xshell的文件传输功能(或rz命令)上传配置文件:

cd /opt/flume/conf
# 上传 flume-netcat-logger.conf
rz  # 选择本地文件上传

步骤2:启动Flume Agent

在终端1中执行:

cd /opt/flume
./bin/flume-ng agent \
    --conf ./conf \
    --conf-file ./conf/flume-netcat-logger.conf \
    --name a1 \
    -Dflume.root.logger=INFO,console

步骤3:发送测试数据

打开终端2,使用telnet发送数据:

telnet localhost 44444

输入测试内容:

Hello Flume
This is a test message
Big Data Processing

步骤4:观察Flume输出

在终端1中可以看到Flume接收到的日志:

Event: { headers:{} body: 48 65 6C 6C 6F 20 46 6C 75 6D 65 Hello Flume }

任务二:文件到HDFS

步骤1:准备工作

# 创建监控目录
mkdir -p /opt/flume/logs
chmod 777 /opt/flume/logs

# 在HDFS创建输出目录
hdfs dfs -mkdir -p /flume/logs

步骤2:启动Flume Agent

cd /opt/flume
./bin/flume-ng agent \
    --conf ./conf \
    --conf-file ./conf/flume-file-hdfs.conf \
    --name a2 \
    -Dflume.root.logger=INFO,console

步骤3:创建测试日志文件

在终端2中执行:

echo "2024-01-01 10:00:00 INFO User login success" > /opt/flume/logs/test1.log
echo "2024-01-01 10:01:00 ERROR Database connection failed" > /opt/flume/logs/test2.log
echo "2024-01-01 10:02:00 INFO Data processing completed" > /opt/flume/logs/test3.log

步骤4:验证HDFS数据

# 查看HDFS目录
hdfs dfs -ls /flume/logs/

# 查看具体日期目录
hdfs dfs -ls /flume/logs/$(date +%Y%m%d)/

# 查看文件内容
hdfs dfs -cat /flume/logs/$(date +%Y%m%d)/*

步骤5:检查已处理文件

ls -la /opt/flume/logs/

可以看到已处理的文件被添加了.COMPLETED后缀。

6. 实验结果

成功完成以下任务:

  1. NetCat到Logger:通过telnet发送的数据能够被Flume捕获并输出到控制台
  2. 文件到HDFS:监控目录中的日志文件能够被自动采集并写入HDFS

7. 心得体会

  1. Flume架构理解:Flume的Source-Channel-Sink架构设计清晰,通过配置文件即可灵活定义数据流向,无需编写代码。

  2. 配置文件规范

    • 组件命名需要使用agent.component.name的格式
    • Source和Sink必须绑定到Channel
    • 同一个Source可以连接多个Channel
  3. HDFS集成:Flume与HDFS的集成非常便捷,通过配置hdfs.path即可实现数据落地,支持按时间分区存储。

  4. 实际应用场景

    • 日志采集:收集服务器日志用于分析
    • 实时数据管道:构建数据采集到存储的实时管道
    • 多源聚合:从多个数据源采集数据到统一存储
posted @ 2026-01-04 19:27  wjord2023  阅读(3)  评论(0)    收藏  举报