pythonでRSSフィードを取得し、画像がない場合、リンク先の記事から拾う

[最終更新] 2018年7月4日

pythonでRSSフィードを取得する。具体的にはhoge.rdfとか取得する。で、その中に画像情報が入っていない場合、リンク先の記事のまで飛んで、その中にある画像のURLを取得し、画像つき記事のみ出力してみるサンプル。

環境づくり

python3系。pipで以下を入れておく。

  • feedparser
    • feedのパースに使う
  • lxml
    • htmlのパースに使う
  • cssselect
    • css記法

やること

  1. 任意のサイトのRSSフィードを取得する
  2. feedparserで解析する
  3. 各記事について、リンク先の記事に飛ぶ
  4. コンテンツ内で一番最初に表示される画像のURLを取得する
  5. 画像付きの記事のみ、任意の数出力する

ソースコード

架空のexample.com/index.rdfに対して行うとする。

import feedparser
import lxml.html
from urllib.request import urlopen
from urllib.parse import urljoin
import datetime


class RssParser:
    def __init__(self):
        self._d = feedparser.parse('https://example.com/index.rdf')

    def to_dict(self):
        entries = [self._get_content(entry) for entry in self._d.entries]
        return entries

    def _get_content(self, entry):
        content = {}
        # 各entryの内容はサイトによる
        content['title'] = entry['title']
        content['link']  = entry['link']
        content['description'] = entry['summary']
        content['date']  = datetime.datetime.strptime(entry['updated'], "%Y-%m-%dT%H:%M:%S+09:00").strftime("%Y-%m-%d %H:%M:%S")
        content['img']   = self._get_img(content['link'])
        # print(content)
        return content

    def _get_img(self, link):
        tree = lxml.html.parse(urlopen(link))
        html = tree.getroot()
        # 画像URLの取得
        try:
            # urljoinで相対パス→絶対パス
            img  = urljoin(link, html.cssselect('img.photo_table__img')[0].attrib['src'])
        # 画像がない場合はFalseが入る
        except(IndexError):
            return False
        return img

    def to_s(self):
        [print(entry) for entry in self._d.entries]

if __name__ == '__main__':
    rp = RssParser()
    # rp.to_s()
    print(rp.to_dict())

これで、辞書形式で返ってくる。_get_content()の中身はサイトによってかなり変わるだろうから、適宜調整。

このうち、画像があるものについてだけ、任意の記事数だけ取得するクラスを作ってみる。Rss.parser.to_dict()の戻り値を引数にとる感じで。ついでなので、出力はjsonにする。

import json

class Entry2Json:
    def __init__(self):
        pass

    # quantity: 出力する記事数
    def to_json(self, entries, quantity=6):
        contents = []
        for entry in entries:
            if not entry['img']:
                continue
            contents.append(entry)
            if len(contents) >= quantity:
                break
        print(json.dumps(contents, ensure_ascii=False, indent=4))

json.dumpsは日本語のためにensure_ascii=Falseにしている。

以上。

参考リンク

ありがとうございました。

関連記事

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です