202号室の手記

数学やコンピュータの小ネタを中心に書きます.

不純な動機で画像収集プログラムを作った件

誰もが一度は通る道(に違いない)。
某まとめブログを対象に作ったが、同じ要領で他のサイトにも適用できます。
乱用による成果物(色んな意味で)は、自己責任で処理(意味深)してください。
コードの全文はこちら

1. XPathの取得

収集対象のサイトのURLを仮に、http://niceurlとします。
ブラウザはChromeを使いましたが、他のブラウザでも同様の機能はあると思います。
http://niceurlにアクセスし、対象の画像で右クリック、"Inspect"を選択すると、 Developper Toolが立ち上がり、Webコンテンツとソースコードの対応付けをしてくれます。
下図のように、対象の画像に対応するソースコードの箇所で右クリック>Copy>Copy XPathと選択すると、 クリップボードXPathが貼り付けられます。

f:id:paperlefthand:20170630015746p:plain

上の例では、'//*[@id="more"]/a[1]'となっていました。
これは、"任意の階層及びタグで、idが"more"である要素の直下にある、aタグ要素の一番目" を指す一意名です。
XPathについては、こちらを参照。

2. 収集対象域の特定

'//*[@id="more"]/a[1]'を元にa[2],a[3],…と辿っていくと、 素敵画像のパスを特定できるわけです。
というわけで、コードの前半は次のようになります。

import os
import lxml.html
import urllib.request
import requests

url = " http://niceUrl"
actress = "niceName"

try:
    os.mkdir(actress) # (1)
except:
    pass

html = urllib.request.urlopen(url).read()  
root = lxml.html.fromstring(html)             # (2)
imgs = root.xpath('//*[@id="more"]/a')   # (3)
img_urls = [x.get("href") for x in imgs if ".jpg" in x.get("href")] # (4)
  1. 指定した人物名でディレクトリを作っています。
    顔認識なんかやりたいときのためにこうしています。
  2. urlopenで開いたWebページをいったんread()でテキスト化し、 改めてlxmlモジュールで読み直しています。
    こうすることで、取得したWebページをXPathの文法でパースすることができます。
  3. XPath'//*[@id="more"]/a'で、
    “任意の階層及びタグで、idが"more"である要素の直下にある、aタグ要素全て"を指定します。
  4. 取得したaタグ要素は、
    <a href="http://niceurl/nicegirl.jpg" target="_blank">...</a>
    などとなっているため、ここから.get()メソッドで、href属性の値すなわち画像ファイルのURLを取得します。 また、URLが画像ファイルになっていないものをリスト内包表記の条件式で排除しています。
    結果として、img_urlsには、お目当の画像全てのURLが格納されていることになります。

3. いざ、

コードの後半部です。

for (c,iurl) in enumerate(img_urls):   
    r = requests.get(iurl)
    if r.status_code == 200:
        with open(actress + "/" + actress + "{}.jpg".format(c), 'wb') as file:
            file.write(r.content)

requestsオブジェクトのget()メソッドで、URLにアクセスし、成功(200)した場合処理を進めます。
画像ファイル名は、"ディレクトリ名と同じ名前+番号.jpg"としました。
この名前でファイルをopenし、requestsオブジェクトのcontentを書き込みます。

4. さあ、お楽しみの時間だ

以上により、カレントディレクトリに作成された"niceName"ディレクトリ以下に、
番号でラベリングされた素敵画像が集まっています。
うまくいかない場合は、XPathが上記の例と異なっている可能性があるので、
もう一度確認してみてください。
楽しい画像収集ライフを!