PythonでPixivのブックマークした画像を一括取得したいともがくお話～改修編～

#はじめに
本投稿は[前投稿](https://qiita.com/haraday/items/add722167d0d6f2342f9)後コードを見て改善したいと思ったところが
いくつかあったので改善したいと考え、
コードの修繕をすることにしました。
なお、改悪している気はしないのですが、
改悪になっていることもありますので、ご了承ください。
#開発環境
OS：Windows10 64bit　1903
CPU/Memory:i5-7200U/8GB
python 3.6.8 64bit版
エディター（？）：VSCode version 1.38.1
#コードの復習
前回の完成品のコードを再度ここにかいておきます。

```py:pixiv_download_CLI.py
from pixivpy3 import *
from time import sleep
import json
import os

#folder check
if not os.path.exists("./pixiv_images"):
    os.mkdir("./pixiv_images")
if not os.path.exists("./pixiv_images/bookmark"):
    os.mkdir("./pixiv_images/bookmark")
#api login
aapi=AppPixivAPI()
aapi.login("Mail", "Pass")
#main
bookmark_count=input("your bookmark count number please.\n only public bookmark:")
bookmark_count=int(bookmark_count)//30+1
json_user_collect = aapi.user_bookmarks_illust("user-id", restrict='public')
while bookmark_count > 0:
    print("#"+str(bookmark_count))
    num=len(json_user_collect.illusts)
    bookmark_count=bookmark_count-1
    for illust in json_user_collect.illusts[:num]:
        writer=illust.user.name.replace("/","-")
        if not os.path.exists("./pixiv_images/bookmark/"+writer):
            os.mkdir("./pixiv_images/bookmark/"+writer)
        savepath="./pixiv_images/bookmark/"+writer
        aapi.download(illust.image_urls.large,path=savepath,name=str(illust.title.replace("/","-"))+".png")
        print("#"+str(writer)+":"+str(illust.title))
        sleep(1)
    if bookmark_count>0:
        next_url=json_user_collect.next_url
        next_qs=aapi.parse_qs(next_url)
        json_user_collect=aapi.user_bookmarks_illust(**next_qs)
print("終了しました。")
```

こんな風ですが今回修繕する箇所は

1. import周り
2. ログイン周り
3. json取得時のエラー処理
4. download処理のエラー処理 

この4つを考えていきます。

#第一ラウンド-importの修繕
まずはコードを見てみましょう

```py
from pixivpy3 import *
from time import sleep
import json
import os
```

前から気になっていた

```py
from pixivpy3 import *
```

このコードではワイルドカードを用いてpixivpy3から、
importしているわけなのですが、
このワイルドカードを使ったimportは
**正直よろしくない**
というのを聞いたことがあったので、
ここを直そうと思います。

あの頃はfrom ~ import * の意味を知らなかったし、
普通にimportだけではどうにもできなかったので使っていましたが、
コレ自体で、
pixivpyのすべてのAPIをimportしていることがわかりました。
それを知ったのは、Vscodeの機能の一つ、
**定義へ移動**
です。
多分他のソフトにもあると思いますが一応使い方を記しておきます。

**1.該当箇所にカーソルを合わせて右クリック**
![くぃった１.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498105/a668f9bc-ae55-9240-eb0c-9cc72b725d95.jpeg)

**2.”定義へ移動”を押す**

**3.見れる**
![qiita2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498105/2f255fe2-0621-678f-cd62-6bb353c206d8.jpeg)

ここで気づいたのは、

```py
__all__ = ("PixivAPI", "AppPixivAPI", "PixivError")
```

**これ全部をimportしてるのでは？**
ということに気づいたのでコードを

```py
from pixivpy3 import *
```

から

```py
from pixivpy3 import PixivAPI
from pixivpy3 import AppPixivAPI
from pixivpy3 import PixivError
```

へと変更してみました。

するとこれで実行できてしまいました。
成功です。


#第2ラウンド-ログイン周り
パスワードを平文でコード上に書くと事故りそうなので、
とりあえずは、手入力を毎回求める仕組みにします。

```py
aapi=AppPixivAPI()
aapi.login("Mail", "Pass")
```

これを
inputでも使って、

```py
mail=input("APIログインのために\npixivのmailアドレスを入力:")
password=input("pixivのパスワードを入力")
aapi=AppPixivAPI()
aapi.login(mail, password)
```

無難ですね。

#第3ラウンド～json部分のエラー処理
こちらも無難に行きましょう。
改変前

```py
json_user_collect = aapi.user_bookmarks_illust("user-id", restrict='public')
```

おっと、これよく見たら、useridも自分でコードを書き換えないと行けないみたいですね。
APIのデータを使って置き換えておきます。
さて、
エラー処理には、tryとexceptを使いますが、
使い方をあんまり理解していないので、簡単なものでなんとかします。
今回はとりあえずエラーかどうかさえ分かればいいので、

```py
myself_user_id=int(aapi.user_id)
try:
    json_user_collect = aapi.user_bookmarks_illust(myself_user_id, restrict=bookmark_type)
except:
    print("error")
    sleep(10)
    quit()
```

一行目でAPIから取得したユーザーのIDを変数に代入しておきます。
あとはtryでごまかしておきました。

#第4ラウンド～download処理のエラー処理 
一番の鬼門、というかダウンロードの際一番障害になりやすいとこですね。
何故そうなのかは、下に説明をざっくりかいておきます。
<details><summary>理由</summary><div>
作品名や作者名には、ファイル名としては利用できない文字が多々あるわけですが、
正直な話、機種依存文字を含めても多くの文字がファイル名として使えません。
現時点では、名前に/があれば置き換えてくれますが、
それ以外は手つかずで、
何度か、エラーを吐いて終了してしまうこともありました。
今回はそれらの作品は諦め、ダウンロードを継続できるように変更します。
</div></details>

改変前コード

```py
aapi.download(illust.image_urls.large,path=savepath,name=str(illust.title.replace("/","-"))+".png")
```

こちらもtryとexceptと更に、continueを使っていきます。
改変後

```py
            try:
                aapi.download(illust.image_urls.large,path=savepath,name=str(illust.title.replace("/","-"))+".png")
            except:
                print("error")
                print("#"+str(writer)+":"+str(illust.title))
                sleep(1)
                continue
```

tryとexceptを使って、それっぽくなりました。
本当ならCSVにでも出力したいとこですが、今回はやめておきます。

#終わりに
閲覧いただきありがとうございました。
今回は修繕というとこで、主に異常系を中心に見ていきました。
今後は、ランキングの取得や、エラーだった作品の情報のCSV出力、
更には機械学習などをやっていきたいと思います。
機械学習とかは初心者には厳しい予感しかしませんが、
頑張っていきますので、ご指南のほど宜しくおねがいします。
最後にコード全体を見ておしまいです。

#コード全体

```py
from pixivpy3 import PixivAPI
from pixivpy3 import AppPixivAPI
from pixivpy3 import PixivError
from time import sleep
import json
import os

#folder check
if not os.path.exists("./pixiv_images"):
    os.mkdir("./pixiv_images")
if not os.path.exists("./pixiv_images/bookmark"):
    os.mkdir("./pixiv_images/bookmark")
#api login
mail=input("APIログインのために\npixivのmailアドレスを入力:")
password=input("pixivのパスワードを入力")
aapi=AppPixivAPI()
aapi.login("Mail", "Pass")
#main
bookmark_count=input("your bookmark count number please.\n only public bookmark:")
bookmark_count=int(bookmark_count)//30+1
myself_user_id=int(aapi.user_id)
try:
    json_user_collect = aapi.user_bookmarks_illust(myself_user_id, restrict=bookmark_type)
except:
    print("error")
    sleep(10)
    quit()
while bookmark_count > 0:
    print("#"+str(bookmark_count))
    num=len(json_user_collect.illusts)
    bookmark_count=bookmark_count-1
    for illust in json_user_collect.illusts[:num]:
        writer=illust.user.name.replace("/","-")
        if not os.path.exists("./pixiv_images/bookmark/"+writer):
            os.mkdir("./pixiv_images/bookmark/"+writer)
        savepath="./pixiv_images/bookmark/"+writer
        try:
            aapi.download(illust.image_urls.large,path=savepath,name=str(illust.title.replace("/","-"))+".png")
        except:
            print("error")
            print("#"+str(writer)+":"+str(illust.title))
            sleep(1)
            continue
        print("#"+str(writer)+":"+str(illust.title))
        sleep(1)
    if bookmark_count>0:
        next_url=json_user_collect.next_url
        next_qs=aapi.parse_qs(next_url)
        json_user_collect=aapi.user_bookmarks_illust(**next_qs)
print("終了しました。")
```

おしまい。

#前回・次回
前回：(https://qiita.com/haraday/items/add722167d0d6f2342f9)