feedparserで、media コンテンツを取る
Nov 24, 2008
feedparserで、どうやってビデオを取れるかをずっと悩みましたけど、今日少しだけ、進展した。問題の核心はyoutubeや、vimeoは Yahoo! RSS モジュールを使って、RSS拡張ネームスペースにデータを入れている。この拡張データの処理はfeedparserが中途半端でやってる。見てみよう。
YoutubeのGDATA APIで取ったデータはこうなる
... | |
<entry> | |
<id>http://gdata.youtube.com/feeds/api/videos/R3orQKBxiEg</id> | |
<published>2008-07-17T23:58:51.000Z</published> | |
<updated>2008-11-24T02:32:25.000Z</updated> | |
... | |
<title type="text">Official Watchmen Trailer</title> | |
<content type="text">Title speaks for itself | |
so people don't have to keep answerin | |
the name of the song is: | |
smashing pumpkins- the beginning is the end is the beginning</content> | |
... | |
<author> | |
<name>Garrettheparrot</name> | |
<uri>http://gdata.youtube.com/feeds/api/users/garrettheparrot</uri> | |
</author> | |
<media:group> | |
<media:title type="plain">Official Watchmen Trailer</media:title> | |
<media:description type="plain">Title speaks for itself | |
so people don't have to keep answerin | |
the name of the song is: | |
smashing pumpkins- the beginning is the end is the beginning</media:description> | |
<media:keywords>2009, Comic, Men, Movie, Watch, Watches, Who</media:keywords> | |
<yt:duration seconds="140"/> | |
<media:category label="Film & Animation" scheme="http://gdata.youtube.com/schemas/2007/categories.cat">Film</media:category> | |
<media:content url="http://www.youtube.com/v/R3orQKBxiEg&f=gdata_user_favorites" type="application/x-shockwave-flash" medium="video" isDefault="true" expression="full" duration="140" yt:format="5"/> | |
<media:content url="rtsp://rtsp2.youtube.com/CjALENy73wIaJwlIiHGgQCt6RxMYDSANFEgGUhRnZGF0YV91c2VyX2Zhdm9yaXRlcww=/0/0/0/video.3gp" type="video/3gpp" medium="video" expression="full" duration="140" yt:format="1"/> | |
<media:content url="rtsp://rtsp2.youtube.com/CjALENy73wIaJwlIiHGgQCt6RxMYESARFEgGUhRnZGF0YV91c2VyX2Zhdm9yaXRlcww=/0/0/0/video.3gp" type="video/3gpp" medium="video" expression="full" duration="140" yt:format="6"/> | |
<media:thumbnail url="http://i.ytimg.com/vi/R3orQKBxiEg/2.jpg" height="97" width="130" time="00:01:10"/> | |
<media:thumbnail url="http://i.ytimg.com/vi/R3orQKBxiEg/1.jpg" height="97" width="130" time="00:00:35"/> | |
<media:thumbnail url="http://i.ytimg.com/vi/R3orQKBxiEg/3.jpg" height="97" width="130" time="00:01:45"/> | |
<media:thumbnail url="http://i.ytimg.com/vi/R3orQKBxiEg/0.jpg" height="240" width="320" time="00:01:10"/> | |
<media:player url="http://www.youtube.com/watch?v=R3orQKBxiEg"/> | |
</media:group> | |
... | |
</entry> | |
... |
media という名前空間の下に結構データが入ってる。なのに、feedparserはちょっとしか取らない。
>>> d = feedparser.parse("http://gdata.youtube.com/feeds/api/users/IanLewisInJapan/favorites") | |
>>> e = d['entries'][0] | |
>>> filter(lambda x: x.startswith('media_'), e.keys()) | |
['media_category', 'media_player', 'media_group', 'media_keywords', 'media_description', 'media_content', 'media_thumbnail'] | |
>>> e['media_content'] | |
u'' | |
>>> e['media_thumbnail'] | |
u'' | |
>>> e['media_player'] | |
u'' | |
>>> e['media_description'] | |
u'Last.fm/presents Yellow Magic Orchestra Interview at Royal Festival Hall in London.\nCheck out http://www.last.fm/Presents to find out about all of our other interviews or upcoming/past events.' | |
>>> |
ビデオのURLはどこかにない。原因はfeedparserの拡張ネームスペース処理に入ってるけども、一言いうと、<media:content>というタグの属性は取れてない。こう見たら、どうやって、とれるかを調べたら、unknown_starttag()というメソッドの中にこのコードを見つけた。
feedparser.py
... | |
# call special handler (if defined) or default handler | |
methodname = '_start_' + prefix + suffix | |
try: | |
method = getattr(self, methodname) | |
return method(attrsD) | |
except AttributeError: | |
return self.push(prefix + suffix, 1) | |
... |
じゃ、XMLを解析するときに、タグを見つけたら、unknown_starttag()という関数が実行されて、タグの名前に一致するメソッドがあれば、実行する処理やってる。それで、start_media_content()というメソッドがあれば実行してくれるわけだね。でも、どうやって、パーサークラスに付けるのか。feedparserは_StrictFeedParserというクラスを名前で使ってるから、自分が作ったクラスを_ScrictFeedParserと交換。
feedparser._StrictFeedParser_old = feedparser._StrictFeedParser | |
class DlifeFeedParser(feedparser._StrictFeedParser_old): | |
| |
def _start_media_content(self, attrsD): | |
self.entries[-1]['media_content_attrs'] = copy.deepcopy(attrsD) | |
feedparser._StrictFeedParser = DlifeFeedParser |
それで、またparse()を実行すると、
>>> import feedparser | |
>>> import copy | |
>>> feedparser._StrictFeedParser_old = feedparser._StrictFeedParser | |
>>> class DlifeFeedParser(feedparser._StrictFeedParser_old): | |
... | |
... def _start_media_content(self, attrsD): | |
... self.entries[-1]['media_content_attrs'] = copy.deepcopy(attrsD) | |
... return self.push('media_content', 1) | |
... | |
>>> feedparser._StrictFeedParser = DlifeFeedParser | |
>>> d = feedparser.parse("http://gdata.youtube.com/feeds/api/users/IanLewisInJapan/favorites") | |
>>> filter(lambda x: x.startswith("media_"), d['entries'][0].keys()) | |
['media_category', 'media_player', 'media_group', 'media_content_attrs', 'media_keywords', 'media_description', 'media_content', 'media_thumbnail'] | |
>>> d['entries'][0]['media_content_attrs'] | |
['medium', 'format', 'url', 'expression', 'duration', 'type', 'yt:format'] |
それで、media:contentの属性を取れた。 media:groupの下にcontentが複数ある場合もあるから、もうちょっとまとめないといけないけど、やり方が少し分かってきた。
blog comments powered by Disqus