PythonのBeautifulSoupを使って、
複数のサイト(の最新記事)をスクレイピングし、
更新があればChatWorkに通知を送信するシステムを作成しました。
備忘録のために書き留めておきます。
メインとなるスクレイピングのコード
まずは必要なライブラリやモジュールをインポートします。
config や chatwork への通知処理は後ほど別ファイルに書きます。
# coding: UTF-8
import requests
from bs4 import BeautifulSoup
from my_config import my_config, update_recent_article
from chatwork_notification import chatwork_notify
サイト別に記事一覧を取得する関数を書きます。
スクレイピングしたいサイトごとに、最新記事のDOMを取得するように調整してください。
def extract_articles(page_html, type):
if type == "A":
main = page_html.find("div", class_="inner-news")
articles = main.find_all("li", class_="table-view-cell media")
elif type == "B":
articles = page_html.find("div", class_="comicIndex-rightBox")
return articles
次に、取得した記事から、記事のURLを抽出する関数を書きます。
def extract_article_url(article, type):
domain = ""
if type == "A":
domain = "https://AAA.jp"
elif type == "B":
domain = "https://BBB.com"
url = domain + article.get("href")
return url
次に、取得した記事から、記事のタイトルを抽出する関数を書きます。
def extract_article_title(page_html, article, type):
page_title = ""
if type == "A":
title = html.find("div", class_="media-body").getText()
title = title.replace("\n"," ")
elif type == "B":
title = html.find("span", class_="titleBox").getText()
return title + " " + page_title
取得した記事から、更新された記事を抽出します。
更新前の最新の記事のindexはmy_config.iniで管理します。
def extract_update_article(page_url, articles, recent_article, name, type):
article_list = []
first_article_num = ""
# 逆順に取得していき、最新記事より1つ古い記事のurlを取得
for article in articles:
if article == 0:
continue
url = extract_article_url(article, type)
# URLから記事番号を取得
if type == "A":
article_num = url.replace(page_url + "episode/", "").replace("/", "")
elif type == "B":
article_num = url.replace("https://BBB.com/viewer/?cid=", "")
if recent_article == article_num:
break
title = extract_article_title(page_html, article, type)
article_list.append([title, url])
if first_article_num == "":
first_article_num = article_num
# my_configを更新
if first_article_num != "":
update_recent_article(name, first_article_num)
return article_list
メインの処理を書きます。
if __name__ == "__main__":
# スクレイピングしたいサイト数だけ処理を繰り返す
for i in range(1, 2):
# my_configを取得
name = "web_info_" + str(i)
page_url = my_config[name]['url']
page_type = my_config[name]['type']
recent_article = my_config[name]['recent_article']
# スクレイピングする
res = requests.get(page_url)
page_html = BeautifulSoup(res.text, 'html.parser')
# 記事一覧を取得する
articles = extract_articles(page_html, page_type)
# 更新された記事を取得する
article_list = extract_update_article(page_url, articles, recent_article, name, page_type)
# 更新された記事があれば通知する
if len(article_list) > 0:
chatwork_notify(list_=article_list)
設定ファイルに書くコード
my_config.py に、
my_config.ini ファイルの読み取りと、
my_config.ini ファイルへの書き込み処理を書きます。
# coding: UTF-8
import configparser
import re
my_config = configparser.ConfigParser()
my_config.read('./my_config.ini')
# recent_articleの記事番号を更新する関数
def update_recent_article(name, article_num):
with open('./my_config.ini', 'r') as f:
lines = f.readlines()
with open('./my_config.ini', 'w') as f:
name_flag = False
for line in lines:
if re.match(r'(\[' + name + '\])', line):
name_flag = True
if re.match(r'(recent_article =)', line):
if name_flag:
name_flag = False
f.write("recent_article = {}\n".format(article_num))
continue
f.write(line)
次にスクレイピングサイトの情報を.iniファイルに書きます。
# coding: UTF-8
[chatwork_info]
in_webhook_url = 1
# サイトA
[web_info_1]
type = A
url = https://AAA.jp/
recent_article = 1
# サイトB
[web_info_2]
type = B
url = https://BBB.jp/
recent_article = 1
スクレイピングするサイトを増やしたい場合は、
上記と同じ形式で増やしてください。
その際、web_info_◯ の番号が重複したりずれたりしないように注意してください。
チャットワークへの通知コード
# coding: UTF-8
import requests
APIKEY = '取得したAPIキーを入力'
ENDPOINT = 'https://api.chatwork.com/v2'
ROOMID = '通知したいルームのIDを入力'
post_message_url = '{}/rooms/{}/messages'.format(ENDPOINT, ROOMID)
def chatwork_notify(list_=None):
headers = {'X-ChatWorkToken': APIKEY}
text = ""
for element in list_:
if text != "":
text += "\n"
text += element[0] + "\n" + element[1]
params = {'body': text, "self_unread": 1}
requests.post(post_message_url, headers=headers, params=params)
APIKEYとROOMIDはチャットワークにログインして取得します。
chatwork_notify関数は、site_checker.py で使用するものです。
通知したい内容に応じて、文章(text)等を好きに変更してください。