Help us understand the problem. What is going on with this article?

サイトの更新日を真面目に取得する

(更新)クラスにしたものを置いておきます。 【Python】ニュース記事の更新日をHTMLから取得する

サイトの更新日を取得するのってむずくね

レスポンスヘッダーを調べることで、静的なサイトであれば最終更新日がわかることがあります。

get_lastmodified.py
import requests
res = requests.head('https://www.kantei.go.jp')
print(res.headers['Last-Modified'])
Mon, 17 Feb 2020 08:27:02 GMT

(前回記事)【Python】ウェブサイトの最終更新日を取得

一部ニュースサイトや日本の政府関係の多くのサイトではこれで問題なく取れるのですが、大半のサイトはうまくいきません。

KeyError: 'last-modified'

じゃどうしたらいいかというと、大きく2つの方法がありそうです。

方針1 URLを見る

URLの中には 2019/05/01 や 2019-05-01 のような文字列が入っていることがあります。これを抜き出すのは有力で確実な手段です。

方針2 スクレイピング

最終的に頼るのはここなんでしょう。

ということで、これらの合わせ技で、普段読んでいるニュースサイトから自動でサイト更新日を抜き出していきます。
取得したbeautifulsoupオブジェクトをsoupとしています。
取得した更新日はdatetime型に変換します。文字列の抽出や整形は正規表現を使います。

get_lastmodified.py
import bs4
import datetime
import re

調べたニュースサイト

CNN
Bloomberg
BBC
Reuter
Wall Street Journal
Forbes Japan
Newsweek
朝日新聞
日経新聞
産経新聞
読売新聞
毎日新聞

CNN

https://edition.cnn.com/2020/02/17/tech/jetman-dubai-trnd/index.html

get_lastmodified.py
print(soup.select('.update-time')[0].getText())
#Updated 2128 GMT (0528 HKT) February 17, 2020 

timestamp_temp_hm = re.search(r'Updated (\d{4}) GMT', str(soup.select('.update-time')[0].getText()))
timestamp_temp_bdy = re.search(r'(January|February|March|April|May|June|July|August|September|October|November|December) (\d{1,2}), (\d{4})', str(soup.select('.update-time')[0].getText()))
print(timestamp_temp_hm.groups())
print(timestamp_temp_bdy.groups())
#('2128',)
#('February', '17', '2020')
timestamp_tmp = timestamp_temp_bdy.groups()[2]+timestamp_temp_bdy.groups()[1]+timestamp_temp_bdy.groups()[0]+timestamp_temp_hm.groups()[0]
news_timestamp = datetime.datetime.strptime(timestamp_tmp, "%Y%d%B%H%M")
print(news_timestamp)
#2020-02-17 21:28:00


# 日付だけならURLからも取れる
URL = "https://edition.cnn.com/2020/02/17/tech/jetman-dubai-trnd/index.html"
news_timestamp = re.search(r'\d{4}/\d{1,2}/\d{1,2}', URL)
print(news_timestamp.group())
#2020/02/17
news_timestamp = datetime.datetime.strptime(news_timestamp.group(), "%Y/%m/%d")
print(news_timestamp)
#2020-02-17 00:00:00

コメント:'Updated'の文字列が常に入っているのかは未検証。CNNの記事はまとめページを除くと日付がURLに入っているので、これを取るのが確実に見える

Bloomberg

https://www.bloomberg.co.jp/news/articles/2020-02-17/Q5V6BO6JIJV101

get_lastmodified.py
print(soup.select('time')[0].string)
# #
# #            2020年2月18日 7:05 JST
# #
timesamp_tmp = re.sub(' ','',str(soup.select('time')[0].string))
timesamp_tmp = re.sub('\n','',timesamp_tmp)
news_timestamp = datetime.datetime.strptime(timesamp_tmp, "%Y年%m月%d日%H:%MJST")
print(news_timestamp)
#2020-02-18 07:05:00

# URLでも日付までは取れる
URL = "https://www.bloomberg.co.jp/news/articles/2020-02-17/Q5V6BO6JIJV101"
timestamp_tmp = re.search(r'\d{4}-\d{1,2}-\d{1,2}', URL)
print(news_timestamp_tmp.group())
#2020-02-17
news_timestamp = datetime.datetime.strptime(timestamp_tmp, "%Y-%m-%d")
print(news_timestamp)
#2020-02-17 00:00:00

コメント:タグ内で改行と空白があり一手間必要。

BBC

https://www.bbc.com/news/world-asia-china-51540981

get_lastmodified.py
print(soup.select("div.date.date--v2")[0].string)
#18 February 2020
news_timestamp = datetime.datetime.strptime(soup.select("div.date.date--v2")[0].string, "%d %B %Y")
print(news_timestamp)
#2020-02-18 00:00:00

コメント:細かい時間はどこ見ればいいのかわかりませんでした。

Reuter

https://jp.reuters.com/article/apple-idJPKBN20C0GP

get_lastmodified.py
print(soup.select(".ArticleHeader_date")[0].string)
#February 18, 2020 /  6:11 AM / an hour ago更新

m1 = re.match(r'(January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}',str(soup.select(".ArticleHeader_date")[0].string))
print(m1.group())
#February 18, 2020

m2 = re.search(r'\d{1,2}:\d{1,2}',str(soup.select(".ArticleHeader_date")[0].string))
print(m2.group())
#6:11

news_timestamp = datetime.datetime.strptime(m1.group()+' '+m2.group(), "%B %d, %Y %H:%M")
print(news_timestamp)
#2020-02-18 00:00:00

Wall Street Journal

https://www.wsj.com/articles/solar-power-is-beginning-to-eclipse-fossil-fuels-11581964338

get_lastmodified.py
print(soup.select(".timestamp.article__timestamp")[0].string)
#
#          Feb. 17, 2020 1:32 pm ET
#

news_timestamp = re.sub(' ','',str(soup.select(".timestamp.article__timestamp")[0].string))
news_timestamp = re.sub('\n','',m)
print(news_timestamp)
#Feb.17,20201:32pmET
news_timestamp = re.match(r'(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec).(\d{1,2}),(\d{4})(\d{1,2}):(\d{1,2})',str(news_timestamp))
print(news_timestamp.groups())
#('Feb', '17', '2020', '1', '32')
tmp = news_timestamp.groups()
timesamp_tmp = tmp[0]+' '+ tmp[1].zfill(2)+' '+tmp[2]+' '+tmp[3].zfill(2)+' '+tmp[4].zfill(2)
print(timesamp_tmp)
#Feb 17 2020 01 32
news_timestamp = datetime.datetime.strptime(timesamp_tmp, "%b %d %Y %H %M")
print(news_timestamp)
#2020-02-17 01:32:00

Forbes Japan

https://forbesjapan.com/articles/detail/32418

get_lastmodified.py
print(soup.select("time")[0].string)
#2020/02/18 12:00
news_timestamp = datetime.datetime.strptime(soup.select("time")[0].string, "%Y/%m/%d %H:%M")
print(news_timestamp)
#2020-02-18 12:00:00

Newsweek

https://www.newsweek.com/fears-rise-over-coronavirus-american-cruise-passenger-diagnosed-after-previously-showing-no-1487668

get_lastmodified.py
print(soup.select('time')[0].string)
# On 2/17/20 at 12:11 PM EST
m = re.search(r'(\d{1,2})/(\d{1,2})/(\d{1,2}) at (\d{1,2}:\d{1,2}) ', str(soup.select('time')[0].string))
print(m.groups())
#('2', '17', '20', '12:11')
tmp = m.groups()
timesamp_tmp = tmp[0].zfill(2)+' '+ tmp[1].zfill(2)+' '+'20'+tmp[2].zfill(2)+' '+tmp[3]
print(timesamp_tmp)
news_timestamp = datetime.datetime.strptime(timesamp_tmp, "%m %d %Y %H:%M")
print(news_timestamp)
#2020-02-17 12:11:00

朝日新聞

https://www.asahi.com/articles/ASN2K7FQKN2KUHNB00R.html

get_lastmodified.py
print(soup.select('time')[0].string)
#2020年2月18日 12時25分
news_timestamp = datetime.datetime.strptime(soup.select('time')[0].string, "%Y年%m月%d日 %H時%M分")
print(news_timestamp)
#2020-02-18 12:25:00

コメント:静的でわかりやすい。ざっと見たところカテゴリー別でも揺らぎが無くて助かる。

日経新聞

https://r.nikkei.com/article/DGXMZO5556760013022020TL1000

get_lastmodified.py
print(soup.select('time')[1])
#2020年2月18日 11:00
news_timestamp = datetime.datetime.strptime(soup.select('time')[1].string, "%Y年%m月%d日 %H:%M")
print(news_timestamp)
#2020-02-18 11:00:00

https://www.nikkei.com/article/DGXLASFL18H2S_Y0A210C2000000

get_lastmodified.py
print(soup.select('.cmnc-publish')[0].string)
#2020/2/18 7:37
news_timestamp = datetime.datetime.strptime(soup.select('.cmnc-publish')[0].string, "%Y/%m/%d %H:%M")
print(news_timestamp)
#2020-02-18 07:37:00

https://www.nikkei.com/article/DGXKZO55678940V10C20A2MM8000

get_lastmodified.py
print(soup.select('.cmnc-publish')[0].string)
#2020/2/15付
news_timestamp = datetime.datetime.strptime(soup.select('.cmnc-publish')[0].string, "%Y/%m/%d付")
print(news_timestamp)
#2020-02-15 00:00:00

コメント:色々書き方がある。ざっと見で3つあったけれどもっとあるかも。

産経新聞

https://www.sankei.com/world/news/200218/wor2002180013-n1.html

get_lastmodified.py
print(soup.select('#__r_publish_date__')[0].string)
#2020.2.18 13:10
news_timestamp = datetime.datetime.strptime(soup.select('#__r_publish_date__')[0].string, "%Y.%m.%d %H:%M")
print(news_timestamp)
#2020-02-18 13:10:00

コメント:よくみたらURLに時まで載ってた。

読売新聞

https://www.yomiuri.co.jp/national/20200218-OYT1T50158/

get_lastmodified.py
print(soup.select('time')[0].string)
#2020/02/18 14:16
news_timestamp = datetime.datetime.strptime(soup.select('time')[0].string, "%Y/%m/%d %H:%M")
print(news_timestamp)
#2020-02-18 14:16:00

コメント:日付だけならURLから取れる。

毎日新聞

https://mainichi.jp/articles/20180803/ddm/007/030/030000c

get_lastmodified.py
print(soup.select('time')[0].string)
#2018年8月3日 東京朝刊
news_timestamp = datetime.datetime.strptime(soup.select('time')[0].string, "%Y年%m月%d日 東京朝刊")
print(news_timestamp)
#2018-08-03 00:00:00

https://mainichi.jp/articles/20200218/dde/012/030/033000c

get_lastmodified.py
print(soup.select('time')[0].string)
#2020年2月18日 東京夕刊
news_timestamp = datetime.datetime.strptime(soup.select('time')[0].string, "%Y年%m月%d日 東京夕刊")
print(news_timestamp)
#2020-02-18 00:00:00

https://mainichi.jp/articles/20200218/k00/00m/010/047000c

get_lastmodified.py
print(soup.select('time')[0].string)
#2020年2月18日 09時57分
#最終更新はprint(soup.select('time')[1].string)
news_timestamp = datetime.datetime.strptime(soup.select('time')[0].string, "%Y年%m月%d日 %H時%M分")
print(news_timestamp)
#2020-02-18 09:57:00

https://mainichi.jp/premier/politics/articles/20200217/pol/00m/010/005000c

get_lastmodified.py
print(soup.select('time')[0].string)
#2020年2月18日
news_timestamp = datetime.datetime.strptime(soup.select('time')[0].string, "%Y年%m月%d日")
print(news_timestamp)
#2020-02-18 00:00:00

コメント:毎日新聞では、電子版のみの記事は分単位で取得できるぽい。朝刊・夕刊からの記事と毎日プレミアについては、URLで取れるのと同じ、日付までしか取得できない。

ニュースサイト Rヘッダーから URLから HTML中身から
CNN 年月日 年月日時分
Bloomberg 年月日 年月日時分
BBC 年月日
Reuter 年月日時分
Wall Street Journal 年月日時分
Forbes Japan 年月日時分
Newsweek 年月日時分
朝日新聞 年月日時分 年月日時分
日経新聞 年月日時分
産経新聞 年月日時分 年月日時 年月日時分
読売新聞 年月日 年月日時分
毎日新聞 年月日 年月日時分*

*毎日新聞は記事によっては日付のみあるいは日付+朝/夕刊の記載

思ったこと

言語はもちろん、サイトごとに日付の表記はまちまちです。同じニュースサイト内であっても表記揺れがあり、それについては全てを確認できているわけではありません。
HTMLみても取れないけどURLを見るとわかる、というサイトは今のところ見つけられていません。合わせ技と言いましたが、スクレイピングだけで取得しても変わらないですね。
この方法は各サイトごとに地道にタグやクラス名を読んでいかなければならず、全てのサイトはもちろん、ニュースサイトのみですら対応するのはかなり難しそうです。もっと良いやり方があればぜひ教えてください。

(更新)クラスにしたものを置いておきます。 【Python】ニュース記事の更新日をHTMLから取得する

KanikaniYou
昨今のAIブームに押し流されてPython勉強中の文系学生。 Qiitaでは自分のような初学者が躓いたポイントを共有していきたいです。 VRガジェットも好き。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした