Contents
はじめに
Google Cloud Platform(以下、GCP)を利用して、
この1年間で13個のサービスを作りたいと思っています。
まずは、簡単なモノから作りたいなと考えまして、
IT記事のQiitaのランキング情報(1位)を毎日つぶやくボットを作成しました。
その中で苦労したこととボットの作り方を紹介したいと思います。
前半はスクレイピングに絞って説明します。
後半はtwitter botのコードとどうやって自動で稼働させるかを紹介します。
稼働環境はLinuxのCentOS8です。
スクレイピング Beautiful Soupを利用(失敗)
今回はGoogle Cloud Platform(以下、GCP)を用いて、
自動でランキング内容を呟くボットをを作りたいと思いました。
よって、環境はLinux(CentOS8)にしようと考えて、
まずはQiitaの記事をスクレイピングして、ランキング1位の記事のURLの取得を試みました。
DockerでCentOS8のイメージを持ってきて、
スクレイピングに必要な以下のものをインストールします。
- python3・・・プログラミング言語
- Beautiful Soup・・・スクレイピングのライブラリ
- Google-chrome・・・スクレイピングのブラウザ
- Crome-driver・・・ブラウザドライバー
しかーし、ブラウザのインストールがLinuxベースのCentOS上でどうしてもできないのです。。
以下がCentOS8上で行ったコマンドとエラー内容。
まずは、リポジトリファイルを編集します。
vi /etc/yum.repos.d/google.chrome.repo
内容は理解しなくても良いので、以下をコピー。
[google-chrome] name=google-chrome baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch enabled=1 gpgcheck=1 gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
google-chromeをインストール
dnf install google-chrome-stable
すると、以下のようなエラーが出ます。
Failed to set locale, defaulting to C.UTF-8 google-chrome 2.8 kB/s | 1.4 kB 00:00 Errors during downloading metadata for repository 'google-chrome': - Status code: 404 for http://dl.google.com/linux/chrome/rpm/stable/aarch64/repodata/repomd.xml (IP: 172.217.25.78) Error: Failed to download metadata for repo 'google-chrome': Cannot download repomd.xml: Cannot download repodata/repomd.xml: All mirrors were tried
このエラーのおかげで、Chromeがインストールできず、
pythonやGoでスクレイピングすることを諦めました。。
スクレイピング Qiita-APIを利用(失敗)
スクレイピングをしたいのに、Chromeが利用できないのは想定外で、
どのようにしてQiitaのランキング情報を取得しようか考えました。
そういえば、APIがあるんじゃない?と思いまして、
QiitaのAPIからランキング情報を取得する方法を調べてみることにしました。
ビンゴ!QiitaのAPIはちゃんとありました。
・公式サイト:Qiita API v2
しかーし、公式ドキュメントをみても、ランキング情報はAPIで提供していませんでした。
上手くいかない。。
スクレイピング wgetコマンドの利用(成功)
ここでマクドナルドに行って、別案を考えることに。
そもそもpythonでスクレイピングできるなら、Linuxコマンドでもスクレイピングできるのでは?
と思い、「Linux コマンド スクレイピング」でググるとヒントが。
wgetコマンドを利用することで、対象サイトのHTML全文を取得できることがわかりました。
よって、以下の方針でスクレイピングを実施し、
Qiita記事のランキング1位の情報を取得することを実現しました。
- wgetコマンドでQiitaサイトのHTMLを全て取得する。
- HTML全文から、ランキング情報をURLを全て取得する。
- ランキング1位のURLを取り出し、ツイートする内容を作成する。
- twitterのAPIを利用して、作成したつぶやきをツイートする。
- 上記のコードをGCP上でデプロイして、自動運用する。
コード全文は後半の記事に譲りまして、この前半の記事では私が学んだことを中心に説明します。
wgetコマンドでHTMLの全文を取得する。
wgetコマンドは仕事で利用したことがなかったので、知りませんでした。
軽く検索してみて、仕様を確認。(参考サイト)
Qiitaの記事のHTML出力したかったので、適当なディレクトリ上で、下記のコマンドを実行。
#QiitaのサイトのHTMLO内容をindex.htmlへ出力。 wget https://qiita.com/ index.html
150KBのそこそこ大きいファイルが完成します。
このファイルをpythonのreライブラリを用いて、必要なURLを取得するコードを作成していきます。
re.findallコマンドで文字列を抽出する
次に、前節で取得したHTMLファイルを読み込んで、対象のURLを取り出したい。
まずはwgetしたindex.htmlファイルを読み込み、その内容を出力してみます。
with open('./index.html') as f: html = str(f.read()) print(html) #index.htmlファイルの内容を全て表示する。(かなりの出力内容が出ます。)
Qiitaのサイトに行くと、Chromeのツールでランキング1位のHTML部分を取得します。
対象のURLをコピーしたものは下記です。
<a href="https://qiita.com/e99h2121/items/419c3bd39d8dea40f21a" class="css-qrra2n">海外「なぜ日本はハードウェアの時代と同じようにソフトウェアに秀でることができない?」</a>
これを見てみると、『<a href=”…”』の中にURLがあるので、
ここを取得すれば良いことがわかります。
import re with open('./index.html') as f: html = str(f.read()) string_html = re.findall('<a href=\"https:\/\/qiita\.com\/.*\"',html) print(string_html)
しかーし、これを実施すると、対象のURL以外にも大きな範囲の文字列を取得してしまいます。
対象のURLで、なるべく文字列が短く取得するためには、
下記のように非貪欲マッチを利用する必要がある。
貪欲マッチと非貪欲マッチを利用する。
- 貪欲マッチ・・・「*」「+」「?」を利用して、できるだけ長いテキストを抽出する。
- 非貪欲マッチ・・・「*?」「+?」「??」を利用して、できるだけ長いテキストを抽出する。
今回は1行が非常に長いHTMLとなり、マッチ条件が複数あるため、非貪欲マッチを利用して、
対象のURLを取得する。(ここに時間がかかった)
import re with open('./index.html') as f: html = str(f.read()) string_html = re.findall('<a href=\"https:\/\/qiita\.com\/.+?\"',html) print(string_html)
これを実行すると、下記がprintされる。
['<a href="https://qiita.com/e99h2121/items/419c3bd39d8dea40f21a"', '<a href="https://qiita.com/rpf-nob/items/6823fb8728754386ef30"', '<a href="https://qiita.com/kuromitsu0104/items/dc0021a20100e11f2f7d"', '<a href="https://qiita.com/shogo-1988/items/a96eb63a9b108696d966"', '<a href="https://qiita.com/KazukiSadasue/items/cf0d1d5b711a78bcd051"', '<a href="https://qiita.com/bow_arrow/items/a88cf7a444fb6045b8e4"', '<a href="https://qiita.com/sparklingbaby/items/3f1e07f78573b5c3b66b"', '<a href="https://qiita.com/koyaaarr/items/259ad4f0d574497c5b08"', '<a href="https://qiita.com/Rahariku/items/69b512fad60242fbd6ac"', '<a href="https://qiita.com/eijiSaito/items/70aad4d59cc5427981e1"', '<a href="https://qiita.com/nodai2h_ITC/items/6242046d789b0bf1b4de"', '<a href="https://qiita.com/shinbunbun_/items/9963e7cf7bd2faca407a"', '<a href="https://qiita.com/kato_dev/items/cee1e110b7d80cca48c0"', '<a href="https://qiita.com/c60evaporator/items/fd019f5ac6eb4d612cd4"', '<a href="https://qiita.com/thruaxle/items/8cb59dbbc5cf5a3a5fb6"', '<a href="https://qiita.com/TokyoYoshida/items/1c62c01093e6a9be442e"', '<a href="https://qiita.com/daikidev111/items/107929c11e250e0eb0e9"', '<a href="https://qiita.com/morita-toyscreation/items/04d9c77dfb596aa2b5a8"', '<a href="https://qiita.com/ngtkana/items/d7fc4463e56b966d1ebf"', '<a href="https://qiita.com/Hassan/items/cb092e7ae944059a1256"', '<a href="https://qiita.com/teriyaki_jumping/items/02f860241b93186219b9"', '<a href="https://qiita.com/gnbrganchan/items/d204cc9f98c4651d3c3e"', '<a href="https://qiita.com/kkk5713/items/52207f8c0c49fd9addda"', '<a href="https://qiita.com/MaShunzhe/items/f3e1b439bb0233be615a"', '<a href="https://qiita.com/ROW/items/7df5e238083b34b3a958"', '<a href="https://qiita.com/nanako_t/items/1486ee2fb307fe7dba80"', '<a href="https://qiita.com/flcn-x/items/393c6f1f1e1e5abec906"', '<a href="https://qiita.com/iriyamanorio/items/891ac6a18a5e1432d791"', '<a href="https://qiita.com/yugoes1021/items/4d5ed9401728472a27ed"', '<a href="https://qiita.com/t-shimizume/items/1759c7134c03415d7aa4"']
このように欲しいランキング情報が取得できていることがわかります。
さらに、これをListに格納することで、欲しいURLをいつでも取得できることができます。
下記はListに格納するプログラムです。
import re with open('./index.html') as f: html = str(f.read()) string_html = re.findall('<a href=\"https:\/\/qiita\.com\/.+?\"',html) url_list = [] for i in string_html: j = i.lstrip('<a href=\"') k = j.rstrip('\"') url_list.append('h'+k) #バグなのかわからないが、一緒にhttpsの"h"が削除されるので、文字列"h"を付け足しています。 print(url_list)
実行結果は下記です。ちゃんとURLが取得できていますね。
['https://qiita.com/e99h2121/items/419c3bd39d8dea40f21a', 'https://qiita.com/rpf-nob/items/6823fb8728754386ef30', 'https://qiita.com/kuromitsu0104/items/dc0021a20100e11f2f7d', 'https://qiita.com/shogo-1988/items/a96eb63a9b108696d966', 'https://qiita.com/KazukiSadasue/items/cf0d1d5b711a78bcd051', 'https://qiita.com/bow_arrow/items/a88cf7a444fb6045b8e4', 'https://qiita.com/sparklingbaby/items/3f1e07f78573b5c3b66b', 'https://qiita.com/koyaaarr/items/259ad4f0d574497c5b08', 'https://qiita.com/Rahariku/items/69b512fad60242fbd6ac', 'https://qiita.com/eijiSaito/items/70aad4d59cc5427981e1', 'https://qiita.com/nodai2h_ITC/items/6242046d789b0bf1b4de', 'https://qiita.com/shinbunbun_/items/9963e7cf7bd2faca407a', 'https://qiita.com/kato_dev/items/cee1e110b7d80cca48c0', 'https://qiita.com/c60evaporator/items/fd019f5ac6eb4d612cd4', 'https://qiita.com/thruaxle/items/8cb59dbbc5cf5a3a5fb6', 'https://qiita.com/TokyoYoshida/items/1c62c01093e6a9be442e', 'https://qiita.com/daikidev111/items/107929c11e250e0eb0e9', 'https://qiita.com/morita-toyscreation/items/04d9c77dfb596aa2b5a8', 'https://qiita.com/ngtkana/items/d7fc4463e56b966d1ebf', 'https://qiita.com/Hassan/items/cb092e7ae944059a1256', 'https://qiita.com/teriyaki_jumping/items/02f860241b93186219b9', 'https://qiita.com/gnbrganchan/items/d204cc9f98c4651d3c3e', 'https://qiita.com/kkk5713/items/52207f8c0c49fd9addda', 'https://qiita.com/MaShunzhe/items/f3e1b439bb0233be615a', 'https://qiita.com/ROW/items/7df5e238083b34b3a958', 'https://qiita.com/nanako_t/items/1486ee2fb307fe7dba80', 'https://qiita.com/flcn-x/items/393c6f1f1e1e5abec906', 'https://qiita.com/iriyamanorio/items/891ac6a18a5e1432d791', 'https://qiita.com/yugoes1021/items/4d5ed9401728472a27ed', 'https://qiita.com/t-shimizume/items/1759c7134c03415d7aa4']
おわりに
長くなりましたが、chromeやAPIを利用せずに、スクレイピングする手法をご紹介しました。
学びも非常に多かったので、ブログに残しましたが、如何でしたでしょうか。
wgetコマンド、普段は使わないと思いますが、
今回のように環境の制約でスクレイピングできない時は役に立つので、
利用したことがない人は是非利用してみて下さい!
以上です、ありがとうございました!!
コメント