いかにして効率よく大量のおっぱい画像をダウンロードするか というエントリを読んだら、私の中に潜むおっぱいマニア(Python 使いのこと)の血が騒いで、勢いで書いてしまった。後悔はしていない。
で、これを作って動かしてみて気づいたんだけど、Yahoo! の画像検索の API では、最大で 1000 枚までしか検索できない。なのに元記事では 7000 枚以上もダウンロードできてる…時間を置いて検索しなおすと検索結果が変わって、新しい画像がゲットできるとか?おっぱいマニアへの道は遠くて険しい
それから、 SimpleXML というクラスは演算子のオーバロードを学ぶために私が大昔に作ったもので、いわば習作。当時は
今もだけど XML についてよく理解していなかった。だからこれは参考にしないで、
Python2.4.2でPHP5のSimpleXMLを真似 で公開されているものとか、あるいは
Beautiful Soap (というもの。まだ私は試してないけど)を使った方がいいかも。それ以外でも XML をパースして、ハッシュと属性参照でアクセスできるようなツリーを作るライブラリの何かいいやつがあったら教えてください。やっぱり私はまだ、おっぱいマニアにはほど遠い。
ちなみにダウンロードした 1000 枚のおっぱい画像のファイルサイズは、合計で 108 Mほどでした。
#! /usr/bin/python
# -*- coding:utf8 -*-
from urllib import quote, urlopen
import time
import xml.dom.minidom as minidom
class SimpleXML(object):
def __init__(self, minidom_obj):
self.dom = minidom_obj
def __getitem__(self, key):
if self.dom.attributes.has_key(key):
return self.dom.getAttribute(key)
raise KeyError
def __getattr__(self, attrname):
if attrname in dir(self.dom):
tmp = eval("self.dom."+attrname)
if isinstance(tmp, xml.dom.minidom.NodeList):
return map( lambda x: SimpleXML(x), tmp)
elif isinstance(tmp, xml.dom.minidom.Node):
return SimpleXML(tmp)
else:
return tmp
return self.buff[attrname]
return map( lambda x: SimpleXML(x),
filter(lambda x: x.tagName == attrname,
filter( lambda x: not (isinstance(x, xml.dom.minidom.Comment) or
isinstance(x, xml.dom.minidom.Text)),
self.dom.childNodes)))
def __unicode__(self):
if len(self.dom.childNodes) == 1 and isinstance(self.dom.childNodes[0], xml.dom.minidom.Text):
return self.dom.childNodes[0].data
imageNum = 0
totalResultsAvailable = 2
data = {}
data["appid"] = "****"
data["query"] = "おっぱい"
data["type"] = "all"
data["results"] = 50
data["format"] = "any"
data["adult_ok"] = 1 # ここ重要!!!
data["start"] = 1
while data["start"] < totalResultsAvailable:
res = urlopen( "http://api.search.yahoo.co.jp/ImageSearchService/V1/imageSearch?"
+ "&".join(["=".join([key, quote(str(value))]) for key, value in data.items()]))
res = res.read()
print res
document = minidom.parseString(res)
sdoc = SimpleXML(document)
totalResultsAvailable = int(unicode(sdoc.ResultSet[0]["totalResultsAvailable"]))
time.sleep(1)
for result in sdoc.ResultSet[0].Result:
img = urlopen(unicode(result.Url[0]))
if img.info().gettype()[:5] != "image":
img.close()
img = urlopen(unicode(result.Thumbnail[0].Url[0]))
if img.info().gettype()[:5] == "image":
print unicode(imageNum)+"."+unicode(result.FileFormat[0])
localfile = file(unicode(imageNum)+"."+unicode(result.FileFormat[0]),"wb")
localfile.write(img.read())
img.close()
localfile.close()
imageNum += 1
data["start"] += data["results"]
リンクしていただきましたtomoemonです.
>XML をパースして、ハッシュと属性参照でアクセスできるような
lxmlやElementTreeといったものがよく使われているようです.ElementTreeはピュアPython,lxmlはCによる実装ですので速度的にはlxmlの方が有利でしょうか.
SimpleXMLのようなアクセス方法についてはlxmlのobjectifyを用いることで,ほぼ実現することができます.属性をハッシュで参照できないのは少々残念ですが,XPathも利用することができるのでXML操作をだいぶ楽にしてくれるライブラリだと思います.もしよければお試しください.
http://pypi.python.org/pypi/lxml/1.3.4
http://codespeak.net/lxml/index.html
>>
from lxml import objectify
data = yahooのリクエスト結果
root = objectify.fromstring(data)
# 属性の参照はget関数
print root.get("totalResultsReturned")
#子ノードはアトリビュートで参照
for e in root.Result:
print e.Url, e.Title
<<
P.S.
私も試してみましたが,YahooのAPIで1000枚以上取得しているのは確かに不思議ですね(笑)