自动抓取网页数据(如何用Python从维基百科中抓取冬奥会的城市数据可视化?)
优采云 发布时间: 2021-12-21 20:16自动抓取网页数据(如何用Python从维基百科中抓取冬奥会的城市数据可视化?)
使用Python从维基百科、百度百科等中抓取公共数据网站并存入表格。这不是一项艰巨的任务。但是在很多应用场景中,我们不再局限于将捕获的数据存储在表格中,还需要更加直观的进行可视化。比如在这个案例中,使用Python从维基百科中抓取过去举办过冬奥会的城市,然后创建地图、图片库,甚至灵活的共享和协作。为此,如果在抓取数据后使用 Python 来可视化和共享网页,则会更加复杂且效率低下。对于许多非专业人士来说,它会限制性能。而且如果结合SeaTable来实现,会非常方便,任何人都可以上手。
本文将分享如何使用Python从维基百科中抓取城市数据,然后自动填充到SeaTable表中,并使用SeaTable表可视化插件自动生成地图、图库等。下图是一个基本的举办冬季奥运会的城市表。
任务目标:通过各个城市的维基链接找到该城市对应的地理位置(经纬度),并填写“经纬度”字段。同时,从维基百科下载一张城市的宣传图片,上传到“城市图片”栏。
SeaTable表格字段自动获取城市经纬度到表格的“纬度和经度”字段
要从网页中获取信息,需要一些简单的python 爬取技术。这个任务是使用 Python 模块 requests 和 beatifulsoup 实现的。requests模块可以模拟在线请求,返回html的DOM树,beatifulsoup通过解析DOM树获取标签中想要的信息。以维基百科中某个城市的经纬度为例,DOM树的结构如下:
只要在网页中可以看到信息,就可以通过DOM树的源码查询其位置,通过简单的分析就可以提取出想要的内容。具体分析方法可以参考beautifulsoup文档。
下面给出通过url解析其经纬度信息的代码:
import requests
from bs4 import BeautifulSoup
url = "https://en.wikipedia.org/wiki/Chamonix" # 维基百科的城市链接
# 请求该链接, 获取其内容, 网页内容是一段 DOM 树
resp = requests.get(url)
# 把获取的内容装进 beatifulsoup解析器,以待解析
soup = BeautifulSoup(resp.content)
# 纬度, 找到 DOM 属性 class 为 longitude 的结构, 获取其标签值
lon = soup.find_all(attrs={"class": "longitude"})[0].string
# 经度, 找到 DOM 属性 class 为 latitude的结构, 获取其标签值
lat = soup.find_all(attrs={"class": "latitude"})[0].string
上面找到的经纬度格式是标准的地理格式,写成45° 55′ 23.16″ N, 6° 52′ 10.92″ E,保存在SeaTable table 需要转换成十进制格式才能写入。这里需要写一个转换逻辑进行转换。
自动获取城市图片到表格的“城市图片”字段
在这个任务中,除了要知道经纬度信息外,还需要下载一张图片,传到表中。同样,图片的经纬度也是一样的。原创信息也可以在DOM树中找到:
img标签的src值就是我们需要的下载链接。结合SeaTable API的文件操作,可以方便的下载图片,然后上传到表中。以下是该任务的完整代码:
import requests
from bs4 import BeautifulSoup
import re
from seatable_api import Base, context
import os
import time
'''
该脚本演示了通过从维基百科举行冬奥会的城市数据中摘取相关内容,解析,并把其填入 seatable 表格中的案例
数据包括地理位置的经纬度, 以及代表图片
'''
SERVER_URL = context.server_url or 'https://cloud.seatable.cn/'
API_TOKEN = context.api_token or 'cacc42497886e4d0aa8ac0531bdcccb1c93bd0f5'
TABLE_NAME = "历届举办地"
URL_COL_NAME = "维基百科城市链接"
CITY_COL_NAME = "举办城市"
POSITION_COL_NAME = "经纬度"
IMAGE_COL_NAME = "城市图片"
def get_time_stamp():
return str(int(time.time()*10000000))
class Wiki(object):
def __init__(self, authed_base):
self.base = authed_base
self.soup = None
def _convert(self, tude):
# 把经纬度格式转换成十进制的格式,方便填入表格。
multiplier = 1 if tude[-1] in ['N', 'E'] else -1
return multiplier * sum(float(x) / 60 ** n for n, x in enumerate(tude[:-1]))
def _format_position(self, corninate):
format_str_list = re.split("°|′|″", corninate)
if len(format_str_list) == 3:
format_str_list.insert(2, "00")
return format_str_list
def _get_soup(self, url):
# 初始化DOM解析器
resp = requests.get(url)
soup = BeautifulSoup(resp.content)
self.soup = soup
return soup
def get_tu_position(self, url):
soup = self.soup or self._get_soup(url)
# 解析网页的DOM,取出经纬度的数值, 返回十进制
lon = soup.find_all(attrs={"class": "longitude"})[0].string
lat = soup.find_all(attrs={"class": "latitude"})[0].string
converted_lon = self._convert(self._format_position(lon))
converted_lat = self._convert(self._format_position(lat))
return {
"lng": converted_lon,
"lat": converted_lat
}
def get_file_download_url(self, url):
# 解析一个DOM,取出其中一个图片的下载链接
soup = self.soup or self._get_soup(url)
src_image_tag = soup.find_all(attrs={"class": "infobox ib-settlement vcard"})[0].find_all('img')
src = src_image_tag[0].attrs.get('src')
return "https:%s" % src
def handle(self, table_name):
base = self.base
for row in base.list_rows(table_name):
try:
url = row.get(URL_COL_NAME)
if not url:
continue
row_id = row.get("_id")
position = self.get_tu_position(url)
image_file_downlaod_url = self.get_file_download_url(url)
extension = image_file_downlaod_url.split(".")[-1]
image_name = "/tmp/wik-image-%s-%s.%s" % (row_id, get_time_stamp(), extension)
resp_img = requests.get(image_file_downlaod_url)
with open(image_name, 'wb') as f:
f.write(resp_img.content)
info_dict = base.upload_local_file(
image_name,
name=None,
relative_path=None,
file_type='image',
replace=True
)
row_data = {
POSITION_COL_NAME: position,
IMAGE_COL_NAME: [info_dict.get('url'), ]
}
base.update_row(table_name, row_id, row_data)
os.remove(image_name)
self.soup = None
except Exception as e:
print("error", row.get(CITY_COL_NAME), e)
def run():
base = Base(API_TOKEN, SERVER_URL)
base.auth()
wo = Wiki(base)
wo.handle(TABLE_NAME)
if __name__ == '__main__':
run()
下面是一张通过运行脚本自动写入数据的表的结果。可以看出,相对于在线搜索和手动填写每行数据,脚本的自动化操作可以节省大量时间,并且准确高效。
使用SeaTable的地图插件自动生成城市地图
有了之前获取到的城市经纬度信息,我们可以在SeaTable表的“插件”栏中添加一个地图插件,然后简单的点击即可根据“经纬度”在地图上自动标记城市“ 场地。并且还可以标记不同的标签颜色,设置直接和浮动显示字段等。相比单调地查看表格中的每个城市,通过地图进行可视化显然更加生动直观。
使用 SeaTable 的图库插件可视化城市图片
图库插件也可以放在表格工具栏上,方便随时打开查看。在图库插件的设置中,还可以根据表格中的“城市图片”字段,以图库的形式显示图片,还可以设置标题名称等显示字段. 这比浏览表格中的缩略图更美观、更方便,大大提高了浏览体验。并点击图片放大。点击标题也可以直接进入查看和编辑表格中的行内容。
此外,表单还支持灵活的共享和协作权限管控,可以满足详细多样的共享场景。例如,如果您想直接分享地图和图库供他人查看,也可以直接在表单插件的外部应用中添加“地图”和“图库”。更多使用可以自己体验,这里就不介绍了。
总结
SeaTable作为一种新型的协作表和信息管理工具,不仅功能丰富,而且使用方便。当我们通常使用Python来实现一些程序时,可以灵活组合SeaTable表的功能,从而节省编程、开发、维护等时间和人力成本,快速轻松地实现更多有趣的事情和更完整的应用。它还允许使用工具发挥更大的价值。