Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图

用 Python 从维基百科、百度百科等网站抓取公开的数据,并存储到表格中,这不是什么难事儿。但在很多应用场景中,我们不再局限于把抓取的数据存储到表格,还需要更直观的去可视化。比如在本案例中,用 Python 从维基百科抓取往届举办冬奥会的城市,然后制作出地图、图库,甚至进行灵活的共享协作。要实现这些,如果抓取数据后再用 Python 去做网页来可视化和共享,就会比较复杂,效率也不高,对于很多非专业人员来说,更是限制了发挥。而如果结合 SeaTable 表格来实现就会非常方便,谁都可以上手。它作为新型的在线协同表格和信息管理工具,不仅能方便地管理各类型数据,还提供了丰富的数据可视化功能,也有完善的 Python API 功能等。

本文就来分享如何用 Python 从维基百科中抓取城市数据, 然后自动填入到 SeaTable 表格中,并用 SeaTable 表格的可视化插件自动生成地图、图库等。下图是冬奥会举办城市的基础表格。

任务目标:通过每个城市的维基百科链接, 去查找该城市对应的地理位置(经纬度)并填入到“经纬度“字段, 同时在维基百科中把该城市的宣传图片下载一张,并上传到“城市图片“字段。

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第1张图片

自动获取城市经纬度到表格“经纬度”字段

从网页中获取信息, 需要一些简单的 python 爬虫技术。该任务中采用 requests 和 beatifulsoup 的 Python 模块进行实现, 其中 requests 模块可以模拟线上请求,返回一段 html 的 DOM 树, beatifulsoup 通过解析 DOM 树来获取标签中的想要的信息。以维基百科中的一个城市经纬度为例, 该 DOM 树的结构如下:

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第2张图片

只要在网页中能看到的信息, 通过 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 表格中需要将其转换成十进制的格式进行写入。这里则需要写一个转换逻辑进行转换。

自动获取城市图片到表格“城市图片”字段

该任务中除了需要知道经纬度的信息, 还需要把一张图片下载下来,传递到表格中, 同样的, 图片也和经纬度一样, 在 DOM 树中也可以找到其原始信息:

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第3张图片

其中 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()

以下是通过运行脚本自动化写入数据的表格结果, 可以看出, 比起上网查询然后手动填写每一行数据, 脚本的自动化操作则可以节省大量时间,并且准确和高效。

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第4张图片

用 SeaTable 的地图插件自动生成城市地图

有了前面获取的城市经纬度信息,我们就可以从 SeaTable 表格的“插件”栏中一键添加地图插件,然后仅需简单点选,就可以根据“经纬度”字段把城市自动标记到地图上了。并且还可以标记不同的标签颜色、设置直接和悬浮显示字段等。相比于在表格中去单调的查看各个城市,通过地图可视化显然更加形象和直观了。

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第5张图片

用 SeaTable 的图库插件可视化城市图片

图库插件同样可以放置到表格工具栏,方便随时打开查看。在图库插件的设置里,同样仅需简单点选,就可以根据表格中的“城市图片”字段,把图片以图库形式展示出来,并且还可以设置标题名称、其他显示字段。这要比在表格中去浏览小图,显得更加美观也更方便了,大大提升了浏览体验。而且点击图片还可以放大查看。点击标题还可以直接进入查看和编辑其在表格中的行内容。

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第6张图片

另外,表格还支持灵活的共享协作权限管控,能满足细致的多样化的共享场景。比如想直接共享地图、图库给别人去查看,还可以直接去表格插件的外部应用里添加“地图”、“图库”。更多使用,大家可以自行去体验,这里不多做介绍。

Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图_第7张图片

总结

作为新型的协同表格和信息管理工具,SeaTable 不仅功能丰富,而且简单易用。平时我们用 Python 实现一些程序时,就可以灵活结合 SeaTable 表格的功能,从而省去编程、开发、维护等时间和人力成本,快速又方便地实现更多有趣的事儿、更完善的应用。也让工具的运用发挥出更大的价值。

你可能感兴趣的:(Python + SeaTable | 用 Python 从维基百科抓取冬奥会城市信息并制作地图)