本文是扩展文,介绍利用Selenium模拟人工操作,从网页上自动获取信息。这样一种方法可以处理重复性工作,解放双手,提高工作效率。属于使用Pyecharts做可视化之前的一些其他探索。
在利用Excel做地图可视化时(见本系列的第4篇文章),可能会遇到一个问题,就是地址不够精确,地图无法识别。
我们以一个案例为例讲解。
佛山市的一些景点价格如下(网上查的大致价格,不一定准确):
如果我们用Excel地图去展示,会发现一共只有7个点,而我们表格明明有12个地点。也就是说还有5个地址没有识别成功,所以没有显示出来。
我们可以看一下,定位这里,可以有很多选项,经纬度,城市,国家,街道,完整地址等等。
试着改为完整地址,这个时候发现显示多了几个,但是数一下,只有9个,依然是没有显示完全。
所以我们得换一个思路,什么定位一定能够找到?答案是经纬度定位。所以我们需要把这些景点的经纬度找到。
有很多网站能提供经纬度的查询,我们选取百度出来的第一个。
进入网站后,试着查一下佛山市西樵山,很好,结果出来了。我试了下,这里需要注意的是需要把地名前面加上所属市,例如西樵山,前面加上佛山市,这样基本都能够查找到。
当我们要找的信息不多时,我们可以手工一个个去查询,但是,当数据量成千上万时,依靠人工就不太现实,还容易出错。
这时,我们可以做一个自动化工具去实现这个功能。
Selenium是一个开源软件,Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。也支持多门编程语言。
这次我用python来实现。尽管我一直很喜欢C#,但是python有太多可以参考的例子,就哪个方便用哪个。
编程之前,我们回顾一下人工去查询经纬度,它的步骤是什么:
Step1:打开网页
Step2:在地名文本框里输入要查询的景点名称
Step3:点击搜索按钮
Step4:复制查询到的经纬度值并保存
Step5:清空地名文本框并输入新的景点名称
如此重复上述过程。
分析清楚上面几步后,编程就很简单了。关于selenium的详细教程,《Selenium操作全指南,2w字超全总结》(https://blog.csdn.net/IT_LanTian/article/details/122986725)这篇文章讲得很清楚,就不在这里啰嗦。
需要提醒的是要留点时间给服务器反应一下,否则返回的经纬度值可能没有发生变化。另外是每次需要清空文本框,否则会导致输入无限叠加。代码如下:
# -*- coding: gbk -*-
# 王永平 2022.6.12
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
#这里要注意用对chromedriver的版本
browser = webdriver.Chrome(r'C:\Program Files\Google\Chrome\Application\chromedriver.exe')
#需要访问的网站
browser.get("https://jingweidu.bmcx.com/")
scenic_spot = [
'佛山市西樵山',
'佛山市长鹿农庄',
'佛山市清晖园',
'佛山市祖庙',
'佛山市南海湾森林生态园',
'佛山市顺峰山公园',
'佛山市南海影视城',
'佛山市南风古灶',
'佛山市梁园',
'佛山市盈香生态园',
'佛山市三水荷花世界',
'佛山市三水芦苞温泉度假村',
]
for i in range(len(scenic_spot)):
try:
#在地名文本框输入景点名称
browser.find_element(By.XPATH,"/html/body/div[3]/div[2]/div[1]/div[2]/div[3]/input[1]").send_keys(scenic_spot[i])
time.sleep(2)
browser.find_element(By.XPATH,"/html/body/div[3]/div[2]/div[1]/div[2]/div[3]/input[2]").click()
#给点时间,避免服务器还未来得及反应过来
time.sleep(2)
#获取经度文本框的值
lng = browser.find_element(By.XPATH,"/html/body/div[3]/div[2]/div[1]/div[2]/div[3]/input[3]").get_attribute('value')
#获取维度文本框的值
lat = browser.find_element(By.XPATH,"/html/body/div[3]/div[2]/div[1]/div[2]/div[3]/input[4]").get_attribute('value')
print(scenic_spot[i]+","+lng+","+lat)
#清空地名文本框,为下一次输入做准备(否则会在这个文本框上叠加地名导致查询不到)
browser.find_element(By.XPATH,"/html/body/div[3]/div[2]/div[1]/div[2]/div[3]/input[1]").clear()
except:
print(str(i)+",Error:跳过")
这样我们就取得了这些景点的经纬度。这里有个我经常用的技巧,就是在cmd输出的时候,用逗号或其他符号去分割连接。这是为了方便在Excel里,直接使用数据分列功能。当然,数据量大的时候,还是应该直接编程导出到Excel。
复制到excel,进行分列:
现在我们获得了经纬度了,如下所示:
接着在Excel地图里,使用经纬度定位。可以看到这次12个地点都已经有了。
这个时候,尴尬的事情发生了,这个图是有12个点了,但跟前面的9个点差异有点大。而且明明清晖园和顺峰山很近,地图上却没有显示。这是怎么回事?
我们手工去查一下清晖园。就会发现如下截图所示结果,这……跟实际离谱得不行,真是坑啊!
为了搞懂这个问题,我们直接访问腾讯地图官网去查询,会有如下结果。刚刚那个离谱的点,是下图的第8个点,它的全称是:清晖园礼饼专家。也就是之前那个网站没有考虑到多个名称重复时,应该怎么显示及让用户确认。
发现这个问题后,解决起来也简单,就是换一个经纬度查询网站。例如直接用腾讯地图或百度地图,这里两家截图还是有一点点差异,但已经非常小,本身民用地图也不会有太高精度。这个小例子说明还是大品牌靠谱。
利用这样一种方法,我们可以做出很多准确定位的地图。例如:下面这张图是全国TDS水质分布,靠经纬度定位。红色表示TDS较高,绿色表示TDS较低。