プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

pythonではてなブログのエントリー一覧を取得する

ラズパイによるbotとしてはてなブログのエントリーをTweetする機能を作っています。

これまでは、Tweetの定型文を手動で入力していましたが、自分のはてなブログのエントリー一覧から自動生成することを考えました。
はてなブログのエントリー一覧は↓のようなURLから取得できそうです。

http://s51517765.hatenadiary.jp/archive?page=2

s51517765.hatenadiary.jp
f:id:s51517765:20180105213336j:plain

エントリー一覧のURLは末尾の数字を順番に増やして取得できると推測できます。
以前に、C#で作成したスクレイピングツールもあり、こちらでも機能を拡張すれば可能です。
s51517765.hatenadiary.jp

pythonではbeautifulsoupというモジュールが簡単ということなので、試してみました。
↓を参考にしました。

beautifulsoupはurlを指定してhtmlを取得し、その中から指定したタグを抽出するということが容易にできるそうです。
そこで、以下のようにプログラミングします。
①Urlを指定しhtmlを取得
②エントリーのタグを抽出し、この中から、エントリーのタイトルとurlを取得
③次のページに移動
④エントリーがなくなったら終了

”a”のタグはLinkを示していて、htmlの中から"a"を取得します。
この取得した一覧はlist形式になっています。

    html = requests.get(url)
    soup = BeautifulSoup(html.text, 'lxml') ##lxmlを指定するほうがよい
    alink = soup.select('a') #linkの一覧をListとして取得

f:id:s51517765:20180104115111j:plain

この中から、classが "entry-title-link" であるものを抽出します。
htmlを知っていればわかると思いますが、classはhtmlの記法の一つで、ここで言えば ”entry-title-link” のクラスを指定していて、別途設定したスタイルを適用するようになっています。

if 'entry-title-link' in alink[i].get('class'):

リンク要素から、リンクのテキストとurlを取得します。

print('【プログラミング素人のはてなブログ】' +alink[i].getText()+' '+alink[i].get('href'))

リンクurlを予め宣言しておいた、list=[]に見つからなければ追加しながらprint()します。このようにして重複を防止します。
これを、ページを遷移しながら繰り返し、エントリーがなくなるまで続けます。
ここではページを遷移しても、新しいurlがでてこなくなれば手動でプログラムを停止します。

自動化するには「新しいページに新しいurlがない」とか「『記事はありません』という文言を見つけたら終わり」といった方法が考えられますが、これをコーディングするコストがメリットを超えるので手動停止という方法をとりました。
これが、実行に数十分かかるとなるとPCの前を離れられないなどのコストがかかり、コーディングするべきとなりますが、ここでは数秒なので、目視で止めることで十分なのです。

def soup_taikutsu(url):
    html = requests.get(url)
    soup = BeautifulSoup(html.text, 'lxml') ##lxmlを指定するほうがよい

    alink = soup.select('a') #linkの一覧をListとして取得

    #print(len(alink)) #Listの長さ
    for i in range(len(alink)):
        if alink[i].get("class")!=None: #クラスが未設定でない
            if 'entry-title-link' in alink[i].get('class'): #エントリーのclassとして指定されているものの時
                if alink[i].get("href") not in list: #すでに抽出済みでなければ
                    list.append(alink[i].get("href"))
                    print('【プログラミング素人のはてなブログ】' +alink[i].getText()+' '+alink[i].get('href'))

if __name__ == '__main__':
    list=[]
    rootUrl='http://s51517765.hatenadiary.jp/archive?page=' #エントリー一覧の基本url
    n=1
    while(True):
        url=rootUrl+str(n)
        soup_taikutsu(url)
        n+=1

このほかにfind_allという関数を使う方法もできました。

alink = soup.find_all('a')

取得できる結果は同じです。
こちらではListではなく "for ~ in ~"でアクセスします。
またlink urlに"s51517765.hatenadiary.jp/entry/"が見つかるかどうかで判断しました。

import requests, os, bs4

from bs4 import BeautifulSoup
print("start!")

def soup(url):
    html = requests.get(url)
    soup = BeautifulSoup(html.text, 'lxml')

    alink = soup.find_all('a')

    for a in alink:
        
            if a.string!=None and a.get("href")!=None:
                if a.get("href").find("s51517765.hatenadiary.jp/entry/")!=-1: #自分のブログの外は除外
                    #print(a.string) #Linkのテキスト
                    #print(a.get("href")) #Linkのurl
                    if a.get("href") not in list: #urlがリストに無ければ
                        list.append(a.get("href"))
                        print("【プログラミング素人のはてなブログ】" + a.string + " " + a.get("href"))

# mainは同様

f:id:s51517765:20180104121909j:plain