Selenium爬虫-获取天气并使用MapReduce分析温度最高的那一天

文章目录

Selenium爬虫

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sin</groupId>
    <artifactId>seleniumDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.21.0</version> <!-- 或者最新发布的版本 -->
        </dependency>
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.7.0</version> <!-- 或者最新发布的版本 -->
        </dependency>


        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.4.0</version> <!-- 请根据需要选择适当的版本 -->
        </dependency>


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.1</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

WeatherScraper.java

读取每一天的天气

java 复制代码
package com.sin;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.List;

public class WeatherScraper {

    @Test
    public void test() {
        // 设置 ChromeDriver,确保使用的是最新版本
        // 用于管理浏览器驱动器,确保使用的驱动程序与浏览器版本匹配
        WebDriverManager.chromedriver().setup();
        // 创建一个新的 Chrome 浏览器实例执行自动化测试
        WebDriver driver = new ChromeDriver();

        try {
            // 打开目标网页,获取天气信息
            driver.get("http://www.weather.com.cn/weather40d/101040100.shtml");

            // 查找表格元素,获取天气数据
            WebElement table = driver.findElement(By.id("table"));

            // 获取所有行元素,返回一个列表
            List<WebElement> rows = table.findElements(By.tagName("tr"));

            // 遍历每一行,逐行处理
            for (WebElement row : rows) {
                // 获取当前行的所有单元格
                List<WebElement> cells = row.findElements(By.tagName("td"));

                // 遍历每个单元格,输出内容
                for (WebElement cell : cells) {
                    // 打印单元格内容,格式化为"农历:{内容}"
                    System.out.print("农历:" + cell.getText() + " ---------");
                }
                // 输出换行,分隔每一行的数据
                System.out.println();
            }
        } finally {
            // 无论如何,确保关闭浏览器以释放资源
            driver.quit();
        }
    }

}

weatherScraper.java

读取每一天的天气并存储在文件中

java 复制代码
package com.sin;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

public class WeatherScraper {

   @Test
public void test() {
    // 设置 ChromeDriver,确保使用的是最新版本
    WebDriverManager.chromedriver().setup();
    // 创建一个新的 Chrome 浏览器实例
    WebDriver driver = new ChromeDriver();

    // 创建文件写入器,用于将数据写入到文件中
    try (BufferedWriter writer = new BufferedWriter(new FileWriter("weather_data.txt"))) {
        try {
            // 打开目标网页,获取天气信息
            driver.get("http://www.weather.com.cn/weather40d/101040100.shtml");

            // 找到 ID 为 "table" 的表格元素
            WebElement table = driver.findElement(By.id("table"));

            // 获取所有行元素(<tr>),返回一个列表
            List<WebElement> rows = table.findElements(By.tagName("tr"));

            // 遍历每一行,逐行处理
            for (WebElement row : rows) {
                // 获取当前行的所有单元格(<td>)
                List<WebElement> cells = row.findElements(By.tagName("td"));

                // 检查当前行是否有单元格内容
                if (!cells.isEmpty()) {
                    // 使用 StringBuilder 来构建这一行的数据
                    StringBuilder rowData = new StringBuilder();
                    // 遍历每个单元格,构建行数据
                    for (WebElement cell : cells) {
                        // 将单元格内容添加到 rowData 中,格式为"农历:{内容}"
                        rowData.append("农历:" + cell.getText() + "\t" + "\n" + "----------");
                    }
                    // 将构建的行数据写入到文件
                    writer.write(rowData.toString());
                    writer.newLine(); // 写入后换行
                    writer.newLine(); // 再次换行以分隔不同的行
                }
            }
        } finally {
            // 确保在操作完成后关闭浏览器,以释放资源
            driver.quit();
        }
    } catch (IOException e) {
        // 捕获并打印输入输出异常
        e.printStackTrace();
    }
}

}

结果

tex 复制代码
农历:廿九
01
29/24℃
40%
历史均值	
----------
农历:三十
02
29/22℃
43%
历史均值	
----------
农历:抗日纪念日
03
29/23℃
40%
历史均值	
----------
农历:初二
04
30/23℃
47%
历史均值	
----------
农历:初三
05
29/23℃
27%
历史均值	
----------
农历:初四
06
30/24℃
30%
历史均值	
----------
农历:白露
07
30/23℃
47%
历史均值	
----------

农历:初六
08
29/23℃
47%
历史均值	
----------
农历:初七
09
28/23℃
30%
历史均值	
----------
农历:教师节
10
28/23℃
47%
历史均值	
----------
农历:初九
11
28/22℃
40%
历史均值	
----------
农历:初十
12
29/23℃
47%
历史均值	
----------
农历:十一
13
29/22℃
40%
历史均值	
----------
农历:十二
14
29/22℃
37%
历史均值

班	
----------

农历:十三
15
30/22℃
40%
历史均值

休	
----------
农历:十四
16
31/22℃
43%
历史均值

休	
----------
农历:中秋节
17
31/24℃
37%
历史均值

休	
----------
农历:十六
18
31/22℃
43%
历史均值	
----------
农历:十七
19
39/31℃
0mm
实况	
----------
农历:十八
20
39/29℃
0mm
实况	
----------
农历:十九
21
33/23℃
4mm
实况	
----------

农历:秋分
22
32/26℃
0mm
实况	
----------
农历:廿一
23
33/25℃
0mm
实况	
----------
农历:廿二
24

33°
26℃	
----------
农历:廿三
25

32°
26℃	
----------
农历:廿四
26

33°
25℃	
----------
农历:廿五
27

36°
27℃	
----------
农历:廿六
28

36°
27℃	
----------

农历:廿七
29

36°
22℃
班	
----------
农历:降温14℃
30

22°
18℃	
----------
农历:国庆节
01

18°
16℃
休	
----------
农历:三十
02

18°
15℃
休	
----------
农历:初一
03

21°
17℃
休	

----------
农历:初二
04

20°
19℃
休	
----------
农历:初三
05

27°
19℃
休	
----------

使用MapReduce进行分析最高哪一天气温最高

map部分

java 复制代码
package com.sin.demo;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * TemperatureMapper 类用于从输入数据中提取农历日期和对应的气温信息。
 * 它扩展了 Hadoop 的 Mapper 类,并重写了 map 方法。
 * @createTime 2024/9/24 19:11
 * @createAuthor SIN
 * @use 用于处理气温数据的 MapReduce 作业
 */
public class TemperatureMapper extends Mapper<Object, Text, Text, IntWritable> {
    // 定义一个静态整数可写对象,用于存储气温
    private final static IntWritable temperature = new IntWritable();
    // 定义一个文本对象,用于存储农历日期
    private Text lunarDate = new Text();

    // 用于存储当前的农历日期
    private String currentLunarDate = null;

    @Override
    protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        // 将输入的 Text 对象转为字符串并去除两端空白字符
        String line = value.toString().trim();

        // 匹配农历行:如果该行以 "农历:" 开头
        if (line.startsWith("农历:")) {
            // 提取农历日期,去掉 "农历:" 部分
            currentLunarDate = line.replace("农历:", "").trim(); // 设置当前农历日期
        }

        // 匹配气温行:如果该行包含 "℃"
        if (line.contains("℃")) {
            // 通过 "/" 分隔气温,获取最高气温部分
            String tempStr = line.split("/")[0]; // 获取最高气温部分
            // 提取数字部分并转换为整数
            int temp = Integer.parseInt(tempStr.replaceAll("[^0-9]", "")); // 提取数字并转为整数

            // 检查当前农历日期是否已设置
            if (currentLunarDate != null) {
                // 将当前农历日期设置为输出键
                lunarDate.set(currentLunarDate); // 使用当前农历日期
                // 将气温值设置为输出值
                temperature.set(temp);
                // 向上下文写出农历日期和气温
                context.write(lunarDate, temperature);
            }
        }
    }
}

reduce部分

java 复制代码
package com.sin.demo;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * TemperatureReducer 类用于处理从 TemperatureMapper 传来的气温数据。
 * 它扩展了 Hadoop 的 Reducer 类,并重写了 reduce 和 cleanup 方法。
 * @createTime 2024/9/24 19:16
 * @createAuthor SIN
 * @use 用于计算每个农历日期的最高气温
 */
public class TemperatureReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    // 存储当前找到的最大气温对应的农历日期
    private Text maxTempDate = new Text();
    // 存储当前已知的最大气温,初始化为 Integer.MIN_VALUE
    private IntWritable maxTemperature = new IntWritable(Integer.MIN_VALUE);

    /**
     * reduce 方法接收来自 Mapper 的键值对,并计算每个农历日期的最高气温。
     * @param key 农历日期
     * @param values 气温值的集合
     * @param context 上下文对象,用于输出结果
     * @throws IOException 输入输出异常
     * @throws InterruptedException 中断异常
     */
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int currentMax = Integer.MIN_VALUE; // 当前处理的最大气温

        // 遍历所有气温值,找到当前键(农历日期)下的最大气温
        for (IntWritable val : values) {
            if (val.get() > currentMax) {
                currentMax = val.get(); // 更新当前最大气温
            }
        }

        // 如果当前最大气温大于已知最大气温,则更新最大气温和对应的日期
        if (currentMax > maxTemperature.get()) {
            maxTemperature.set(currentMax); // 更新全局最大气温
            maxTempDate.set(key.toString()); // 更新对应的农历日期
        }

        // 输出当前处理的农历日期和找到的气温信息
        System.out.println("Processing date: " + key.toString()); // 输出当前处理的农历日期
        for (IntWritable val : values) {
            System.out.println("Found temperature: " + val.get()); // 输出找到的气温
        }
    }

    /**
     * cleanup 方法在所有 reduce 调用完成后执行,用于输出最终结果。
     * @param context 上下文对象,用于输出结果
     * @throws IOException 输入输出异常
     * @throws InterruptedException 中断异常
     */
    @Override
    protected void cleanup(Context context) throws IOException, InterruptedException {
        // 如果有有效的最大气温,则写出结果
        if (maxTemperature.get() != Integer.MIN_VALUE) {
            context.write(maxTempDate, maxTemperature); // 输出最高气温及其对应的日期
        }
    }
}

main部分

java 复制代码
package com.sin.demo;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

/**
 * MaxTemperatureJob 类用于设置和执行最高气温计算的 MapReduce 作业。
 * @createTime 2024/9/24 19:31
 * @createAuthor SIN
 * @use 该类是程序的入口点,负责配置作业并启动执行。
 */
public class MaxTemperatureJob {
    public static void main(String[] args) throws Exception {

        // 创建 Hadoop 配置对象
        Configuration conf = new Configuration();

        // 创建一个新的 Job 实例,并命名为 "最高气温"
        Job job = Job.getInstance(conf, "最高气温");

        // 设置主类
        job.setJarByClass(MaxTemperatureJob.class);

        // 设置 Mapper 和 Reducer 类
        job.setMapperClass(TemperatureMapper.class);
        job.setReducerClass(TemperatureReducer.class);

        // 设置输出键和值的类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        // 设置输入和输出路径
        FileInputFormat.addInputPath(job, new Path(args[0])); // 输入路径
        FileOutputFormat.setOutputPath(job, new Path(args[1])); // 输出路径

        // 提交作业并等待完成
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

输出结果

shell 复制代码
[root@master ~]# hadoop jar /usr/local/mapReduceDemo1-1.0-SNAPSHOT.jar com.sin.demo.MaxTemperatureJob /sinDemo/demo0/weather_data1.txt /sinDemo/demo0/weatheroutput7
2024-09-24 18:11:36,156 INFO client.DefaultNoHARMFailoverProxyProvider: Connecting to ResourceManager at master/192.168.226.140:8032
2024-09-24 18:11:36,825 WARN mapreduce.JobResourceUploader: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this.
2024-09-24 18:11:36,861 INFO mapreduce.JobResourceUploader: Disabling Erasure Coding for path: /tmp/hadoop-yarn/staging/root/.staging/job_1727145442852_0009
2024-09-24 18:11:37,182 INFO input.FileInputFormat: Total input files to process : 1
2024-09-24 18:11:37,323 INFO mapreduce.JobSubmitter: number of splits:1
2024-09-24 18:11:37,576 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1727145442852_0009
2024-09-24 18:11:37,576 INFO mapreduce.JobSubmitter: Executing with tokens: []
2024-09-24 18:11:37,800 INFO conf.Configuration: resource-types.xml not found
2024-09-24 18:11:37,800 INFO resource.ResourceUtils: Unable to find 'resource-types.xml'.
2024-09-24 18:11:37,879 INFO impl.YarnClientImpl: Submitted application application_1727145442852_0009
2024-09-24 18:11:37,944 INFO mapreduce.Job: The url to track the job: http://master:8088/proxy/application_1727145442852_0009/
2024-09-24 18:11:37,945 INFO mapreduce.Job: Running job: job_1727145442852_0009
2024-09-24 18:11:45,241 INFO mapreduce.Job: Job job_1727145442852_0009 running in uber mode : false
2024-09-24 18:11:45,242 INFO mapreduce.Job:  map 0% reduce 0%
2024-09-24 18:11:51,406 INFO mapreduce.Job:  map 100% reduce 0%
2024-09-24 18:11:57,448 INFO mapreduce.Job:  map 100% reduce 100%
2024-09-24 18:11:57,461 INFO mapreduce.Job: Job job_1727145442852_0009 completed successfully
2024-09-24 18:11:57,566 INFO mapreduce.Job: Counters: 54
        File System Counters
                FILE: Number of bytes read=826
                FILE: Number of bytes written=546405
                FILE: Number of read operations=0
                FILE: Number of large read operations=0
                FILE: Number of write operations=0
                HDFS: Number of bytes read=1985
                HDFS: Number of bytes written=19
                HDFS: Number of read operations=8
                HDFS: Number of large read operations=0
                HDFS: Number of write operations=2
                HDFS: Number of bytes read erasure-coded=0
        Job Counters
                Launched map tasks=1
                Launched reduce tasks=1
                Data-local map tasks=1
                Total time spent by all maps in occupied slots (ms)=3297
                Total time spent by all reduces in occupied slots (ms)=7458
                Total time spent by all map tasks (ms)=3297
                Total time spent by all reduce tasks (ms)=3729
                Total vcore-milliseconds taken by all map tasks=3297
                Total vcore-milliseconds taken by all reduce tasks=3729
                Total megabyte-milliseconds taken by all map tasks=3376128
                Total megabyte-milliseconds taken by all reduce tasks=7636992
        Map-Reduce Framework
                Map input records=230
                Map output records=36
                Map output bytes=748
                Map output materialized bytes=826
                Input split bytes=115
                Combine input records=0
                Combine output records=0
                Reduce input groups=32
                Reduce shuffle bytes=826
                Reduce input records=36
                Reduce output records=1
                Spilled Records=72
                Shuffled Maps =1
                Failed Shuffles=0
                Merged Map outputs=1
                GC time elapsed (ms)=183
                CPU time spent (ms)=880
                Physical memory (bytes) snapshot=319209472
                Virtual memory (bytes) snapshot=6339801088
                Total committed heap usage (bytes)=142573568
                Peak Map Physical memory (bytes)=210288640
                Peak Map Virtual memory (bytes)=2734157824
                Peak Reduce Physical memory (bytes)=108920832
                Peak Reduce Virtual memory (bytes)=3605643264
        Shuffle Errors
                BAD_ID=0
                CONNECTION=0
                IO_ERROR=0
                WRONG_LENGTH=0
                WRONG_MAP=0
                WRONG_REDUCE=0
        File Input Format Counters
                Bytes Read=1870
        File Output Format Counters
                Bytes Written=19

[root@master ~]# hdfs dfs -cat /sinDemo/demo0/weatheroutput7/part-r-00000                
 农历:十七      39
相关推荐
朱颜辞镜花辞树‎35 分钟前
Go爬虫开发学习记录
爬虫·学习·golang
测试界清流3 小时前
Selenium4+Pytest自动化测试框架
selenium·测试工具·pytest
月忆3643 小时前
等待组(waitgroup)
前端·爬虫·python
not coder6 小时前
Selenium 查找页面元素的方式
selenium·测试工具
华科云商xiao徐9 小时前
Python多线程数据爬取程序模版
爬虫·python
华科云商xiao徐9 小时前
Java使用Jsoup库实现通用爬虫
java·爬虫
学不会就看11 小时前
selenium学习实战【Python爬虫】
python·学习·selenium
q5673152311 小时前
分布式增量爬虫实现方案
开发语言·分布式·爬虫·python
华科云商xiao徐1 天前
Java HttpClient实现简单网络爬虫
java·爬虫
代码的乐趣1 天前
支持selenium的chrome driver更新到137.0.7151.68
chrome·selenium·测试工具