BookoffオンラインのAPIをつくってみた。 #3 (改良)

#はじめに
 [前回はこちら](https://qiita.com/tetsuya111/items/f62d4c9b9da0a4c35b55)

 本当はデータベースを作りたかったが、一度に最大5000件しか取れないという壁にぶつかり、どうも深刻な感じなのでとりあえず諦めた。
 前回と前々回で、いくつか関数を作ったが、もう少し改良。

#データの取得

[一回目](https://qiita.com/tetsuya111/items/7064648ca7d4dc218817)の searchN を改良。

```python:util.py
from . import api
import re
import time

def search(query,title="",author="",priceFrom=0,priceUntil=10**32,onlyStocked=True,n=5,type_=api.SearchType.BOOK,timeout=30):
        i=0
        startTime=time.time()
        for data in api.searchN(query,n=10**32,type_=type_):
                if i >= n:
                        break
                if time.time() - startTime > timeout:
                        break
                if (not title or re.search(title,data["title"])) and \
                        (not author or re.search(author,data["author"])) and \
                        priceFrom <= data["price"] < priceUntil and \
                        (not onlyStocked or data["stocked"]):
                        yield data
                        i+=1

```


引数 |意味 
--- |--- 
query |検索する文字
title |タイトル (部分一致)
author |著者名 (部分一致)
priceFrom |{priceFrom} 円以上
priceUntil |{priceUntil} 円未満
onlyStocked |在庫の在るもののみを返す
n |データの個数 (最大)
type |データのタイプ
timeout |タイムアウト


query と title があるのは野暮なようだが、例えば著者名で検索したいとき、 `query = title` なら無理やし、 `query=title+" "+author` ではauthorに正規表現を使いたいときにヒットしない。まあ改良してもこんなもの。(笑)
一応タイムアウトを付けた。

##試す

```python:main.py
from bookoff import api
import getpass
import requests
from bookoff import util
import sys
import json

author=sys.argv[1]
for data in util.search(author,author=author,priceUntil=220):
        print(json.dumps(data,indent=4,ensure_ascii=False))
```

```shell:実行結果
$ python main.py 安部公房
{
    "title": "砂の女(新潮文庫)",
    "url": "https://www.bookoffonline.co.jp/old/0015580570",
    "author": "安部公房",
    "price": 200,
    "stocked": true
}
{
    "title": "壁(新潮文庫)",
    "url": "https://www.bookoffonline.co.jp/old/0015580566",
    "author": "安部公房",
    "price": 200,
    "stocked": true
}
{
    "title": "笑う月(新潮文庫)",
    "url": "https://www.bookoffonline.co.jp/old/0015580572",
    "author": "安部公房",
    "price": 200,
    "stocked": true
}
{
    "title": "箱男(新潮文庫)",
    "url": "https://www.bookoffonline.co.jp/old/0015580571",
    "author": "安部公房",
    "price": 200,
    "stocked": true
}
{
    "title": "こころの声を聴く 河合隼雄対話集(新潮文庫)",
    "url": "https://www.bookoffonline.co.jp/old/0012419276",
    "author": "河合隼雄,安部公房,山田太一,谷川俊太郎,白洲正子",
    "price": 200,
    "stocked": true
}
```

なかなか有能である。[前回のもの](https://qiita.com/tetsuya111/items/f62d4c9b9da0a4c35b55)と組み合わせて、好きな著者の安い本を選んでカートに入れてみる。

###好きな著者の安い本をカートに入れる

```python:main.py
import docopt
import getpass

PRICE_UNTIL=220

__doc__="""
Usage:
        addcheaps <author> [(-n <number>)]  [(-m <mail>)]
"""

def main(argv=sys.argv[1:]):
        args=docopt.docopt(__doc__)

        author=args["<author>"]
        number=int(args["<number>"]) if args["-n"] else 5
        mail=args["<mail>"] or input("mail : ")
        pw=getpass.getpass()

        author=sys.argv[1]
        client=api.Client(mail,pw)
        if not client.logined:
                print("Failed to login")
                return
        for data in util.search(author,author=author,priceUntil=PRICE_UNTIL):
                print(data["title"],data["price"])
                client.addCart(util.getidInUrl(data["url"]))

if __name__ == "__main__":
        main()
```


```shell:実行結果
$ python main.py 梅棹忠夫 -m tetsuya1729@icloud.com                        
Password:              
知的生産の技術(岩波新書) 200                                         
日本文明７７の鍵(文春新書) 200                            
二十一世紀の人類像 民族問題をかんがえる(講談社学術文庫) 200  
```


タイトルから ID を取るのは遅いので、util.Client ではなく api.Client を使った。(改悪か?)
ここまでくれば、中々実用的である。

#終わりに
 本を買うために、プログラミングをするなんて知的すぎんか 。。。只の陰キャラの末路と言う気もせんではないが。やはりスポーツをやらねば。(笑)

###[コード](https://github.com/tetsuya111/util/tree/main/bookoff)