データベースを使ったサイトを作りたい⑥ Python+BeautifulSoupで最新データをスクレイピング

スポンサーリンク
スポンサーリンク

スクレイピング

元々はVBA+IEでスクレイピングをしてデータを収集してデータベースを作った。でもそれを毎回やるのはめんどいので自動化できると良い。サーバー上でスクレイピングするやり方って何があるんだろうと探してみたらPythonのライブラリでBeautifulSoupというものを見つけた。これで定期的に更新されてるか見に行きつつスクレイピングして必要なデータを抽出して、なおかつデータベースを更新できればいいな。とりあえずスクレイピングしよー。

スポンサーリンク

Beautiful Soupでスクレイピング

Beautiful Soup Documentation — Beautiful Soup 4.12.0 documentation

公式ドキュメント。今は4.9.0が最新?

kondou.com - Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新)

こっちは日本語訳。これは4.2.0が基みたい。まぁやってこー。

インストール

CentOSなので

$ pip install beautifulsoup4
Collecting beautifulsoup4
Downloading beautifulsoup4-4.9.1-py3-none-any.whl (115 kB)
|????????????????????????????????| 115 kB 17.9 MB/s
Collecting soupsieve>1.2
Downloading soupsieve-2.0.1-py3-none-any.whl (32 kB)
Installing collected packages: soupsieve, beautifulsoup4
Successfully installed beautifulsoup4-4.9.1 soupsieve-2.0.1

された。

HTMLパーサーのインストール

HTMLを解析してくれるやつ。Pythonで標準に入ってるらしいやつとなんか色々。そのうちlxmlのHTMLパーサーを使おうと思う。速いらしいよ。

$ pip install lxml
Collecting lxml
  Downloading lxml-4.5.2-cp38-cp38-manylinux1_x86_64.whl (5.4 MB)
     |????????????????????????????????| 5.4 MB 10.6 MB/s
Installing collected packages: lxml
Successfully installed lxml-4.5.2

Requestsのインストール

Requests: HTTP for Humans™ — Requests 2.31.0 documentation

HTMLをそのまま取得する時に使うやつみたい。Pythonの標準にもUrllibというライブラリが入ってるらしいけど、こっちのほうが使いやすいらしい。らしいばっかだ。ただ自分の目的だと外部公開されてる固定ページに行って取得するだけだし別にそこまでするようなものでもないかもしんない。まぁ一応入れとく!

$ pip install requests
Collecting requests
  Downloading requests-2.24.0-py2.py3-none-any.whl (61 kB)
     |????????????????????????????????| 61 kB 727 kB/s
Collecting chardet<4,>=3.0.2
  Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)
     |????????????????????????????????| 133 kB 22.3 MB/s
Collecting certifi>=2017.4.17
  Downloading certifi-2020.6.20-py2.py3-none-any.whl (156 kB)
     |????????????????????????????????| 156 kB 30.5 MB/s
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1
  Downloading urllib3-1.25.10-py2.py3-none-any.whl (127 kB)
     |????????????????????????????????| 127 kB 17.0 MB/s
Collecting idna<3,>=2.5
  Downloading idna-2.10-py2.py3-none-any.whl (58 kB)
     |????????????????????????????????| 58 kB 6.0 MB/s
Installing collected packages: chardet, certifi, urllib3, idna, requests
Successfully installed certifi-2020.6.20 chardet-3.0.4 idna-2.10 requests-2.24.0 urllib3-1.25.10

できた。

使ってみる

まずちゃんと取得できるか試す。コード書いた。

import requests
from bs4 import BeautifulSoup

url = 'https://www.shogi.or.jp/tsume_shogi/everyday/'
res = requests.get(url)

soup = BeautifulSoup(res.text, 'lxml')
print(soup.title)

結果

python3 scrape.py
<title>a??a??a?≪a?!ec°a°?a£?i??ec°a°?a£?a?≫a¬!a?Ra,€a??i??a?\a?¬a°?a£?e€£c??</title>

おっとー、また文字化けかい…。んーと

print('こんにちわ')

$ python3 hello.py
こんにちわ

表示される。

import requests

url = 'https://www.shogi.or.jp/tsume_shogi/everyday/'
res = requests.get(url)

print(res.text)

こうして、結果

<title>a??a??a?≪a?!ec°a°?a£?i??ec°a°?a£?a?≫a¬!a?Ra,€a??i??a?\a?¬a°?a£?e€£c??</title>

あーこの時点でもう化けてる。”Requests 文字化け”とかで検索

https://qiita.com/nittyan/items/d3f49a7699296a58605b

とか。自分でも試してみる。

print(res.encoding)

に変えて

$ python3 scrape.py
ISO-8859-1

おー。qiitaだとapparent_encodingを使ってるけどすでにサイト側の文字コードがutf-8だと分かってるので

import requests
from bs4 import BeautifulSoup

url = 'https://www.shogi.or.jp/tsume_shogi/everyday/'
res = requests.get(url)
res.encoding = 'utf-8'

soup = BeautifulSoup(res.text, 'lxml')
print(soup.title)

簡易に文字コードを強制的に指定してあげる。結果

$ python3 scrape.py
<title>まいにち詰将棋|詰将棋・次の一手|日本将棋連盟</title>

取得できた!そしたら最新出題日のデータを取得してみる。

最新を取得

CSSセレクタで指定するのはいまいちよく分かってないのでfindとfind_all使ってやってく。ソース見ると、id=”contents“の中のli要素1個目で、aとpの要素を取得できれば良さげ。その後p要素のテキストを加工すればデータ作れそう。で、こんな感じになった。

import requests
from bs4 import BeautifulSoup

target_url = 'https://www.shogi.or.jp/tsume_shogi/everyday/'
res = requests.get(target_url)
res.encoding = 'utf-8'

soup = BeautifulSoup(res.text, 'lxml')

contents = soup.find(id="contents")
url = contents.find('a').get('href')

print(url)

title = contents.find('p').text

print(title)

q_date = title[0:title.find('日')].replace('年','-').replace('月','-')

print(q_date)

maker = ''
steps = 0
if '、' in title:
  maker = title[title.find('(')+1:title.find('、')-1]
  steps = title[title.find('、')+1:title.find('手詰')]
else:
  steps = title[title.find('(')+1:title.find('手詰')]

print(maker)
print(steps)

結果

$ python3 scrape.py
2020年9月5日の詰将棋(服部慎一郎作、9手詰)|詰将棋・次の一手|日本将棋連盟
日本将棋連盟の2020年9月5日の詰将棋(服部慎一郎作、9手詰)のページです。日本将棋連盟は伝統文化としての将棋の普及発展と技術向上や将棋を通じた交流親善などを目的とした公益社団法人です。
2020年9月5日の詰将棋(服部慎一郎作、9手詰) 2020-9-5 服部慎一郎 9

とりあえず9/5分しかチェックしてないけど大丈夫かな~。BFのfindの引数の書き方がよく分かんなかったので何回もfindした。liはいらんかったね。データの切り出しも正規表現とか使えるともっといい感じに書けるんだろうなぁ…。まだまだですね。まぁ目的のデータはゲットできそうなので、次はこれをDBに更新していく処理を書こう!

コメント

タイトルとURLをコピーしました