DjangoでWebスクレイピングを使った
簡単な天気予報アプリの作り方を紹介します。
現在、スクレイピング先の気象庁のHPの仕様が分かったため、
こちらの天気予報アプリは作れません。現在、修正中です。
こんな方にオススメの記事です。
・DjangoでWebスクレイピングの使い方を知りたい人
・Webスクレイピングした情報をHTMLに橋渡ししたい人
・天気予報アプリの作り方を知りたい人
見た目はこんな感じです。

早速、各コードをみていきます。
Djangoの基本的な設定
settings.py
import os #ここを最初に追加
:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')], #ここを追加
'APP_DIRS': True,
},
]
settings.pyの最初にosモジュールをインポートしましょう。
それと、TEMPLATESのDIRSにtemplatesファイルを追加して、HTMLファイルを利用しましょう。
urls.py
urlpatterns = [
path('', views.main, name='main'),
]
アプリのurls.pyにURL先とviewsを設定して、天気予報を表示できるようにします。
Webスクレイピングはここ views.py
views.pyのコードを紹介します。ちょっと長いです。
ここでは訪問時にURL先をスクレイピング
必要データだけ抽出してHTML上に渡す役割をしています。
from django.shortcuts import render
import requests, re
from bs4 import BeautifulSoup
def main(request):
url = 'https://www.jma.go.jp/jp/yoho/329.html' #気象庁のHP
res = requests.get(url)
res.encoding = res.apparent_encoding
soup = BeautifulSoup(res.text, "html.parser")
weathers = soup.find_all(class_='weather')
date_list = weather_list = []
for i in weathers:
j = str(i).replace('\n','')
date = re.findall('<th class="weather">(.*?)<br/>', str(j))
date_list = date_list + date
weather = re.findall('alt="(.*?)" src', str(j))
weather_list = weather_list + weather
context = {
'seibu_today':date_list[0], 'seibu_tomorrow':date_list[1],
'seibu_today_w':weather_list[0], 'seibu_tomorrow_w':weather_list[1],
}
return render(request, 'main.html', context)
これが全体像です。細かく説明していきます。
def main(request):
url = 'https://www.jma.go.jp/jp/yoho/329.html'
res = requests.get(url)
res.encoding = res.apparent_encoding
soup = BeautifulSoup(res.text, "html.parser")
weathers = soup.find_all(class_='weather')
WebスクレイピングをしたURL先は気象庁の愛知県の天気です。
それを読める形に変えて、class=”weather”の箇所だけ引き抜いています。
class=”weather”は愛知県の天気予報を表示している行で、各行をリスト型weathersに入れます。
また、詳しいWebスクレイピングに関しては、このページを参考にしてください。

date_list = weather_list = []
for i in weathers:
j = str(i).replace('\n','')
date = re.findall('<th class="weather">(.*?)<br/>', str(j))
date_list = date_list + date
weather = re.findall('alt="(.*?)" src', str(j))
weather_list = weather_list + weather
ここでは日付を入れるリスト(date_list)と天気情報を入れるリスト(weather_list)を作ります。
weathersから各行をfor文で取り出し
replaceで一度整型して日付情報をdateとして抜き取り
date_listに追加していきます。
天気情報も同様にweatherとして抜き取りweather_listに追加します。
これでwebスクレイピングで読み取った情報から更に必要な情報のみに抽出しました。
最後は表示したい情報をcontextの中に辞書型として入れて、views.pyは終了です。
天気予報の表示画面 main.html
<head>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
</head>
<body>
<h1>天気予報</h1>
<h3>愛知県西部</h3>
<div>{{ seibu_today }}:{{ seibu_today_w }}
{% if '晴' in seibu_today_w %} 〜晴れなら晴れのマークを表示
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sun" viewBox="0 0 16 16">
<path d="M3.5 8a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0z"/>
<path d="M8.202.28a.25.25 0 0 0-.404 0l-.91 1.255a.25.25 0 0 1-.334.067L5.232.79a.25.25 0 0 0-.374.154l-.36 1.51a.25.25 0 0 1-.282.188l-1.532-.244a.25.25 0 0 0-.286.286l.244 1.532a.25.25 0 0 1-.189.282l-1.509.36a.25.25 0 0 0-.154.374l.812 1.322a.25.25 0 0 1-.067.333l-1.256.91a.25.25 0 0 0 0 .405l1.256.91a.25.25 0 0 1 .067.334L.79 10.768a.25.25 0 0 0 .154.374l1.51.36a.25.25 0 0 1 .188.282l-.244 1.532a.25.25 0 0 0 .286.286l1.532-.244a.25.25 0 0 1 .282.189l.36 1.508a.25.25 0 0 0 .374.155l1.322-.812a.25.25 0 0 1 .333.067l.91 1.256a.25.25 0 0 0 .405 0l.91-1.256a.25.25 0 0 1 .334-.067l1.322.812a.25.25 0 0 0 .374-.155l.36-1.508a.25.25 0 0 1 .282-.19l1.532.245a.25.25 0 0 0 .286-.286l-.244-1.532a.25.25 0 0 1 .189-.282l1.508-.36a.25.25 0 0 0 .155-.374l-.812-1.322a.25.25 0 0 1 .067-.333l1.256-.91a.25.25 0 0 0 0-.405l-1.256-.91a.25.25 0 0 1-.067-.334l.812-1.322a.25.25 0 0 0-.155-.374l-1.508-.36a.25.25 0 0 1-.19-.282l.245-1.532a.25.25 0 0 0-.286-.286l-1.532.244a.25.25 0 0 1-.282-.189l-.36-1.509a.25.25 0 0 0-.374-.154l-1.322.812a.25.25 0 0 1-.333-.067L8.203.28zM8 2.5a5.5 5.5 0 1 1 0 11 5.5 5.5 0 0 1 0-11z"/>
</svg>
{% elif '雨' in seibu_today_w %} 〜雨なら雨マークを表示
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-droplet" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M7.21.8C7.69.295 8 0 8 0c.109.363.234.708.371 1.038.812 1.946 2.073 3.35 3.197 4.6C12.878 7.096 14 8.345 14 10a6 6 0 0 1-12 0C2 6.668 5.58 2.517 7.21.8zm.413 1.021A31.25 31.25 0 0 0 5.794 3.99c-.726.95-1.436 2.008-1.96 3.07C3.304 8.133 3 9.138 3 10a5 5 0 0 0 10 0c0-1.201-.796-2.157-2.181-3.7l-.03-.032C9.75 5.11 8.5 3.72 7.623 1.82z"/>
<path fill-rule="evenodd" d="M4.553 7.776c.82-1.641 1.717-2.753 2.093-3.13l.708.708c-.29.29-1.128 1.311-1.907 2.87l-.894-.448z"/>
</svg>
{% else %} 〜その他の場合、曇りマークを表示
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cloud" viewBox="0 0 16 16">
<path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383zm.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/>
</svg>
{% endif %}
</div>
<div>{{ seibu_tomorrow }}:{{seibu_tomorrow_w}}
{% if '晴' in seibu_tomorrow_w %}
〜同文、略〜
{% elif '雨' in seibu_tomorrow_w %}
〜同文、略〜
{% else %}
〜同文、略〜
{% endif %}
</div>
</body>
BootstrapをベースにHTMLを書いていきます。
メインとなる部分はここです。
<div>{{ seibu_today }}:{{ seibu_today_w }}
{% if '晴' in seibu_today_w %} 〜晴れなら晴れのマークを表示
〜略〜
{% elif '雨' in seibu_today_w %} 〜雨なら雨マークを表示
〜略〜
{% else %} 〜その他の場合、曇りマークを表示
〜略〜
{% endif %}
</div>
Djangoの組み込みでif文を利用しています。
{{ seibu_today }}:{{ seibu_today_w }}でviews.pyの抽出したデータを表示。
{% if ~%}で seibu_today_wの中の情報を判断し、晴れ、雨、その他でマークを変更しています。
これで天気予報アプリが完成します。
参考にした本はこれです。