プログラミング

【日向坂46】ブログから画像を全自動ダウンロードしてみた②【Python】ウェブスクレイピング練習

前回の記事の続きになります。

【日向坂46】ブログから画像を全自動ダウンロードしてみた①【Python】ウェブスクレイピング練習

Pythonの練習も兼ねて何か作ろうと思い立ち、日向坂46の公式ブログをウェブスクレイピングしてみました。   はるいち本当は最近、個人的におすし(金村 美玖)が来ているだけ   ...

 

Pythonを使ったウェブスクレイピングの実践的な内容です。

 

日向坂46の公式ブログからブログ内の画像を全自動ダウンロードすることが目標です。

 

この記事を読んでもらいたい人

  • 日向坂46(特におすし推し)が好きな人
  • 画像のダウンロードを手作業でしたくない人
  • Pythonを勉強した(したい)けど活用の仕方が分からない人

 

Pythonの環境構築(準備)や基礎については以下の記事を参照してください

Pythonの始め方~準備から基礎~

私は、Pythonを習ったことがありません。   いわゆる、独学ってやつです。   独学でも これぐらいのものは作れるようにはなります。   私の場合のPython勉強方 ...

 

おことわり

  • Python歴が浅い&独学のためお見苦しいところはあると思います
  • こっちの書き方がいいと指摘があれば、コメントかTwitterで教えてくださると助かります

 

長くなるのでいくつかの記事に分けたいと思います。

 

最後の記事にはまとめたコードを載せるのでそちらをコピーしてもらえば利用できます。

 

①では、メンバーごとの情報を集めてリストにしていきました。

 

②では、ブログから画像をダウンロードしていきます。

 

注意点

注意点

日向坂46公式サイトより

ウェブスクレイピングは強力な手法ですが、いくつか注意点があるので確認しておきましょう。

 

これは①と同じなので、既に読んでいる人は本編へどうぞ。

 

攻撃とみなされる

コンピューターが高速でリクエスト(ページを表示したり、画像をダウンロードしたり)するので、それこそ人ではあり得ないスピードで行うので、相手のサーバーには負荷がかかります。

 

遅延サーバーダウンが起こったりします。

 

一時停止をはさみながらリクエストの頻度を下げる必要が有ります。

 

利用規約違反

Webサイトによっては、明確にスクレイピングを禁止しているものも存在します。

 

事前に確認しましょう。

 

日向坂の公式サイト内には見つからなかったので、節度有るリクエスト頻度なら大丈夫(なはず)。

 

著作権法違反

Webスクレイピングの対象となる情報に著作権があると、活用方法を誤ってしまうと著作権法違反となるので注意が必要です。

 

個人的に保存する分にはOKだけど、「自分の物ですよ」って使うのはOUTぐらいの感覚。

 

私は全画像ダウンロードしたけどこのサイトで公開するとBANですね。

(各自のパソコンでやってね)

 

スポンサーリンク

ライブラリ

ライブラリ

日向坂46公式サイトより

今回、使用する主なライブラリを先に紹介します。

 

インストールしていないライブラリがあったら各自「pip install」

 

ここでは、「へーそんなのあるだ~」程度の理解で大丈夫です。

 

Requests

サイトの HTMLソースを取得します。

 

ブラウザ上に文字を表示したりするコード。

 

ブラウザを開いた状態で「F12」を押すと確認できます。

 

Beautiful Soup 4

Requestsで取得したHTMLコードを解析します。

 

全体から必要な情報だけ探す時に使います。

 

pykakasi

ひらがなからローマ字に変換するために使います。

 

ファイル名をローマ字で付けたいから。

 

os

フォルダを作ったり、そのフォルダに保存したりするときに使います。

 

time

高速リクエストをすると怒られるので、1秒待つみたいな指示を出します。

 

スポンサーリンク

 

ブログから画像をダウンロードする

ブログから画像をダウンロードする

日向坂46公式サイトより

メンバー個別のブログにいって画像をダウンロードしていきます。

 

今回はおすし(金村 美玖)のブログの1ページ目を例に進めていきます。

 

サイトのHTMLを確認

とりあえずHTMLを確認してみますか。

https://www.hinatazaka46.com/s/official/diary/member/list?ima=0000&page=0&cd=member&ct=12

 

 

<div class="p-blog-article">

が1つ1つの記事になっているらしい。

 

①と同じ手順で記事のHTMLを取得します。

 

url = 'https://www.hinatazaka46.com/s/official/diary/member/list?ima=0000&page=0&cd=member&ct=12'

responce = requests.get(url)

responce.raise_for_status()

bs4_blog = bs4.BeautifulSoup(responce.text, 'html.parser')

article = bs4_blog.select('.p-blog-article')

 

基本的には同じ流れなので説明は割愛します。

 

articleに1記事ごとのHTMLを格納できたので、必要な情報を探していきましょう。

 

日付を取得する

画像ファイル名を「メンバー名_日付_番号」みたいにつけたいので、まずは日付の情報を探しましょう。

 

<div class="c-blog-article__date">

 

が日付情報みたいですね。

 

for j in range(len(article)):
    date = article[j].find('div', {'class': 'c-blog-article__date'}).get_text().strip()

 

実行結果はこんな感じ

2020.12.31 18:21
2020.12.31 18:21
#省略
2020.8.23 18:08

 

流石に投稿時間は要らないので取りましょう

 

date = date.split()

 

実行結果

['2020.12.31', '18:21']
['2020.12.31', '18:21']
#省略
['2020.8.23', '18:08']

 

split()でスペースで分ける(スプリット)

0番目が日付、1番目が投稿時間になってますね。

つまり、0番目だけをつかえばいいので

 

date = date.split()[0]

 

「年.月.日」となっているので、今度は「.」で分ければいいですね。

 

year = date.split('.')[0]
month = date.split('.')[1]
day = date.split('.')[2]

 

実行結果

2020 12 31
2020 12 31
#省略
2020 8 23

 

オッケーですね。

 

ファイル名を作りましょう。

「メンバー名_日付_」まで作ります。

おすしのローマ字名は9番目に格納されています。

 

 
label = name_rome[9] + '_' + year + '_' + month.zfill(2) + '_' + day.zfill(2) + '_'

zfill(数字)で足りない桁を「0」で埋める。

今回は二桁です。

実行結果

miku.kanemura_2020_12_31_
miku.kanemura_2020_12_31_
#省略
miku.kanemura_2020_08_23_

 

良い感じ

一連の流れをまとめると

for j in range(len(article)):
    date = article[j].find('div', {'class': 'c-blog-article__date'}).get_text().strip()
    date = date.split()[0]

    year = date.split('.')[0]
    month = date.split('.')[1]
    day = date.split('.')[2]

    label = name_rome[9] + '_' + year + '_' + month.zfill(2) + '_' + day.zfill(2) + '_'

 

スポンサーリンク

画像をダウンロードする

埋め込まれている画像のHTMLを確認すると

&amp;lt;img src=""&amp;gt;

 

ここが画像の保存先のようなので、まずimgタグを取得しましょう。

とりあえず、0番目の記事で進めていきます。

 

img = article[0].select('img')

 

imgの中からsrcを取りましょう

 

for i in range(len(img)):
    src = img[i].get('src')
    print(src)

 

実行結果

https://cdn.hinatazaka46.com/files/14/diary/official/member/moblog/202012/mobhyLvkr.jpg
https://cdn.hinatazaka46.com/files/14/diary/official/member/moblog/202012/mobPQ6y6C.jpg
https://cdn.hinatazaka46.com/files/14/diary/official/member/moblog/202012/mobXoYItQ.jpg
https://cdn.hinatazaka46.com/files/14/diary/official/member/moblog/202012/mobN6kxq5.jpg
https://cdn.hinatazaka46.com/files/14/diary/official/member/moblog/202012/mobtmvzum.jpg
https://cdn.hinatazaka46.com/files/14/diary/official/member/moblog/202012/mobnaP0PF.jpg

 

ファイル名に番号(No)を振っていきますが、同じ日に2つ記事が投稿されることを加味する必要があります。

last_dayに前の画像の日を記録し、違うならNoを0にリセットしていきます。

 

if day == last_day:
    pass
else:
    No = 0

last_day = day

for i in range(len(img)):

    file_name = label + str(No).zfill(2)

    No = No + 1

 

実行結果

miku.kanemura_2020_12_31_00
miku.kanemura_2020_12_31_01
miku.kanemura_2020_12_31_02
miku.kanemura_2020_12_31_03
miku.kanemura_2020_12_31_04
miku.kanemura_2020_12_31_05

 

ファイル名には拡張子が必要なので付けていきます。

srcに.jpgや.pngがあるのでそれを参考に付けていきます。

(jpgやpngは画像ファイルですよって意味の拡張子)

 

fg = True
if '.jpg' in src or '.jpeg' in src:
    file_name = file_name + '.jpeg'
elif '.png' in src:
    file_name = file_name + '.png'
else:
    print(src)
    fg = False

 

inは指定した文字列を含んでいる

 

実行結果

miku.kanemura_2020_12_31_00.jpeg
miku.kanemura_2020_12_31_01.jpeg
miku.kanemura_2020_12_31_02.jpeg
miku.kanemura_2020_12_31_03.jpeg
miku.kanemura_2020_12_31_04.jpeg
miku.kanemura_2020_12_31_05.jpeg

 

拡張子が付いていますね。

拡張子がjpgやpngじゃなかった時のためにチェックできるようにしています。

 

保存先のpathを指定します。

 

path = os.path.join('data', name_kanji[9], file_name)

 

実行結果

data\金村 美玖\miku.kanemura_2020_12_31_00.jpeg
data\金村 美玖\miku.kanemura_2020_12_31_01.jpeg
data\金村 美玖\miku.kanemura_2020_12_31_02.jpeg
data\金村 美玖\miku.kanemura_2020_12_31_03.jpeg
data\金村 美玖\miku.kanemura_2020_12_31_04.jpeg
data\金村 美玖\miku.kanemura_2020_12_31_05.jpeg

 

srcを元にリクエストを送り画像を保存していきます。

 

import time

if not os.path.isfile(path) and fg:
    responce = requests.get(src)
    time.sleep(1)

    if responce.status_code == 200:
        print(file_name)
        with open(path, "wb") as f:
            f.write(responce.content)
    else:
        print('False', responce.status_code, src)

 

3行目でまだダウンロードしていないか確認

4行目でリクエストを送る

5行目で1秒待つ(サーバーに負担をかけないように)

7行目でステータスコードを確認、200だと正常に接続された

9~10行目で画像の保存

11~12行目で接続できなかったsrcを表示、原因の解明に活かすため

 

保存できてる

スポンサーリンク

コードをまとめる

日向坂46公式サイトより

この記事のコードをまとめると

import time

url = 'https://www.hinatazaka46.com/s/official/diary/member/list?ima=0000&page=0&cd=member&ct=12'

responce = requests.get(url)

responce.raise_for_status()

bs4_blog = bs4.BeautifulSoup(responce.text, 'html.parser')

article = bs4_blog.select('.p-blog-article')

last_day = 0
No = 0

for j in range(len(article)):
    date = article[j].find('div', {'class': 'c-blog-article__date'}).get_text().strip()
    date = date.split()[0]

    year = date.split('.')[0]
    month = date.split('.')[1]
    day = date.split('.')[2]

    label = name_rome[9] + '_' + year + '_' + month.zfill(2) + '_' + day.zfill(2) + '_'

    img = article[j].select('img')

    if day == last_day:
        pass
    else:
        No = 0

    last_day = day

    for i in range(len(img)):
        src = img[i].get('src')

        file_name = label + str(No).zfill(2)

        No = No + 1

        fg = True
        if '.jpg' in src or '.jpeg' in src:
            file_name = file_name + '.jpeg'
        elif '.png' in src:
            file_name = file_name + '.png'
        else:
            print(src)
            fg = False

        path = os.path.join('data', name_kanji[9], file_name)

        if not os.path.isfile(path) and fg:
            responce = requests.get(src)
            time.sleep(1)

            if responce.status_code == 200:
                print(file_name)
                with open(path, "wb") as f:
                    f.write(responce.content)
            else:
                print('False', responce.status_code, src)

 

13~14行目でlast_dayとNoに初期値を入れています。

 

まとめ

本格的にウェブスクレイピングみたいになってきましたね。

 

次の記事ではループの構造を作っていきます。

 

2ページ目、3ページ目と遡っていったり、全メンバーのブログを巡回していきます。

 

個人的に、ループとif文はプログラミングの基本だと思うのでいい復習になると思います。

 

【日向坂46】ブログから画像を全自動ダウンロードしてみた③【Python】ウェブスクレイピング練習

前回の記事の続きになります。   Pythonを使ったウェブスクレイピングの実践的な内容です。   日向坂46の公式ブログからブログ内の画像を全自動ダウンロードすることが目標です。 ...

-プログラミング
-,

Copyright© はるいちの趣味 , 2022 All Rights Reserved Powered by AFFINGER5.