目次
最近は、やれ新しい生成系AIだのクラウドサービスだのOSSだのとサービスがたくさん出すぎてついていけないですね…
でもエンジニアたるもの把握しておかないと…! ということで最近は情報収集も兼ねて技術記事の要約を日課にするようにしています!
今回はその情報収集…がめんどくさくて作ったツールのご紹介をしようと思います(笑)
突然ですが、皆さんはノートアプリはご利用されておりますでしょうか?
Onenote、Evernote、Google Keep等々たくさんありますが、私はNotionというアプリケーションを利用しています。
Notionではこんな感じで
Wiki的なものが作れたり…
簡易的なデータベースが作れたり…
APIを利用して外からいじれたり…
Introduction to Notion’s API
自分でカスタマイズするのがお好きな方にはおすすめです!(できることが多すぎて逆に苦労するのですが…)
記事の要約もこのような感じでNotionで行っています!
全体的な流れとしては
1. Newサイトから最新の記事を見つけて…
2. 記事のタイトルをコピペして…
3. URLをコピペして…
4. 記事を要約して…
5. 索引のためのタグ付けて…
これを1,2週間程度やってみたのですが、めんどくさい….
目的である記事の要約までに時間かかりすぎだし、確認したいNewサイト数に比例して手間が増えていく…
これではやる気がなくなってしまいますね(笑)
…ということで、自動でその日の記事がNoteとしてNotionのデータベースに蓄積されるツールを作りました!
※少々長くなりそうですが、もしご興味ありましたらお付き合いいただければと思います…!
概要
特定の日時に対象Newsサイトに対してScrapingを実施し、最新記事のみ抜き出してNotionのデータベースに流し込み、Noteを作成する。
- 上記”全体的な流れ”の1~3までを自動化
- 対象とするNewsサイト数と工数の比例関係を解消
- もっと多くのサイトからも記事を見つけてくることができる!
- 情報取集のタスクを本当の意味で”情報を見る”ところから始められる。
- 忙しい日でも…外出していても…Newsは保存することで見逃しをなくす。
1. まずはPythonでScrapingのCodeを作るところから…
対象とするNewsサイトはこちら
日経クロステック(xTECH)
Publickey - Enterprise IT × Cloud Computing × Web Technology / Blog
Category: Blog | Cloud Native Computing Foundation
Scrapingとはなんぞや
Pythonの活用方法のひとつにスクレイピングがあります。 スクレイピングとは、WEB上のページにアクセスし、必要な情報を抽出する行為です。 人間が1つひとつ手作業で情報を集めるのに比べ、プログラムを利用した情報の抽出は実装さえ済めば圧倒的に早い速度で多くの情報を集めることが出来ます。
【抜粋】 https://techplay.jp/column/601
【ルールを守って楽しく開発!】
Web Scrapingは実装方法によっては対象のサービスに負荷をかけてしまう恐れがございます。
実施前に必ず、注意するべきことをご確認頂きますようお願いいたします。
本ツールにおけるScrapingのイメージは…
1.記事のこのあたりから”タイトル”, “URL”, “日付”を取ってくる。
2.こんな感じの配列に入れる。
1 2 3 4 5 6 7 8 9 10 11 |
[ ["Title 1", "yyyy-mm-dd", "URL 1"], ["Title 2", "yyyy-mm-dd", "URL 2"], ... ["Title n", "yyyy-mm-dd", "URL n"], ] |
3.最後にこれをNotion APIを通してデータベースに流し込む
そんな感じで書いたコードがこちら…
※いろいろと雑なのは趣味開発ということでご容赦ください…(笑)
日経クロステック(xTECH)用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def xtech_news(): url = "https://xtech.nikkei.com/top/latestdaily.html" res = urllib.request.urlopen(url) soup = BeautifulSoup(res, 'html.parser') page = soup.find("ul", class_="p-articleList -medium") articles = page.find_all("li", class_="p-articleList_item FREE") art_list = [] for t in articles: temp_list = [] page_url = "https://xtech.nikkei.com" + str(t.find("a").get('href')) t = t.text title = ' '.join(t.split()) article_day = str(day.date()) temp_list.append(article_day) temp_list.append(title) temp_list.append(page_url) art_list.append(temp_list) return art_list |
Publickey 用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
def public_key_news(): url = "https://www.publickey1.jp/" res = urllib.request.urlopen(url) soup = BeautifulSoup(res, 'html.parser') articles = soup.find_all("li", class_="clearfix") art_list = [] for t in articles: title = t.find("a").text title = ' '.join(title.split()) article_day = t.find("span", class_="date").text test = t.find("span", class_="date").text page_url = t.find("a").get("href") temp_list = [] article_day = datetime.strptime(article_day, '%Y-%m-%d') temp_list.append(str(article_day.date())) temp_list.append(title) temp_list.append(page_url) #article_day = datetime.strptime(article_day, '%Y-%m-%d').date() if article_day.date() >= day.date(): art_list.append(temp_list) return art_list |
Category: Blog | Cloud Native Computing Foundation 用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
def cnfs_blog(): url = "https://www.cncf.io/blog/" res = urllib.request.urlopen(url) soup = BeautifulSoup(res, 'html.parser') articles = soup.find_all("div", class_="post-archive__text-wrapper") art_list = [] for t in articles: title_list = t.find("span", class_="post-archive__title") title = title_list.text title = ' '.join(title.split()) article_day = t.find("span", class_="post-archive__item_date").text target = "|" idx = article_day.find(target) article_day = ''.join(article_day[:idx].split()) article_day = ''.join(article_day.split(",")) article_day = datetime.strptime(str(article_day),"%B%d%Y") article_day = article_day.date() page_url = title_list.find("a").get("href") temp_list = [] temp_list.append(str(article_day)) temp_list.append(title) temp_list.append(page_url) if article_day >= day.date(): art_list.append(temp_list) return art_list |
次はNotionのAPIを通して、取ってきたデータからノートを作成していきます!
…がこれがいろいろと面倒なことが多そう…
そこで簡易的なWraperを作っている方がいらっしゃったので、こちらを使用していきます!
※巨人の肩には積極的に乗らせていただきます…(笑)
GitHub – qlitre/python-notion: Pythonで作ったNotion APIの簡易ラッパーです
Pythonで作ったNotion APIの簡易ラッパーです。 Contribute to qlitre/python-notion development by creating an account on GitHub.
流れとしては、
1.Notion側でIntegrationを作成して、API Tokenを持ってくる。
2.Databaseを定義したPage側で上記のIntegrationを有効化。
これで外部からのアクセスおよび編集権限を与えることができるらしい…
【参考】Introduction to Notion’s API
3.最後にPython側にDatabeseのURLを教えてあげれば、あとは煮るなり焼くなり
そんな感じで作ったCodeがこちら…
※result ではScrapingで作成した配列を受け取っています。
1 2 3 4 5 6 7 8 9 10 11 12 |
from notion import NotionClient def import_notion(result): for i in result: try: add_items = {'Date': i[0], 'Name': i[1],'URL':i[2]} client.add_page_to_database(database_id=database_id, prop_name_and_value=add_items) except Exception as e: error_date = str(day.date()) Error_format = '\n'.join(i) add_items = {'Error type': str(e), 'Date': error_date,'Error_format':Error_format} client.add_page_to_database(database_id=database_id_error, prop_name_and_value=add_items) |
と…ここまででツール本体の機能が準備できました!
次はこれをどこで実装するか…
– ツールは毎週月曜 – 金曜の18時に実行
– 実行時間は一日5秒程度
– インターネットへのアクセスが必要
– できるだけコストがかからないようにしたい…
…ということで、今回の実行環境には(クラウドの勉強も兼ねて) AWS Lamdbaを採用していきたいと思います!
AWS Lambdaとはなんぞや
AWS Lambda は、サーバーをプロビジョニングまたは管理せずにコードを実行できるようにするコンピューティングサービスです。
Lambda は可用性の高いコンピューティングインフラストラクチャでコードを実行し、コンピューティングリソースに関するすべての管理を行います。これには、サーバーおよびオペレーティングシステムのメンテナンス、容量のプロビジョニングおよび自動スケーリング、さらにログ記録などが含まれます。Lambda で必要なことは、サポートするいずれかの言語ランタイムにコードを与えることだけです。
【抜粋】 AWS Lambda の概要 – AWS Lambda
つまり、EC2などインフラ環境を意識することなく、クラウド上でコードを実行できるサーバーレスサービスですね。
ちなみに気になる料金はこちら…
AWSにはサービスによって無料利用枠があり、Lamdbaでは1カ月間で100万リクエストまで無料で利用できるようです!(今回の実装なら無料で利用できそう…?)
…ということで実装した様子がこちら
さらに今回はAWS Lambdaに対して、特定の日時に動かすために、 Amazon EventBridgeも利用していきます。
Amazon EventBridgeとはなんぞや
EventBridge は、イベントを使用してアプリケーションコンポーネント同士を接続するサーバーレスサービスです。これにより、スケーラブルなイベント駆動型アプリケーションを簡単に構築できます。イベント駆動型アーキテクチャとは、イベントの発信と応答によって連携する、ゆるやかに結合されたソフトウェアシステムを構築するスタイルです。イベント駆動型アーキテクチャは、俊敏性を高め、信頼性が高くスケーラブルなアプリケーションを構築するのに役立ちます。
EventBridge を使用して、自社開発アプリケーション、AWS サービス、サードパーティソフトウェアなどのソースから組織全体のコンシューマアプリケーションにイベントをルーティングできます。EventBridge では、イベントの取り込み、フィルタリング、変換、配信をシンプルかつ一貫性のある方法で行うことができるため、アプリケーションをすばやく構築できます。
【抜粋】 Amazon EventBridge とは – Amazon EventBridge
これを利用することで連携するサービスに対して、Cron式を利用して特定の時間に実行命令を出せるようなのです。
※今回は単純なCron式のみの利用ですが、サービスのアラート機能であったり、バッチ分析、セキュリティイベントの発報などなど多種多様なことができるようでご興味ありましたら是非…!
…ということで実装した様子がこちら
対象のサービスを指定するだけで簡単に紐づけできました!
Cron式の設定も赤枠のこれだけ…
今回構築したツールのザックリとしたイメージがこちらになります!
1.月曜から金曜の18時になったらAmazon EventBridgeがAWS lambda内のツールにイベントを送信
2.ツールは対象サイトへスクレイピングし、“タイトル”、“日付”、”URL”取得し配列へ
3. Notion APIを通じて”タイトル”、“日付”、”URL”を含めたNoteを作成
【コラム】ChatgptのAPIも使ってみた
この記事を書いていてもしかしてChatGPTにお願いしたら、要約もしてくれるんじゃね…?
と思ったので、興味本位で試してみました。
(本末転倒もいいところなので、実装はしませんが…笑)
※API利用は無料版ではできないらしく、課金する必要がありますのでご注意ください!!
AITech – 誰でも使えるAIを検索しよう! – 15 Jul 23
ChatGPT APIの料金を全て紹介!GPT3.5とGPT4の違いやGPT4-Turboについても!
ChatGPTの機能を他のサービス、(例えば、スプレッドシートやGoogleドキュメント、自作チャットボットなど)からでも使用できるようにする仕組みがAPIです。この記事では、APIの使用におけるGPT3.5とGPT4の料金の違いと取得方法について解説します。
処理の流れは…
1.NoteのTagに”Help GPT”を設定
2.スクリプトを実行
3.上記のTagのついたNoteのURLにアクセスして、記事の本文を取得
4.Chat-GPTのAPIを利用して、GPTに要約を依頼
5.要約された文章をNotionのAPIを通してNoteの本文へ
早速スクリプトを書いてみました。
help_gpt.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
from notion_client import Client import urllib.request from bs4 import BeautifulSoup import openai from notion import NotionClient token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" notion_client = NotionClient(token) client = Client(auth=token) openai.api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" def public_key_news(url): content = "" res = urllib.request.urlopen(url) soup = BeautifulSoup(res, 'html.parser') articles = soup.find_all("div", class_="entrybody clearfix") for i in articles: content = content + i.text return content def read_notion_database(database_id): response = client.databases.query( **{ "database_id": database_id, "filter": { "property": "Tags", "multi_select": { 'contains': 'Help-GPT' } } } ) return response def write_notion_database(page_id, context): notion_client.add_paragraph_to_page(page_id=page_id, content=context) print("OK") def help_GPT(target_sentence): responce = openai.ChatCompletion.create( model="gpt-3.5-turbo", #model="gpt-4", messages=[ {"role":"system","content":"あなたは優秀で技術分野に特化した新聞記者です。"}, {"role":"assistant","content": target_sentence}, {"role":"user","content":"上記の文章を要点整理し、50文字から100文字で箇条書きで要約してください。また、文末に文章中の固有名詞またはIT技術用語とその意味の表で作成してください。"} ] ) print(responce["choices"][0]["message"]["content"]) return responce["choices"][0]["message"]["content"] data = read_notion_database("xxxxxxxxxxxxxxxx") url = data.get('results')[0].get('properties').get('URL').get('url') page_id = data.get('results')[0].get('id') content = public_key_news(url) write_notion_database(page_id, help_GPT(content)) |
すごい…さすがGPT先生ですね
しかもGPTへの処理はこの場所だけ…
指示する日本語の方が難しいですね…笑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import openai def help_GPT(target_sentence): responce = openai.ChatCompletion.create( model="gpt-3.5-turbo", #model="gpt-4", messages=[ {"role":"system","content":"あなたは優秀で技術分野に特化した新聞記者です。"}, {"role":"assistant","content": target_sentence}, {"role":"user","content":"上記の文章を要点整理し、50文字から100文字で要約してください。また、文末に文章中の固有名詞またはIT技術用語とその意味の表で作成してください。"} ] ) return responce["choices"][0]["message"]["content"] |
今回は思い付きの雑な実装でしたが、もう少し工夫すればいろいろと面白いことができそうです!
最後に
実際のNotion Note
Notionでは、NoteをWeb上に公開できるようなので参考までに完成したNoteのページを添付しておきます。
Notion Page 3
以上で今回作成したツール開発のご紹介になります!
ここまで大変長くなりましたが、お付き合いいただきありがとうございました!
今回利用した技術以外にも挑戦してみたい方は、Avintonのエンジニア研修の教育プログラムAvintonアカデミーも覗いてみてくださいね。