Notion-douan:搭建自己的閱讀清單

Cetusの發表於2022-03-29

前言

交完論文盲審稿,終於從接近一年的實習、秋招和論文的忙碌中閒下來。

在覆盤秋招的時候發現自己雖然看過不少書,但缺少整理和思考,所以想趁這個機會梳理一下自己的閱讀習慣,希望以後再讀新的東西可以更系統高效。但是手動輸入圖書資訊實在太慢了。經過一番調研,我發現有外掛Notion Plus可以匯出豆瓣圖書列表,但似乎缺少維護(我沒試),以及我自己想體驗一下Notion API,就動了寫一個小程式的念頭。在這裡把搭建過程分享給大家,全當拋磚引玉。

使用場景 : 將單本圖書資訊從豆瓣匯入到Notion database

建立Notion機器人

想要利用Notion提供的API對自己WorkSpace中的block進行操作的話,首先需要建立機器人(integration),併為機器人授予所需要操作的block操作許可權。在 我的機器人 頁面可以快速建立機器人。

建立新的機器人

建立新的機器人

填完資訊點選建立之後,系統跳轉到新的頁面。頁面最上方給出了這個機器人的Secrets ( 就是 Bearer token),點選Show可以檢視和複製。這個token會一直在這個頁面,所以不用擔心忘記。

Secrets

建立資料表並邀請機器人

Notion 其實是提供了建立Database的API的,但我之前其實已經手動建立過了,所以這裡就偷懶沒寫程式碼。我的資料表長這個樣子:

設計資料表

設計資料表

想偷懶的同學可以直接用我的模板:閱讀清單

做好資料表之後需要邀請機器人,並授權:

邀請機器人

獲取豆瓣讀書資料

Notion API提供的是基於RESTful架構的介面,雖然官方文件提供的是JavaScript樣例,但我自己寫Python比較多,所以還是用Python進行開發,還有一個原因就是Python爬取豆瓣資料會更加容易。

def getInfo(url):
    header={
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Encoding': 'gzip, deflate, sdch',
            'Accept-Language': 'zh-CN,zh;q=0.8',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.235'
        }

    r = requests.get(url=url, headers=header)
    soup = BeautifulSoup(r.text, 'lxml')
    # get info
    info = {}
    info['title'] = soup.h1.span.text
    infos = soup.find(id='info').find_all('span',attrs={'class':'pl'})
    
    for i in infos:
        if i.text.strip() == '作者':
            info['作者'] = i.next_sibling.next_sibling.text
        elif i.text == '出版社:':
            info['出版社'] = i.next_sibling.next_sibling.text
        else:
            info[i.text.strip().strip(':')] = i.next_sibling.text.strip()

    info['score'] = soup.find(class_='rating_num').text.strip()
    info['cover'] = soup.find(class_='nbg')['href'].strip()

    return info

獲取資料的程式非常簡單,requests傳送請求,BeautifulSoup解析html。這個函式需要的引數url就是豆瓣讀書某本書詳情頁面的連結,如:

https://cetus-img.oss-cn-beijing.aliyuncs.com/uPic/2022_03/N93e7t.png

資料寫入Notion

到這一步其實才開始用Notion API,簡單來說就是構造請求,POST到指定的API就可以新建一條記錄了。其中,構造請求的關鍵在於構造各欄位(Property)。Notion中各類Property的values可以從property-value-object 中找到詳細資訊。比如Database的Name欄位屬於Title property,構造方式如下:

{
  "Name": {
    "title": [
      {
        "type": "text",
        "text": {
          "content": "The title"
        }
      }
    ]
  }
}

這裡有一個小技巧,就是可以先通過程式查詢指定頁面中各欄位的值來獲取頁面結構,然後直接修改相應的值就可以了。查詢指定頁面的欄位結構,可以構造如下請求:

import requests
token = '***'
database_id = '***'
r = requests.request(
    "POST",
    "https://api.notion.com/v1/databases/" + database_id + "/query",
    headers={"Authorization": "Bearer " + token, "Notion-Version": "2022-02-22"},
)
print(r.text)

其中,token 就是上文建立機器人時Notion自動分配的Secrets ,database_id 就是需要查詢的頁面的id,頁面的id可以直接從連結中找到,下如紅框中的一串(從 / 到 ?中間 )就是id。

https://cetus-img.oss-cn-beijing.aliyuncs.com/uPic/2022_03/DZlBeA.png

我擷取了查詢請求返回值的幾個Property:

"頁數": {
    "id": "U_TO",
    "type": "number",
    "number": 528
},
"書名": {
    "id": "title",
    "type": "title",
    "title": [
        {
            "type": "text",
            "text": {
                "content": "切爾諾貝利的午夜",
                "link": null
            },
            "annotations": {
                "bold": false,
                "italic": false,
                "strikethrough": false,
                "underline": false,
                "code": false,
                "color": "default"
            },
            "plain_text": "切爾諾貝利的午夜",
            "href": null
        }
    ]
},
"封面": {
    "id": "jZol",
    "type": "files",
    "files": [
        {
            "name": "https://img1.doubanio.com/view/subject/l/public/s33836089.jpg",
            "type": "external",
            "external": {
                "url": "https://img1.doubanio.com/view/subject/l/public/s33836089.jpg"
            }
        }
    ]
},

我們可以直接將對應的值替換成我們之前獲取到的資訊。這裡面有很多欄位是我們不需要的,比如“id”,或者"annotations" 。Notion會幫我們自動補全。

我構建的完整的Property如下:

body = {
      "parent": { "type": "database_id", "database_id":  database_id},
      "properties": {
          "書名": {
              "type": "title",
              "title": [{"type": "text", "text": {"content": info.get("title",' ')}}]
          },
          "豆瓣連結": {
              "url": url
          },
          "ISBN": {
              "type": "rich_text", 
              "rich_text": [{"type": "text", "text": {"content": info.get("ISBN",'')}}]
          },
          "頁數": {
              "number": int(info.get("頁數",0))
          },
          "出版社": {
              "type": "rich_text",
              "rich_text": [{"type": "text", "text": {"content": info.get("出版社",' ')}}]
          },
          "評分": {
              "number": float(info["score"])
          },
          "作者": {
              "type": "rich_text",
              "rich_text": [{"type": "text", "text": {"content": info.get('作者','')}}]
          },
          "標籤": {
              "type": "multi_select",
              "multi_select": [{"name": info.get('tag')}]
          },
          "封面": {
              "files": [
                  {
                      "type": "external",
                      "name": info['cover'],
                      "external": {"url": info['cover']}
                  }
              ]
          },
          "狀態": {
              "type": "select",
              "select": {
                  "name": info.get('status'),
              }
          },
      },
  }

之後將這個Body作為請求的主體傳送到相應的Notion API就可以在我們的資料表中新增一條新的記錄啦。

re = requests.request(
        "POST",
        "https://api.notion.com/v1/pages",
        json= body,
        headers={"Authorization": "Bearer " + token, "Notion-Version": "2022-02-22"},

    )

完整程式碼可以從我的Github獲得:Notion_douban

效果

最終的效果如下:

https://cetus-img.oss-cn-beijing.aliyuncs.com/uPic/2022_03/QGNrnx.png

還可以新增一個Gallery View:

https://cetus-img.oss-cn-beijing.aliyuncs.com/uPic/2022_03/rremvg.png

相關文章