fc2ブログ

タグクラウドを設置する

 ブログでよく見かける「タグクラウド」を設置しました。TagCloud_181125.png ブログをアップするごとに、一応「カテゴリ分け」をしていましたが、「ユーザタグ」を付けていないことに気付きました。結局、タグクラウドを設置するには、過去分のブログのユーザタグを新規に付け直す必要がありました・・(これが、結構大変でした・・)。
 記事ごとにユーザタグを入力して、ブログ再登録を繰り返しました。TagSetting_181125.png幸いなことに入力しなくても、過去の入力ワードがボタンになっており、ボタンを押すだけで楽に入力できました。タグクラウドは、以前のブログでお話した、AIの「ワードクラウド」のように自動でブログ内のワードを探してくれるのかと個人的に思い込んでいたので、拍子抜けしましたが、地道にワードを入力していきました。

 ユーザタグを入力し終えた後に、「プラグインの設定」を選択し、TagCloudSetting1_181125.pngFC2ブログ上の「共有プラグイン追加」から「タグクラウド」を選択し、利用させていただきました(作者の方、ありがとうございました)。TagCloudSetting2_181125.pngブログ上のタグクラウドの配置位置を決めて、TagCloudSetting3_181125.png詳細を押すと、HTMLの編集もでき、個人カスタマイズができます。うまく使いこなせていないですが、なかなか便利です。TagCloudSetting4_181125.png ブログの記事は時系列に過去から順に積み上がっていきますが、記事内容(テーマ)は時系列と関係なく、順番が分かりにくいですね。このワードタグのようにキーワードで記事を検索できると大変便利ですね。今後も続けていこうと思います。
スポンサーサイト



ブログアクセスログをスクレイピングする(2)

 前回の続きです。今回は前回自動で収集したデータを集計します。不慣れなPandasを使って試行錯誤しながら進めました。

 収集したデータは11/1〜11/15の15日分ありますが、日毎に「項目行」が入っており、邪魔なのでLibreOffice Calcで事前に削除しておきます。preproc_181122.png集計のコードは以下の通りです。Pandasは独特な世界ですね。Rの方が使い慣れているせいか、ぎこちないコードになっているかも・・。
import pandas as pd
import numpy as np

# file load
df = pd.read_csv('result.csv', sep=',')

# information pickup
host_data = []
pref_data = []
access_count = []

for i in range(0, len(df.index)):
str_temp = df.iloc[i,0]
#print(str_temp)
start_position = int((str_temp).find('(')) + 1
end_position = int((str_temp).find(')')) + 1
host_data.append(str_temp[start_position:end_position-1])
#print(x_str[i])
pref_data.append(df.iloc[i,1])
access_count.append(df.iloc[i,2])

res_data = np.vstack([host_data, pref_data, access_count])
df1 = pd.DataFrame(data=res_data).T
df1.to_csv('access_list1.csv', header=False, index=False)

# Calculation1
host_sum = df1[0].value_counts()
count_total = sum(host_sum)

access_count_res = []
access_count_res_percentage = []
for i in range(0, len(host_sum)):
data_temp = df1[df1[0]==host_sum.index[i]]
count_temp = 0
for j in range(0, len(data_temp)):
count_temp = count_temp + int(data_temp.iloc[j,2])
access_count_res.append(count_temp)
access_count_res_percentage.append(round(count_temp/count_total*100,2))

res_data = np.vstack([host_sum.index, access_count_res, access_count_res_percentage])
df2 = pd.DataFrame(data=res_data).T
df2.to_csv('access_list2.csv', header=False, index=False)

# Calculation2
host_pref = df1[1].value_counts()
count_host_pref_total = sum(host_pref)
res_data1 = np.vstack([host_pref.index, host_pref, round(host_pref/count_host_pref_total*100, 2)]).T
df3 = pd.DataFrame(data=res_data1)
df3.to_csv('access_list3.csv', header=False, index=False)
 5行目でDataFrameとして読み込んだresult.csvは4つの項目列(ニックネーム/ホスト名,都道府県,アクセス数,グラフ)があります。第1項目のデータは文字が途中で切れているものもあり(画像上では隠しています)、不完全であることが分かりました。こんな感じです。res_181122.pngただ、()内のデータはまともなので、そのデータを抽出することにしました。8〜24行目でホスト名、都道府県、アクセス数に整理し直しました。24行目のaccess_list1.csvの中身は以下の通り。第1項目が()内のデータに置き換えられました。list1_181122.png 次に、ホスト名ごとに集計を行います。27行目以降の# Calculation1です。もっとスマートにコードがかけるのかもしれませんが、現在修行中・・。結果(access_list2.csv)は以下の通り。list2_181122.png第2項目はアクセス件数、第3項目は全アクセス件数に対する割合[%]です。アクセス解析と言いながら不明が6割弱あります・・・。主要プロバイダ(個人)や大手企業の名前が確認できます。以前、アクセス解析をしていた時と全く変化がない結果でした・・。ブログに書いているネタが変わっていないので、当然といえば当然かもしれません・・。
 45行目以降の# Calculation2は、都道府県の集計結果です。list3_181122.pngこれも不明が7割ありますが、大都市圏からのアクセスが多いことが分かりました。ありがとうございました。

 以前は、時間をかけてWebページからデータを一つ一つ保存して行っていたデータ収集と集計が「スクレイピング」を使うことで、非常に短時間で行えることができました。また、別案件でチャレンジしてみたいと思います。

ブログアクセスログをスクレイピングする(1)

 以前のブログで「ブログアクセス解析」の話をしましたが、アクセスいただいた方々のホスト、都道府県、アクセス数を日毎に集計するのは大変でした。アクセス解析のページを切り替えつつ、データを日毎にcsvファイルに保存し、LibreOffice Calc(ubuntuを利用)で集計していました。データの一括export機能があればよいのですが・・。そこで今回は「ウェブスクレイピング」を使ってデータを自動で保存してみました。

 FC2ブログの管理ページへのアクセス方法は、前回のブログで詳しくお話した通りです。コードは以下の通りです。
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from bs4 import BeautifulSoup
import time
import csv

options = Options()
options.set_headless()
driver = webdriver.Firefox(options=options)

username = "Your username"
password = "Your Password"

# Login Page
driver.get('https://fc2.com/ja/login.php?ref=blog')
login_username = driver.find_element_by_id("id")
login_username.clear()
login_username.send_keys(username)

login_password = driver.find_element_by_id("pass")
login_password.clear()
login_password.send_keys(password)
login_password.submit()

time.sleep(3)
driver.save_screenshot("ss1.png")

# Ranking Page
driver.get('https://id.fc2.com/?mode=login&done=analyzer')
time.sleep(3)
driver.save_screenshot("ss2.png")

monthdata = 11 # November
for daydata in range(1, 16): # 11/1 - 11/15
url='https://analysis.fc2.com/index.php?lim=500&mode=admin&func=host_ranking&year=2018&month=' + str(monthdata) + '&date=' +str(daydata) + '&hrg=0'
driver.get(url)
time.sleep(2)
driver.save_screenshot((str(monthdata) + "_" + str(daydata) + ".png"))
time.sleep(2)
html = driver.page_source

# BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')

tables = soup.find_all("table")
print(str(len(tables)))
#print(str(tables[3]))
rows = tables[3].findAll("tr")
#print(len(rows))

# CSV file output
csvFile = open("result.csv", 'a', newline = '', encoding = 'utf-8')
writer = csv.writer(csvFile)
try:
for row in rows:
csvRow = []
for cell in row.findAll(['td', 'th']):
str_temp = ''.join((cell.get_text()).split())
csvRow.append(str_temp)
writer.writerow(csvRow)
finally:
csvFile.close()

driver.quit()
26行目までは前回と同じ流れで、それ以降が今回追加したコードです。26行目のss1.pngはログインして入った「管理ページ」で、Page1_181122.png31行目のss2.pngは「アクセス解析ページ」です。Page2_181122.png34行目以降のFor文で11/1〜11/15のページに順番にアクセスします。38行目のスクリーンショットは指定した日の「ホストの追跡ページ」です。Page3_181122.png43行目からBeautifulSoupでページ解析を行います。table要素で目的のアクセスリストを入手できました。52行目以降はcsvファイル出力の処理です。ファイルの中身は以下の通りで、「ホストの追跡ページ」の同じデータが自動で収集できました。res_181122.png 次回は採取したデータの集計についてお話します。

ブログのランキングをスクレイピングする(2)

 前回の続きです。今回はRaspberry Piで毎日自動でブログランキングを取得する試みです。うまく行かないことがいろいろありましたので、その備忘録です。
 使用したRaspberry Piは数年前に購入したRaspberry Pi2 Model Bです。今は自宅で常時電源ONにして、ファイルサーバに利用しています。遊ばせておくのももったいないので、スクレイピングでしっかり仕事をしてもらうことにしましょう。

 まず、Firefox、Selenium、Beautifulsoupをインストールします。
sudo apt-get -y install firefox-esr
pip3 install selenium
pip3 install beautifulsoup4
 インストール後に、前回作成したプログラムを実行させましたが、うまく動きません。試行錯誤しているなかで、FirefoxではなくChromiumならうまく行くとの記事を見つけたので、プログラムをChromium版に修正しました。同時に、chromedriverもインストールしたのですが、古いネット記事を参考にしたため、またもや動かずに大変難儀しました。結局、最新版のchromium-browserをインストールすることで問題が解決しました。
sudo apt-get install chromium-browser

 最終的に動作したプログラムは以下の通りです。
import sys
sys.path.append('/home/pi/.local/lib/python3.5/site-packages/')
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
import csv

options = Options()
options = webdriver.ChromeOptions()
options.add_argument("--headless")
#options.add_argument("--no-sandbox")
driver = webdriver.Chrome(executable_path='/usr/lib/chromium-browser/chromedriver', chrome_options=options)

username = "Your username"
password = "Your password"

# Login Page
driver.get('https://fc2.com/ja/login.php?ref=blog')

login_username = driver.find_element_by_id("id")
login_username.clear()
login_username.send_keys(username)

login_password = driver.find_element_by_id("pass")
login_password.clear()
login_password.send_keys(password)
login_password.submit()

time.sleep(5)

# Ranking Page
driver.get('https://admin.blog.fc2.com/control.php?mode=ranking&sidemenu')
time.sleep(3)

html = driver.page_source
driver.quit()

# BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')

exdate = soup.find('div',{'class': 'rank_day'}) #date
exdate_out_position = int((exdate.string).find(':')) + 1
exdate_out = (exdate.string)[exdate_out_position:(exdate_out_position+10)]

exword = soup.find_all('td',attrs={'class': 'rank_number_td'})

exword_out = [[0 for i in range(2)] for j in range(2)]
for i in range(0, len(exword)):
exword_rn = exword[i].find('span',{'class': 'rank_number'}).extract()
exword_rp = exword[i].find('span',{'class': 'rank_people'}).extract()
exword_out[i][0] = str(exword_rn.get_text())
exword_out[i][1] = str(exword_rp.get_text())

with open('/home/pi/blog_ranking_data.csv', 'a') as f:
f.write(exdate_out + ',' + exword_out[0][0] + ',' + exword_out[0][1]+ ',' + exword_out[1][0]+ ',' + exword_out[1][1] + '\n')
前回から変更した箇所は、以下の通りです。
 ① 1〜13行目:Chromium版に変更(実行パスを明記しました)
 ② 42〜44行目:ランキングの更新日時取得の追加
 ③ 55〜56行目:csvファイル出力部の追加
12行目は、chromium-browserを最新版にする前に発生していた不具合に対応したものです。ブラウザが立ち上がるたびに、「--no-sandbox」で立ち上げ直せとのエラーが出て、起動オプションに入れました。結局、ブラウザを最新版にすることでこの行は不要になりましたが、何だったのでしょうか?

結果ファイルは、以下の通りです。
2018/11/10,206,(昨日:181位) / 14347人中,30,(昨日:27位) / 2577人中
2018/11/11,260,(昨日:206位) / 14781人中,30,(昨日:30位) / 2659人中

 次に、プログラムを毎日定刻に実行する設定を行います。crontabコマンドを使うと実現できそうだったので、早速使ってみました。以下のコマンドを実行すると、エディタが立ち上がりますので、処理したい時刻と処理を記載しました。
crontab -e
crontab_setting181111.png記載した内容を確認したい時は、「ーl」オプションで行うことができます。
crontab -l
また、そもそもcronがシステムで稼働していることは次のコマンドで確認できます。
sudo chkconfig cron
crontab_check181111.png
これで、毎日データを収集し、csvファイルに保存する準備ができました。しばらく動かして、様子を見ていこうと思います。自動スクレイピング、いろいろ何かと使えそうな技術ですね。別件で遊んでみようと思います。

ブログのランキングをスクレイピングする(1)

 以前からスクレイピング(ウェブスクレイピング)に興味がありました。データを効率良く収集し、何か面白い、役に立つデータの解析ができないかと模索しています。題材を探している中で、取り急ぎ、自分の「FC2ブログの閲覧件数」データを取ってみようと思いました。ログインした管理ページからよく確認します・・。

 開発環境は、OSはUbuntu、ブラウザはFirefoxで、プログラムはPythonで組みました。定番のSelenium、Beautifulsoupを利用しました。コードは以下の通りです。動作確認のために、意図して要所要所に画像や文字出力させています。
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from bs4 import BeautifulSoup
import time

options = Options()
options.set_headless()
driver = webdriver.Firefox(options=options)

username = "Your username"
password = "Your password"

# Login Page
driver.get('https://fc2.com/ja/login.php?ref=blog')

login_username = driver.find_element_by_id("id")
login_username.clear()
login_username.send_keys(username)

login_password = driver.find_element_by_id("pass")
login_password.clear()
login_password.send_keys(password)
login_password.submit()

time.sleep(5)
driver.save_screenshot("ss1.png")

# Ranking Page
driver.get('https://admin.blog.fc2.com/control.php?mode=ranking&sidemenu')
time.sleep(3)
driver.save_screenshot("ss2.png")

html = driver.page_source
driver.quit()

# BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')

# File save
f = open('html_source.html', mode='x')
f.write(str(soup))
f.close()

exword = soup.find_all('td',attrs={'class': 'rank_number_td'})
print(" extraction number : "+ str(len(exword)))

for i in range(0, len(exword)):
print("Extraction word : " + str(exword[i]))

exword_rn = exword[i].find('span',{'class': 'rank_number'}).extract()
exword_rp = exword[i].find('span',{'class': 'rank_people'}).extract()
print("exword_rn :" + str(exword_rn))
print("exword_rp :" + str(exword_rp))
print(exword_rn.get_text())
print(exword_rp.get_text())
 前半の34行目までは、Seleniumを用いて、ログイン名、パスワードを入れて管理ページに入る所です。10、11行目に自分のログイン名、パスワードを入れます。14行目はアクセスするログイン画面のURLです。手動でこのURLにアクセスした時の画面は以下の通りです。LoginPage_181103.png 次に、このページにログイン名(メールアドレス/ブログID)とパスワードを入力しますが、それぞれのInput要素(テキストボックス)の名前は、直接ソースコードで探すのもありですが、以下の「開発ツール」で簡便に調べられます。ObjectSearch1_181103.pngFirefoxの場合、目的のオブジェクト(テキストボックス)を選択し、「右クリック - 要素を調査」を実行すると、開発ツールが立ち上がります。ObjectSearch2_181103.png パスワードはこの方法でうまく行かなかったので、結局ページのソースコードから調べました。ページ上のオブジェクトのない所で、「右クリック - ページのソースを表示」を実行すると「ソースコード」が表示されます。ObjectSearch3_181103.png その中から、パスワードのテキストボックスの名前を探します。"pass"であることが分かりました。
<li>メールアドレス/ブログID:</li>
<li><input name="id" type="text" id="id" value="" class="input_fc2id_login" /></li>
<li>パスワード:</li>
<li><input name="pass" type="password" id="pass" class="input_fc2id_login" /></li>
 プログラムの16、20行目の”id”と”pass”はこれに対応しています。必要事項を入力後は、23行目で実行。実行後はタイマー待ちを入れておき、ページの画像保存も行いました。Page1_1801103.png問題なく、自動でログイン成功したようです。次に、赤枠で囲んだ「ランキング」にアクセスします。事前に目的のページに手動でアクセスし、URLを把握しておきます。これも問題なく表示されました(プログラムのss2.png)。Page2_1801103.png この画像の表中の数字を抽出します。40〜42行目で保存したソースコードを解読し、以下の部分が該当していることが分かりました。
<tr>
<td><a href="/control.php?mode=ranking&process=genre">コンピュータ</a></td>
<td class="rank_number_td"><span class="rank_number down">197</span>位 <span class="rank_people">(昨日:195位) / 14334人中</span> </td>
</tr>
<tr>
<td><a href="/control.php?mode=ranking&process=subgenre">プログラミング</a></td>
<td class="rank_number_td"><span class="rank_number down">30</span>位 <span class="rank_people">(昨日:28位) / 2538人中</span> </td>
</tr>
td要素で抽出できそうなので、その路線で進め、目的の値を絞り込んでいきました。

プログラム実行結果は以下の通りです。
<td> extraction number : 2
Extraction word : <td class="rank_number_td">
<span class="rank_number down">197</span>位 <span class="rank_people">(昨日:195位) / 14334人中</span> </td>
exword_rn :<span class="rank_number down">197</span>
exword_rp :<span class="rank_people">(昨日:195位) / 14334人中</span>
197
(昨日:195位) / 14334人中
Extraction word : <td class="rank_number_td">
<span class="rank_number down">30</span>位 <span class="rank_people">(昨日:28位) / 2538人中</span> </td>
exword_rn :<span class="rank_number down">30</span>
exword_rp :<span class="rank_people">(昨日:28位) / 2538人中</span>
30
(昨日:28位) / 2538人中
 途中経過の文字出力があり、鬱陶しいですが、最終結果は、6、7、12、13行目です。うまく抽出できました。

 スクレイピングは今回初めてでしたが、何かと応用ができそうな技術ですね。別の案件で試してみようと思いました。

ご訪問者数

(Since 24 July, 2016)

タグクラウド


プロフィール

Dr.BobT

Author: Dr.BobT
興味のおもむくままに生涯考え続けるエンジニアでありたい。

月別アーカイブ

メールフォーム

名前:
メール:
件名:
本文: