konchangakita

KPSを一番楽しんでいたブログ 会社の看板を背負いません 転載はご自由にどうぞ

はじめての Webスクレイピングを BeautifulSoupで

(※Webサイト書いているのがまずかったら、すぐ修正します)
Webスクレイピングとは、インターネット上のいろんなデータ(記事とか画像とか)をプログラムで(Bot的)収集・保存するものです
似たもので微妙に違うらしいクローリングという言葉もありますが、その違いにあまり意味はないのでどちらでもよいです

うまいこと作れば作るほどに自動的に大量の画像ダウンロードできちゃったりするので、サーバに負担がかかるので禁止されているサイトもありますので注意しましょう。画像収集はほどほどに、攻撃とみなされる場合もあります

BeautifulSoup4 のインストール

BeautifulSoup はシンプルなスクレイピングフレームワークです
Jupyter notebook環境にインストールするので "conda" で

conda install beautifulsoup
> conda list beautifulsoup
# packages in environment at C:\ProgramData\Anaconda3\envs\PyTorch15:
#
# Name                    Version                   Build  Channel
beautifulsoup4            4.9.1                    py38_0    anaconda
from bs4 import BeautifulSoup


Jupyter notebook でコーディング

試しにファイナルファンタジーXIV ファンキットサイトのパソコン用画像をダウンロードするのを例にとってみます(サムネイルの23枚分だけ)
f:id:konchangakita:20200719174707p:plain

1.WebページのHTMLを取得

まずは BeautifulSoup を使って、このページの html記述をまるっとゲット

from bs4 import BeautifulSoup
import requests
import re

url = 'https://jp.finalfantasyxiv.com/xxxxxxxxxxx/xxxxxxxx/'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')
soup

f:id:konchangakita:20200719174117p:plain

取得したHTMLから imgタグのサムネイル部分のだけを抜き出して画像ダウンロードしたいです

<li>
<div class="box_pc_wallpaper">
/*↓この部分↓*/
<img alt="" height="169" src="https://img.finalfantasyxiv.com/xxx/x/x/xxxxxxxxxxxxx.jpg" width="300"/>
/*↑この部分↑*/
<img alt="NEW" class="ic_new" height="24" src="https://img.finalfantasyxiv.com/xxx/x/x/xxxxxxxxxx.png" width="54"/>
</div>


2.タグ抽出

まずは imgタグ を抽出します
 ・"soup.find" だと一致した一個目
 ・"soup.find_all" で一致した全部

img_tag = soup.find_all('img')
img_tag

f:id:konchangakita:20200719183313p:plain

3.特定して絞り込み

imgタグ指定と、正規表現(URLと画像の大きさ)で範囲を絞って、ダウンロードしたいサムネイル画像のURLのみを取得
 ・srcのURL'^https://img.finalfantasyxiv.com/xxx/x/.*\.jpg'
 ・width="300"

import re

imgs = soup.find_all('img', src=re.compile('^https://img.finalfantasyxiv.com/xxx/x/.*\.jpg'), width="300")
imgs

f:id:konchangakita:20200719205259p:plain

画像のダウンロード

対象のURLをゲットできたので、後は Python の機能でダウンロードしてローカルに保存です

for img in imgs:
        print(img['src'])
        file_name = img['src'].split('/')[6] #img srcのURLからfile名を取得
        r = requests.get(img['src'])
        with open(str('./picture/')+str(file_name),'wb') as file:
                file.write(r.content)

f:id:konchangakita:20200719181934p:plain


全体像はこちら


あとは、この後ファイル名を使って Elasticsearch に入れるなりすれば、Webアプリ化の充実に近づくことができそう
(画像自動収集にはWebサイトの負荷にならないように重々考慮しましょう)

Copyright (C) SQUARE ENIX CO., LTD. All Rights Reserved.