vlambda博客
学习文章列表

【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据

看到一篇 Python 天气网爬取历史天气的文章,我只能说:代码太罗嗦了!下面改用 R语言 来练练手。

一 . 先来看一下网页

天气网哈尔滨历史天气链接页:lishi.tianqi.com/haerbi



点开2022年03月天气:lishi.tianqi.com/haerbi


【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据


虽然看起来是表格,但 html 代码并不是 table(是就超级简单了),只能是借助正则表达式来解析了,当然也离不开我一直提倡的tidyverse 优雅数据思维:


【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据


library(tidyverse)
library(rvest)

二. 接着来获取网址

方法1,从网页解析出来

postfix = read_html("http://lishi.tianqi.com/haerbin/index.html") %>% 
html_elements("a") %>%
html_attr("href") %>% # 解析网址
str_subset("^/haerbin") # 筛选出正确的
urls = str_c("http://lishi.tianqi.com/", postfix)


【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据


方法2,按规律手动生成

prefix = "http://lishi.tianqi.com/haerbin/"
Months = map(2011:2021, ~ str_c(.x, sprintf("%02d", 1:12))) %>% # 按规律生成年月
unlist()
Months = c(Months, "202201", "202202","202203","202204")
urls = str_c(prefix, "/", Months, ".html") # 若要颠倒顺序,用rev()

结果略,比解析的多两个,一个是2022年4月,一个是2020年6月(网站漏下了)。

三. 先解决一个网页的爬取+整理

(1) 从网页解析历史天气数据

weather = read_html(urls[1]) %>%              # 2022年3月                         
html_nodes(".thrui") %>%
html_text2()
weather


【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据


结果是一个大字符串,犹如乱码。

(2)借助正则表达式+tidyverse,清洗成整洁数据框

  • 分割成多行,一个样本一行

  • 每一行再分割成多列

tibble(weather) %>%                                         
separate_rows(weather, sep = "\n\r\n(?=\\d{4})") %>%
mutate(weather = str_replace_all(weather, "\r\n|查看更多", "")) %>%
separate(weather, sep = "\n\r*", extra = "drop",
into = c("日期","最高气温","最低气温","天气","风向"))

解释说明

  • 先用"\n\r\n"分割成多行,加个零宽断言(?=\\d{4}) 是为了避免把 \n\r\n查看更多 也给断行;

  • 将多余的\r\n查看更多替换成空

  • \n+0个或多个\r为分隔符,将1列分割成多列

  • 参数extra = "drop",是避免输出一个没有什么影响的警告消息

结果数据框如下:


【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据


四. 批量爬取多个网址

将上面爬取一个网页+整理的过程,封装成一个函数:

crawlurl = function(url) {  
Sys.sleep(sample(5,1)) # 增加随机等待1-5
weather = read_html(url) %>%
html_nodes(".thrui") %>%
html_text2()
tibble(weather) %>%
separate_rows(weather, sep = "\n\r\n(?=\\d{4})") %>%
mutate(weather = str_replace_all(weather, "\r\n|查看更多", "")) %>%
separate(weather, sep = "\n\r*", extra = "drop",
into = c("日期","最高气温","最低气温","天气","风向"))
}

对解析生成的网址urls,借助map循环迭代,完成批量爬虫:

harbin = map_dfr(urls, crawlurl)
harbin


【Tidyverse优雅编程】R语言爬虫:哈尔滨历史天气数据


写出到Excel文件:

writexl::write_xlsx(harbin, "哈尔滨历史天气数据.xlsx")

完工!

最后,完整代码再放一遍:

library(tidyverse)
library(rvest)

## 解析索引页, 获取批量网址
postfix = read_html("http://lishi.tianqi.com/haerbin/index.html") %>%
html_elements("a") %>%
html_attr("href") %>% # 解析网址
str_subset("^/haerbin") # 筛选出正确的
urls = str_c("http://lishi.tianqi.com/", postfix)

## 自定义函数爬取一个网页, 并清洗数据
crawlurl = function(url) {
Sys.sleep(sample(5,1)) # 增加随机等待1-5
weather = read_html(url) %>%
html_nodes(".thrui") %>%
html_text2()
tibble(weather) %>%
separate_rows(weather, sep = "\n\r\n(?=\\d{4})") %>%
mutate(weather = str_replace_all(weather, "\r\n|查看更多", "")) %>%
separate(weather, sep = "\n\r*", extra = "drop",
into = c("日期","最高气温","最低气温","天气","风向"))
}

## 批量爬取, 并保存到文件夹
harbin = map_dfr(urls, crawlurl)
writexl::write_xlsx(harbin, "哈尔滨历史天气数据.xlsx")

附录

我的 R 语言新书:

张敬信:《R语言编程—基于tidyverse》新书信息汇总686 赞同 · 82 评论文章695 赞同 · 85 评论文章707 赞同 · 85 评论文章719 赞同 · 86 评论文章722 赞同 · 87 评论文章729 赞同 · 87 评论文章730 赞同 · 88 评论文章825 赞同 · 99 评论文章824 赞同 · 99 评论文章

已经进入出版流程,预计 22年夏 能与读者见面。更多相关资源请参阅:

张敬信:《R语言编程:基于tidyverse》同类资源汇总36 赞同 · 0 评论文章