FC2アダルトのAPI解析してみるよ!

みんな大好きFC2アダルト!しかし、有料会員にならないと動画のソートを出来ない。
どうにかして動画のソートを出来ないか考えてみる。

以前にスクレイピングで動画情報を取得するコードを書いたが、久々に動かしたら使えなくなっていた。

もっとエレガントな方法、APIを用いて動画情報を取得したい。
APIAndroidクライアントで使われているはずなのでそれを調べた。

下のコードを読めば大体わかると思います。

# -*- coding: utf-8 -*-
import urllib
import urllib2
import xml.etree.ElementTree as ET
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from datetime import *
import base64
import json
from operator import attrgetter

class Fc2():
    hash = ""
    fc2id = ""
    password = ""
    vlist = []
    keyword = ""
    
    api_url = "http://video.fc2.com/android_api.php"
    
    def __init__(self):
        usr = json.loads(open("usr.json").read())
        self.fc2id = str(usr["email"])
        self.password = str(usr["password"])
        
    def refresh_hash(self):
        values = {
                  "method":"get_public_key"
                  }
        data = urllib.urlencode(values)
        response = urllib2.urlopen(self.api_url, data)
        xml = response.read()
        elem = ET.fromstring(xml)
        pem = elem.find("public_key").text
        key = RSA.importKey(pem)
        cipher = PKCS1_v1_5.new(key)
        
        s = "..".join((self.fc2id, self.password, datetime.today().strftime("%Y%m%d%H")))
        data = base64.b64encode(cipher.encrypt(s))
        
        values = {
                  "method":"login",
                  "data":data,
                  }
        data = urllib.urlencode(values)
        response = urllib2.urlopen(self.api_url, data)
        xml = response.read()
        elem = ET.fromstring(xml)
        self.hash = elem.find("hash").text
        
    def total_of_search_keyword(self, keyword):
        self.refresh_hash()
        values = {
                  "method":"content_search",
                  "keyword":keyword,
                  "hash":self.hash,
                  "adult":1,
                  "page":1,
                  }
        data = urllib.urlencode(values)
        response = urllib2.urlopen(self.api_url, data)
        elem = ET.fromstring(response.read())
        return int(elem.find("total").text)
        
    def page_of_search_keyword(self, page):
        values = {
                  "method":"content_search",
                  "keyword":self.keyword,
                  "hash":self.hash,
                  "adult":1,
                  "page":page,
                  }
        data = urllib.urlencode(values)
        response = urllib2.urlopen(self.api_url, data)
        content = response.read()
        elem = ET.fromstring(content)
        
        for vnode in elem.iter("video"):
            vdict = {}
            for child in vnode.findall(".*"):
                vdict[child.tag] = vnode.find(child.tag).text
            self.vlist.append(vdict)
    
    def search_keyword(self, keyword):
        self.vlist = []
        self.keyword = keyword
        total = self.total_of_search_keyword(keyword)
        print "Total:", total
        pagenum = (total+7)/8
        for i in xrange(1, pagenum+1):
            self.page_of_search_keyword(i)
            
    def sort(self, sortby="view_count", accending=False):
        self.vlist.sort(key=lambda video:int(video[sortby]), reverse=not accending)
            


残念なことにキーワード情報から動画情報を取得するAPIでは1回叩くたびに8つしか取れない。
結局速度の点ではスクレイピングと大して変わらない(スクレイピングでは1ページに50の動画情報が取れる)
Hashさえ取れれば後の通信は暗号化されていなかった。

DOSにならないように高速に動画情報を取得、ソートetcをしたいならデータベースでも作るしか無い。
しかしサーバーがなかった(おわり)