RSS1.0を検索する際の名前空間の指定

ここ最近Pythonのlxmlモジュールを試していて、RSS1.0形式のデータをXPathで検索する場合は名前空間を指定しなければならないことを知った。


例えば、RSSから各記事のタイトル部分を取得したいとして
RSS2.0の場合、「 /rss/channel/item/title 」でOKなのだが、
RSS1.0の場合、「 /rdf:RDF/item/title 」というようにルートノードから順に並べただけでは取得できない。



RSS1.0、RSS2.0、それぞれをダウンロードする。

$ wget -q http://www.pheedo.jp/f/gigazine_1 && mv gigazine_1 gigazine_rss1.xml
$ wget -q http://www.pheedo.jp/f/gigazine_2 && mv gigazine_2 gigazine_rss2.xml
$ ls -tl | grep gigazine
-rw-rw-r-- 1 hogeuser hogeuser   38043  928 20:58 gigazine_rss1.xml
-rw-rw-r-- 1 hogeuser hogeuser   49547  928 20:58 gigazine_rss2.xml


以下、検証用スクリプト

#!/usr/bin/env python
# -*- coding:utf8 -*-
from lxml import etree

def find_by_xpath(src, xpath, ns={}):
    print 'SOURCE = %s' % src
    print 'XPATH = %s' % xpath
    print 'NAMESPACE = %s' % ns
    finded = []
    try:
        finded = etree.parse(src).xpath(xpath, namespaces=ns)
        print '> finded = %sitems\n' % len(finded)
    except etree.Error, err:
        print '> error = %s "%s"\n' % (err.__class__, err)
    #return finded

# rss2.0
#   XPath式をルートノードから順に書く => OK: 取得できる
find_by_xpath('gigazine_rss2.xml', '/rss/channel/item/title')

# rss1.0
#   XPath式をルートノードから順に書く => NG: エラーが発生する
find_by_xpath('gigazine_rss1.xml', '/rdf:RDF/item/title')

# rss1.0
#   XPath式の指定に加えて、rss1.0データのルートノード部分の
#   名前空間定義に従って、名前空間rdfを指定する => NG: 取得できない(0件)
find_by_xpath('gigazine_rss1.xml', '/rdf:RDF/item/title', {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'})

# rss1.0
#   XPath式の指定、名前空間rdfの指定に加えて、別名のない名前空間に
#   自分で適当な別名(以下の例では"hoge")を指定する => OK: 取得できる
find_by_xpath('gigazine_rss1.xml', '/rdf:RDF/hoge:item/hoge:title', {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'hoge': 'http://purl.org/rss/1.0/'})


以下、実行結果

$ python test_lxml_xpath2.py
SOURCE = gigazine_rss2.xml
XPATH = /rss/channel/item/title
NAMESPACE = {}
> finded = 36items

SOURCE = gigazine_rss1.xml
XPATH = /rdf:RDF/item/title
NAMESPACE = {}
> error = lxml.etree.XPathEvalError "Undefined namespace prefix"

SOURCE = gigazine_rss1.xml
XPATH = /rdf:RDF/item/title
NAMESPACE = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
> finded = 0items

SOURCE = gigazine_rss1.xml
XPATH = /rdf:RDF/hoge:item/hoge:title
NAMESPACE = {'hoge': 'http://purl.org/rss/1.0/', 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
> finded = 37items

以下の記事がすごく参考になった。
オフィスで見る夜明け:C#でRSS - livedoor Blog(ブログ)