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
相关推荐
数据小小爬虫5 小时前
利用Java爬虫获取苏宁易购商品详情
java·开发语言·爬虫
小木_.5 小时前
【Python 图片下载器】一款专门为爬虫制作的图片下载器,多线程下载,速度快,支持续传/图片缩放/图片压缩/图片转换
爬虫·python·学习·分享·批量下载·图片下载器
lovelin+v175030409665 小时前
安全性升级:API接口在零信任架构下的安全防护策略
大数据·数据库·人工智能·爬虫·数据分析
qq_375872697 小时前
14爬虫:scrapy实现翻页爬取
爬虫·scrapy
Jelena技术达人7 小时前
Java爬虫获取1688关键字接口详细解析
java·开发语言·爬虫
小爬虫程序猿11 小时前
如何利用Python爬虫精准获取苏宁易购商品详情
开发语言·爬虫·python
API快乐传递者11 小时前
Python爬虫获取1688详情接口详细解析
开发语言·爬虫·python
小爬虫程序猿13 小时前
如何设置爬虫的访问频率?
爬虫