数据采集第四次作业

目录

作业一:

运行代码及结果-1

1、首先要去网站上确认目标网站结构,以沪深 A 股页面为例

2、打开网页时发现会有广告弹出,为了不影响数据的爬取,设置了一个关闭广告的函数close_ads
屏幕截图 2025-12-08 111523

点击查看代码
# 关闭广告
def close_ads(driver):
    # 定义可能的广告关闭按钮XPath列表
    for xpath in ['//img[contains(@src, "ic_close.png")]', '//img[@onclick="_tk_tg_zoomin()"]',
                  '//button[contains(@class, "close")]', '//span[contains(text(), "关闭")]']:
        try:
            # 等待广告关闭按钮可点击,然后点击
            WebDriverWait(driver, 3).until(EC.element_to_be_clickable((By.XPATH, xpath))).click()
            logger.info(f"已关闭广告({xpath})")
            return True  # 关闭成功后退出函数
        except:
            continue  # 该XPath对应的按钮不存在,尝试下一个
    logger.info("未检测到广告")  # 所有XPath都尝试过,未找到广告关闭按钮

3、对于东方财富网,由于其同一类页面(如不同股票板块的列表页)通常采用相同的 HTML 结构,因此我通过不同URL访问对应板块,再用统一的XPath提取数据。整体爬取的框架为:先访问页面→处理干扰(广告)→等待核心元素(表格)加载→提取数据。这里通过EC.presence_of_element_located确保表格加载完成后再提取,避免获取空数据。

点击查看代码
def crawl_board(board_name, url, driver):
    driver.get(url)  # 访问页面
    close_ads(driver)  # 预处理(关广告)
    # 等待表格加载完成
    WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH, '//div[@class="quotetable"]//table//tbody')))
    # 提取表格数据
    for row in driver.find_elements(...):
        cols = row.find_elements(By.TAG_NAME, 'td')
        data.append((cols[0].text, cols[1].text, ...))  # 按列索引收集数据

4、在爬取完数据后,下一步就是将数据存储到数据库了。首先先清洗数据(处理格式问题和特殊值),再用executemany批量插入,保证数据的准确性。INSERT IGNORE配合主键约束,进一步防止重复数据。代码如下

点击查看代码
def save_data(data, board):
    if not data: return logger.warning(f"{board}无数据可保存")
    try:
        with pymysql.connect(**DB_CONFIG) as conn:
            with conn.cursor() as cur:
                sql = """INSERT IGNORE INTO stock_info 
                        (stock_code, stock_name, latest_price, price_change_percent, price_change,
                         volume, turnover, amplitude, highest, lowest, open_price, pre_close, board)
                        VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
                proc_data = []
                for item in data:
                    try:
                        code, name = item[1].strip(), item[2].strip()
                        latest = float(item[3].strip().replace(',', '')) if item[3].strip() != '-' else None
                        pct, change = item[4].strip(), float(item[5].strip().replace(',', '')) if item[
                                                                                                      5].strip() != '-' else None
                        vol, turn, amp = item[6].strip(), item[7].strip(), item[8].strip()
                        high = float(item[9].strip().replace(',', '')) if item[9].strip() != '-' else None
                        low = float(item[10].strip().replace(',', '')) if item[10].strip() != '-' else None
                        open_p = float(item[11].strip().replace(',', '')) if item[11].strip() != '-' else None
                        pre_p = float(item[12].strip().replace(',', '')) if item[12].strip() != '-' else None
                        proc_data.append(
                            (code, name, latest, pct, change, vol, turn, amp, high, low, open_p, pre_p, board))
                    except:
                        continue
                if proc_data:
                    cur.executemany(sql, proc_data)
                    conn.commit()
                    logger.info(f" {board}保存{len(proc_data)}条数据")
    except Exception as e:
        logger.error(f"{board}保存失败:{e}")
        conn.rollback()

image

image

image

心得体会-1

本次实践我掌握了 Selenium 自动化爬取、XPath 元素定位与 MySQL 数据存储的核心逻辑。学会了处理广告干扰、数据清洗问题,体会到代码模块化与容错设计的重要性。

代码链接:https://gitee.com/lin-weijie123/2025_crawl_project/blob/master/作业四/1.py

作业二:

运行代码及结果-2

1、慕课上的课程众多,为了方便爬取,我选择先登录mooc平台,从我自己选择的课程中爬取信息
image

2、对于上图的页面,并不能看到所有课程的详细信息,因此需要通过开发者工具提取每个课程的URL,再逐一进行爬取

image

3、随便进入一个课程,根据题目的要求,依次查看课程号、课程名称、学校名称、主讲教师、团队成员、参加人数、课程进度、课程简介

image

image

image

image

image

image

4、懒加载提取课程 URL:使用滚动触发懒加载,确保加载所有课程

点击查看代码
def extract_personal_course_urls(driver, wait):
    driver.get(PERSONAL_COURSE_URL)
    # 滚动3次加载所有课程(懒加载机制)
    for i in range(3):
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(3)
    
    # 多选择器定位课程链接(兜底适配不同页面结构)
    selectors = ["a[data-action='课程tag-非新学期课程']", "div.course-card-wrapper a.j-course-card-box"]
    course_link_elements = []
    for selector in selectors:
        elements = driver.find_elements(By.CSS_SELECTOR, selector)
        if elements:
            course_link_elements = elements
            break
    
    # 提取课程ID和URL(正则匹配)
    course_urls = []
    for elem in course_link_elements:
        full_url = elem.get_attribute("href")
        course_id_match = re.search(r'course/(\w+-\d+)', full_url)  # 提取课程号(如BNU-1206419811)
        if course_id_match:
            course_id = course_id_match.group(1)
            course_urls.append((course_id, full_url))
    return course_urls

5、课程详情提取(部分示例)

点击查看代码
def get_course_detail(driver, wait, course_id, course_url):
    driver.get(course_url)
    time.sleep(8)  # 等待页面加载
    
    # 1. 课程名称
    name_selectors = [".course-title", "h1.course-title"]
    for selector in name_selectors:
        try:
            course_info["course_name"] = driver.find_element(By.CSS_SELECTOR, selector).text.strip()
            break
        except:
            continue
    
    # 2. 教师信息
    teacher_selectors = [".m-teachers_teacher-list .um-list-slider_con_item", ".teacher-panel .teacher-item"]
    teachers = []
    for selector in teacher_selectors:
        items = driver.find_elements(By.CSS_SELECTOR, selector)
        if items:
            for item in items:
                teacher_text = item.text.strip().replace("\n", " ")  # 去掉换行(如“王宁\n教授”→“王宁 教授”)
                teachers.append(teacher_text)
            break
    course_info["teacher"] = teachers[0] if teachers else "未公开"  # 主讲教师
    course_info["team"] = "、".join(teachers[1:]) if len(teachers)>1 else "无"  # 团队
    
    # 3. 参加人数
    count_text = driver.find_element(By.CSS_SELECTOR, ".course-enroll-info .count").text.strip()
    count_match = re.search(r'(\d+)', count_text)
    course_info["enroll_count"] = int(count_match.group(1)) if count_match else 0
    
    return course_info
  1. 数据库保存:将爬取的课程信息插入数据库,使用ON DUPLICATE KEY UPDATE避免重复数据,确保数据唯一性
点击查看代码
def save_to_database(conn, cursor, course_info):
    cursor.execute('''
        INSERT INTO personal_course_info 
        (course_name, college, teacher, team, enroll_count, course_status, course_intro, course_id, course_url)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
        ON DUPLICATE KEY UPDATE  # 重复课程ID时更新数据
            college=%s, teacher=%s, team=%s, enroll_count=%s, course_status=%s, course_intro=%s
    ''', (course_info["course_name"], course_info["college"], ...))  # 传入所有字段值
    conn.commit()

image

image

image

心得体会-2

通过本次MOOC个人课程爬虫作业,我掌握了Selenium自动化爬取、MySQL数据存储等核心技能,过程中使用了正则提取关键信息、也使用了用多选择器适配不同页面结构。

代码链接:https://gitee.com/lin-weijie123/2025_crawl_project/blob/master/作业四/2.py

作业三:

运行代码及结果-3

  1. 任务一:开通MapReduce服务

image

  1. 任务一:Python脚本生成测试数据

使用more命令查看生成的数据
image

2.任务二:配置Kafka
步骤 1:客户端下载成功

image

步骤 2:查看kafka的IP

image
kafka-topics.sh --create --topic fludesc --partitions 1 --replication-factor 1 --bootstrap-server 192.168.0.132:9092

步骤 3:查看topic信息

image

3.任务三: 安装Flume客户端

步骤 1:下载Flume客户端

image

步骤 2:重启Flume服务

image

4.任务四:配置Flume采集数据

测试消费者消费kafka中的数据
image

心得体会-3

完成华为云Flume日志采集实验,我掌握了Xshell操作、MapReduce开通及Kafka、Flume配置,熟悉了大数据实时数据采集流程,通过实践提升了工具实操能力。

posted @ 2025-12-09 00:36  林伟杰123  阅读(0)  评论(0)    收藏  举报