文章目录
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