使用 R 语言爬取全国所有的万达广场信息

最近有个培训的小伙伴想要爬取万达官网上所有的万达广场信息。这个可以很容易通过 R 语言实现。

要爬取的网址是:http://www.wandaplazas.com/intro/plaza/

我们可以按 Fn + F12 打开页面审查(我使用的是 Chrome 浏览器):

可以看到我们要爬的内容在 Elements 的这个位置,我们可以右键 copy selector:

然后就可以在 R 语言里面写代码了:

library(tidyverse)
library(rvest)

# http://www.wandaplazas.com/intro/plaza/
read_html("http://www.wandaplazas.com/intro/plaza/") -> html
html %>%
html_nodes("#con_one_2") %>%
html_text() %>%
read_csv(col_names = F) -> df

df

#> # A tibble: 873 × 1
#> X1
#> <chr>
#> 1 北京市
#> 2 上海市
#> 3 天津市
#> 4 ·北京CBD万达广场
#> 5 项目位于北京市朝阳区,2006年12月开业,商业面积为10.33万平方米。
#> 6 ·北京丰科万达广场
#> 7 项目位于北京市丰台区,2016年12月开业,商业面积为19.07万平方米。
#> 8 ·北京丰台西铁营万达广场
#> 9 项目位于北京市丰台区,2017年12月开业,商业面积为10.83万平方米。
#> 10 ·北京怀柔万达广场
#> # … with 863 more rows

然后我们把爬取到的内容整理下:

df %>%
dplyr::filter(str_detect(X1, "·") | str_detect(X1, "项目")) %>%
mutate(项目信息 = if_else(str_detect(X1, "·"), X1, "")) %>%
type_convert() %>%
fill(项目信息) %>%
dplyr::filter(!str_detect(X1, "·")) %>%
select(项目 = 项目信息, 项目信息 = X1) %>%
mutate(项目 = str_remove_all(项目, "·")) %>%
mutate(项目信息 = if_else(项目 == "渭南临渭万达广场", "项目位于陕西省渭南市高新区,2015年8月开业,商业面积为12.58万平方米。", 项目信息),
项目信息 = if_else(项目 == "南京江宁万达广场", "项目位于江苏省南京市江宁区,2013年12月开业,商业面积为19.57万平方米。", 项目信息),
项目信息 = if_else(项目 == "泉州浦西万达广场", "项目位于福建省泉州市丰泽区,2012年9月开业,商业面积为21.03万平方米。", 项目信息),
项目信息 = if_else(项目 == "衡阳蒸湘万达广场", "项目位于湖南省衡阳市蒸湘区,2017年9月开业,商业面积为12.01万平方米。", 项目信息)) %>%
mutate(位置 = str_match(项目信息, "位于(.*),\\d")[,2],
开业时间 = str_match(项目信息, ",(.*)开业")[,2],
商业面积_万平方米 = str_match(项目信息, "商业面积为(.*)万平方米")[,2]) %>%
type_convert() %>%
mutate(开业时间 = lubridate::ymd(paste0(开业时间,"1日"))) -> df

df

#> # A tibble: 418 × 5
#> 项目 项目信息 位置 开业时间 商业面积_万平方米
#> <chr> <chr> <chr> <date> <dbl>
#> 1 北京CBD万达广场 项目位于北京市朝阳… 北京… 2006-12-01 10.3
#> 2 北京丰科万达广场 项目位于北京市丰台… 北京… 2016-12-01 19.1
#> 3 北京丰台西铁营万达广场 项目位于北京市丰台… 北京… 2017-12-01 10.8
#> 4 北京怀柔万达广场 项目位于北京市怀柔… 北京… 2018-01-01 9
#> 5 北京槐房万达广场 项目位于北京市丰台… 北京… 2016-12-01 18.9
#> 6 北京乐多港万达广场 项目位于北京市昌平… 北京… 2020-12-01 16.1
#> 7 北京石景山万达广场 项目位于北京市石景… 北京… 2008-12-01 13.7
#> 8 北京双桥万达广场 项目位于北京市朝阳… 北京… 2020-12-01 4.21
#> 9 北京通州万达广场 项目位于北京市通州… 北京… 2014-11-01 12.1
#> 10 北京延庆万达广场 项目位于北京市延庆… 北京… 2020-09-01 13.4
#> # … with 408 more rows

这样我们就得到了所有的万达广场信息:

DT::datatable(df)

为了在地图上标注这些地点,我们可以使用百度地图解析下经纬度:

library(jsonlite)
df %>%
mutate(location = map_chr(项目, function(x) {
try({
paste0("https://api.map.baidu.com/geocoding/v3/?address=", x,
"&output=json&ak=KNfhEZFNPTNL5Gyjm3O81nlE5mURbOhn&ret_coordtype=gcj02ll") %>%
fromJSON() -> lst
paste0(lst$result$location, collapse = ",")
})
})) -> df

df

#> # A tibble: 418 × 6
#> 项目 项目信息 位置 开业时间 商业面积_万平方… location
#> <chr> <chr> <chr> <date> <dbl> <chr>
#> 1 北京CBD万达广场 项目位于北… 北京… 2006-12-01 10.3 116.407…
#> 2 北京丰科万达广场 项目位于北… 北京… 2016-12-01 19.1 116.305…
#> 3 北京丰台西铁营万达广场 项目位于北… 北京… 2017-12-01 10.8 116.355…
#> 4 北京怀柔万达广场 项目位于北… 北京… 2018-01-01 9 116.629…
#> 5 北京槐房万达广场 项目位于北… 北京… 2016-12-01 18.9 116.368…
#> 6 北京乐多港万达广场 项目位于北… 北京… 2020-12-01 16.1 116.190…
#> 7 北京石景山万达广场 项目位于北… 北京… 2008-12-01 13.7 116.226…
#> 8 北京双桥万达广场 项目位于北… 北京… 2020-12-01 4.21 116.563…
#> 9 北京通州万达广场 项目位于北… 北京… 2014-11-01 12.1 116.641…
#> 10 北京延庆万达广场 项目位于北… 北京… 2020-09-01 13.4 115.984…
#> # … with 408 more rows

注意这里的 ak=KNfhEZFNPTNL5Gyjm3O81nlE5mURbOhn 是我的百度 ak,大家需要更换成自己的(参考平台上的课程「使用 R 语言进行地理编码:地址解析经纬度、坐标转换 & 根据经纬度判断所处的省市区县」:https://rstata.duanshu.com/#/brief/course/6f8633b486ed49e398c486d0d9f0f59a)

不过这样直接得到的坐标是 GCJ02 坐标,可以使用下面的代码转换成 WGS84 的:

source("坐标转换.R")
df %>%
separate(location, into = c("经度", "纬度"), sep = ",") %>%
mutate(经度 = as.numeric(经度),
纬度 = as.numeric(纬度),
value2 = map2_chr(经度, 纬度, GCJ02_WGS84)) %>%
select(-contains("度")) %>%
separate(value2, into = c("经度", "纬度"), sep = ",") %>%
type_convert() -> df
df

#> # A tibble: 418 × 7
#> 项目 项目信息 位置 开业时间 商业面积_万平方… 经度 纬度
#> <chr> <chr> <chr> <date> <dbl> <dbl> <dbl>
#> 1 北京CBD万达广场 项目位… 北京… 2006-12-01 10.3 116. 39.9
#> 2 北京丰科万达广场 项目位… 北京… 2016-12-01 19.1 116. 39.8
#> 3 北京丰台西铁营万达广场 项目位… 北京… 2017-12-01 10.8 116. 39.9
#> 4 北京怀柔万达广场 项目位… 北京… 2018-01-01 9 117. 40.3
#> 5 北京槐房万达广场 项目位… 北京… 2016-12-01 18.9 116. 39.8
#> 6 北京乐多港万达广场 项目位… 北京… 2020-12-01 16.1 116. 40.2
#> 7 北京石景山万达广场 项目位… 北京… 2008-12-01 13.7 116. 39.9
#> 8 北京双桥万达广场 项目位… 北京… 2020-12-01 4.21 117. 39.9
#> 9 北京通州万达广场 项目位… 北京… 2014-11-01 12.1 117. 39.9
#> 10 北京延庆万达广场 项目位… 北京… 2020-09-01 13.4 116. 40.5
#> # … with 408 more rows

坐标转换.R 文件在附件中。

然后就可以保存了:

df %>%
writexl::write_xlsx("万达广场的分布.xlsx")

最后我们还可以绘制一副地图展示万达广场的分布:

library(sf)
df %>%
st_as_sf(coords = c("经度", "纬度"), crs = 4326) -> daloc

library(leaflet)
leaflet() %>%
addTiles("http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}",
attribution = "绘制:微信公众号 RStata") %>%
addScaleBar() %>%
leafem::addLogo(img = "https://mdniceczx.oss-cn-beijing.aliyuncs.com/image_20201220175301.png", width = 80, height = 80) -> map

mapview::mapview(daloc, map = map,
layer.name = "万达广场分布")

大家放大这幅地图就可以看到标注的万达广场点和底图上的有所偏差,这是因为这个底图是 GCJ02 的,如果换成 WGS84 的底图,例如 OSM 底图就不会有这种问题了:

mapview::mapview(daloc,
layer.name = "万达广场分布")

或者不要对坐标进行转换:

daloc %>%
st_drop_geometry() %>%
mutate(location = map_chr(项目, function(x) {
try({
paste0("https://api.map.baidu.com/geocoding/v3/?address=", x,
"&output=json&ak=KNfhEZFNPTNL5Gyjm3O81nlE5mURbOhn&ret_coordtype=gcj02ll") %>%
fromJSON() -> lst
paste0(lst$result$location, collapse = ",")
})
})) %>%
separate(location, into = c("经度", "纬度"), sep = ",") %>%
st_as_sf(coords = c("经度", "纬度"), crs = 4326) -> daloc2
mapview::mapview(daloc2, map = map,
layer.name = "万达广场分布")

例如:

点击这里跳转到 RStata 短书平台获取附件:使用 R 语言爬取全国所有的万达广场信息

评论